diff --git a/jetstream.ts b/jetstream.ts index 4b39b4d..feba7b8 100644 --- a/jetstream.ts +++ b/jetstream.ts @@ -24,10 +24,13 @@ const fireWebhooks = async ( const webhooks = getWebhooksByDid(did); if (webhooks.length === 0) return; const results = await Promise.allSettled( - webhooks.map(({ method, url }) => + webhooks.map(({ method, url, token }) => fetch(url, { method, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + ...(token ? { Authorization: `Bearer ${token}` } : {}), + }, body: JSON.stringify(payload), }) ), diff --git a/server.ts b/server.ts index 6afeb4f..5603d6f 100644 --- a/server.ts +++ b/server.ts @@ -43,13 +43,13 @@ router.post("/notes/feed", async (ctx) => { router.post("/:did/webhooks", async (ctx) => { const { did } = ctx.params; const body = await ctx.request.body.json(); - const { method, url } = body ?? {}; + const { method, url, token } = body ?? {}; if (!method || !url) { ctx.response.status = 400; ctx.response.body = { error: "method and url are required" }; return; } - const subscription = addWebhookSubscription({ did, method, url }); + const subscription = addWebhookSubscription({ did, method, url, token }); ctx.response.status = 201; ctx.response.body = subscription; }); diff --git a/src/data/db.ts b/src/data/db.ts index f60c804..fab974d 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -89,20 +89,23 @@ type WebhookSubscriptionRow = { did: string; method: string; url: string; + token?: string; }; export const addWebhookSubscription = ( - { did, method, url }: Omit, + { did, method, url, token }: Omit, ): WebhookSubscriptionRow => { db.exec( - "INSERT INTO webhook_subscription (did, method, url) VALUES (?, ?, ?)", + "INSERT INTO webhook_subscription (did, method, url, token) VALUES (?, ?, ?, ?)", did, method, url, + token ?? null, ); return db.prepare( "SELECT id, did, method, url FROM webhook_subscription WHERE id = last_insert_rowid()", ).get()!; + // Note: token is intentionally excluded from the SELECT (write-only) }; export const deleteWebhooksByDid = (did: string): void => { @@ -111,7 +114,7 @@ export const deleteWebhooksByDid = (did: string): void => { export const getWebhooksByDid = (did: string): WebhookSubscriptionRow[] => { return db.prepare( - "SELECT id, did, method, url FROM webhook_subscription WHERE did = ? ORDER BY id DESC LIMIT 10", + "SELECT id, did, method, url, token FROM webhook_subscription WHERE did = ? ORDER BY id DESC LIMIT 10", ).all(did); }; diff --git a/src/migrations/init.ts b/src/migrations/init.ts index 0f271ce..2b0cf9c 100644 --- a/src/migrations/init.ts +++ b/src/migrations/init.ts @@ -55,4 +55,10 @@ db.exec(` ON webhook_subscription(did); `); +try { + db.exec(`ALTER TABLE webhook_subscription ADD COLUMN token TEXT;`); +} catch { + // Column already exists — no-op +} + db.close();