mirror of
https://github.com/svemagie/indiekit-endpoint-blogroll.git
synced 2026-04-02 15:34:59 +02:00
feat: integrate bookmark→blogroll hook via contentNegotiationRoutes
Uses res.on('finish') middleware mounted at '/' to detect successful
micropub bookmark creations and auto-import the bookmarked site's feed
into the blogroll. Self-contained within the plugin — no external patch
scripts required.
This commit is contained in:
46
index.js
46
index.js
@@ -7,12 +7,48 @@ import { blogsController } from "./lib/controllers/blogs.js";
|
|||||||
import { sourcesController } from "./lib/controllers/sources.js";
|
import { sourcesController } from "./lib/controllers/sources.js";
|
||||||
import { apiController } from "./lib/controllers/api.js";
|
import { apiController } from "./lib/controllers/api.js";
|
||||||
import { startSync, stopSync } from "./lib/sync/scheduler.js";
|
import { startSync, stopSync } from "./lib/sync/scheduler.js";
|
||||||
|
import { importBookmarkUrl } from "./lib/bookmark-import.js";
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
const protectedRouter = express.Router();
|
const protectedRouter = express.Router();
|
||||||
const publicRouter = express.Router();
|
const publicRouter = express.Router();
|
||||||
|
|
||||||
|
// Global hook router: intercepts POST requests site-wide to detect micropub
|
||||||
|
// bookmark creations and auto-import the bookmarked site into the blogroll.
|
||||||
|
// Mounted at "/" via contentNegotiationRoutes (runs before auth middleware).
|
||||||
|
const bookmarkHookRouter = express.Router();
|
||||||
|
bookmarkHookRouter.use((request, response, next) => {
|
||||||
|
response.on("finish", () => {
|
||||||
|
// Only act on successful POST creates (201 Created / 202 Accepted)
|
||||||
|
if (
|
||||||
|
request.method !== "POST" ||
|
||||||
|
(response.statusCode !== 201 && response.statusCode !== 202)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore non-create actions (update, delete, undelete)
|
||||||
|
const action =
|
||||||
|
request.query?.action || request.body?.action || "create";
|
||||||
|
if (action !== "create") return;
|
||||||
|
|
||||||
|
// bookmark-of may be a top-level field (form-encoded / JF2 JSON)
|
||||||
|
// or nested inside properties (MF2 JSON format)
|
||||||
|
const bookmarkOf =
|
||||||
|
request.body?.["bookmark-of"] ||
|
||||||
|
request.body?.properties?.["bookmark-of"]?.[0];
|
||||||
|
if (!bookmarkOf) return;
|
||||||
|
|
||||||
|
const { application } = request.app.locals;
|
||||||
|
importBookmarkUrl(application, bookmarkOf).catch((err) =>
|
||||||
|
console.warn("[Blogroll] bookmark-import failed:", err.message)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
mountPath: "/blogrollapi",
|
mountPath: "/blogrollapi",
|
||||||
syncInterval: 3600000, // 1 hour
|
syncInterval: 3600000, // 1 hour
|
||||||
@@ -54,6 +90,14 @@ export default class BlogrollEndpoint {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global middleware (mounted at "/") — intercepts micropub bookmark creations.
|
||||||
|
* Uses res.on("finish") so it never interferes with the request lifecycle.
|
||||||
|
*/
|
||||||
|
get contentNegotiationRoutes() {
|
||||||
|
return bookmarkHookRouter;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Protected routes (require authentication)
|
* Protected routes (require authentication)
|
||||||
* Admin dashboard and management
|
* Admin dashboard and management
|
||||||
@@ -149,4 +193,4 @@ export default class BlogrollEndpoint {
|
|||||||
destroy() {
|
destroy() {
|
||||||
stopSync();
|
stopSync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user