@xtandard/webhooks 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +315 -0
- package/bin/xtandard-webhooks.mjs +3 -0
- package/dist/basic-BIW3Rvuz.cjs +199 -0
- package/dist/basic-BIW3Rvuz.cjs.map +1 -0
- package/dist/basic-DKk0Xfuu.mjs +176 -0
- package/dist/basic-DKk0Xfuu.mjs.map +1 -0
- package/dist/chunk-D7D4PA-g.mjs +13 -0
- package/dist/cli.cjs +655 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +42 -0
- package/dist/cli.d.mts +42 -0
- package/dist/cli.mjs +653 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/contract-8h-Azxa5.d.cts +71 -0
- package/dist/contract-9XpcwcCn.mjs +22 -0
- package/dist/contract-9XpcwcCn.mjs.map +1 -0
- package/dist/contract-B2d5dNU3.cjs +33 -0
- package/dist/contract-B2d5dNU3.cjs.map +1 -0
- package/dist/contract-BEhDcd_5.mjs +28 -0
- package/dist/contract-BEhDcd_5.mjs.map +1 -0
- package/dist/contract-Bf1qguwt.cjs +57 -0
- package/dist/contract-Bf1qguwt.cjs.map +1 -0
- package/dist/contract-Bnb3fgRJ.d.cts +177 -0
- package/dist/contract-C2r2Xzwp.d.mts +46 -0
- package/dist/contract-CiPskNvS.d.cts +46 -0
- package/dist/contract-DhQ4JjGG.d.mts +71 -0
- package/dist/contract-T1kcZNdG.d.mts +177 -0
- package/dist/contract-lETlIuXo.d.cts +30 -0
- package/dist/contract-lETlIuXo.d.mts +30 -0
- package/dist/core-CMpnmI5Q.mjs +1605 -0
- package/dist/core-CMpnmI5Q.mjs.map +1 -0
- package/dist/core-DT4ppWh8.d.mts +502 -0
- package/dist/core-KJawHjFF.d.cts +502 -0
- package/dist/core-ZGhH6Vs2.cjs +1790 -0
- package/dist/core-ZGhH6Vs2.cjs.map +1 -0
- package/dist/core.cjs +8 -0
- package/dist/core.d.cts +2 -0
- package/dist/core.d.mts +2 -0
- package/dist/core.mjs +2 -0
- package/dist/create-fetch-handler-BIdk9P30.mjs +1724 -0
- package/dist/create-fetch-handler-BIdk9P30.mjs.map +1 -0
- package/dist/create-fetch-handler-CmooujQo.cjs +1771 -0
- package/dist/create-fetch-handler-CmooujQo.cjs.map +1 -0
- package/dist/create-fetch-handler-Dlkhustu.d.cts +162 -0
- package/dist/create-fetch-handler-jy3hy5nZ.d.mts +162 -0
- package/dist/dispatcher-B0xTEHt1.cjs +212 -0
- package/dist/dispatcher-B0xTEHt1.cjs.map +1 -0
- package/dist/dispatcher-Coubwrka.mjs +196 -0
- package/dist/dispatcher-Coubwrka.mjs.map +1 -0
- package/dist/entry-auth-basic.cjs +5 -0
- package/dist/entry-auth-basic.d.cts +83 -0
- package/dist/entry-auth-basic.d.mts +83 -0
- package/dist/entry-auth-basic.mjs +2 -0
- package/dist/entry-auth-delegated.cjs +28 -0
- package/dist/entry-auth-delegated.cjs.map +1 -0
- package/dist/entry-auth-delegated.d.cts +36 -0
- package/dist/entry-auth-delegated.d.mts +36 -0
- package/dist/entry-auth-delegated.mjs +27 -0
- package/dist/entry-auth-delegated.mjs.map +1 -0
- package/dist/entry-auth-none.cjs +4 -0
- package/dist/entry-auth-none.d.cts +25 -0
- package/dist/entry-auth-none.d.mts +25 -0
- package/dist/entry-auth-none.mjs +2 -0
- package/dist/entry-authorization-delegated.cjs +27 -0
- package/dist/entry-authorization-delegated.cjs.map +1 -0
- package/dist/entry-authorization-delegated.d.cts +31 -0
- package/dist/entry-authorization-delegated.d.mts +31 -0
- package/dist/entry-authorization-delegated.mjs +26 -0
- package/dist/entry-authorization-delegated.mjs.map +1 -0
- package/dist/entry-authorization-none.cjs +3 -0
- package/dist/entry-authorization-none.d.cts +18 -0
- package/dist/entry-authorization-none.d.mts +18 -0
- package/dist/entry-authorization-none.mjs +2 -0
- package/dist/entry-authorization-roles.cjs +6 -0
- package/dist/entry-authorization-roles.d.cts +65 -0
- package/dist/entry-authorization-roles.d.mts +65 -0
- package/dist/entry-authorization-roles.mjs +2 -0
- package/dist/entry-bun.cjs +24 -0
- package/dist/entry-bun.cjs.map +1 -0
- package/dist/entry-bun.d.cts +8 -0
- package/dist/entry-bun.d.mts +8 -0
- package/dist/entry-bun.mjs +23 -0
- package/dist/entry-bun.mjs.map +1 -0
- package/dist/entry-drizzle-mysql.cjs +20 -0
- package/dist/entry-drizzle-mysql.cjs.map +1 -0
- package/dist/entry-drizzle-mysql.d.cts +27 -0
- package/dist/entry-drizzle-mysql.d.mts +27 -0
- package/dist/entry-drizzle-mysql.mjs +19 -0
- package/dist/entry-drizzle-mysql.mjs.map +1 -0
- package/dist/entry-drizzle-pg.cjs +21 -0
- package/dist/entry-drizzle-pg.cjs.map +1 -0
- package/dist/entry-drizzle-pg.d.cts +26 -0
- package/dist/entry-drizzle-pg.d.mts +26 -0
- package/dist/entry-drizzle-pg.mjs +20 -0
- package/dist/entry-drizzle-pg.mjs.map +1 -0
- package/dist/entry-drizzle-sqlite.cjs +21 -0
- package/dist/entry-drizzle-sqlite.cjs.map +1 -0
- package/dist/entry-drizzle-sqlite.d.cts +23 -0
- package/dist/entry-drizzle-sqlite.d.mts +23 -0
- package/dist/entry-drizzle-sqlite.mjs +20 -0
- package/dist/entry-drizzle-sqlite.mjs.map +1 -0
- package/dist/entry-elysia.cjs +125 -0
- package/dist/entry-elysia.cjs.map +1 -0
- package/dist/entry-elysia.d.cts +1017 -0
- package/dist/entry-elysia.d.mts +1017 -0
- package/dist/entry-elysia.mjs +123 -0
- package/dist/entry-elysia.mjs.map +1 -0
- package/dist/entry-express.cjs +57 -0
- package/dist/entry-express.cjs.map +1 -0
- package/dist/entry-express.d.cts +15 -0
- package/dist/entry-express.d.mts +15 -0
- package/dist/entry-express.mjs +56 -0
- package/dist/entry-express.mjs.map +1 -0
- package/dist/entry-hono.cjs +35 -0
- package/dist/entry-hono.cjs.map +1 -0
- package/dist/entry-hono.d.cts +16 -0
- package/dist/entry-hono.d.mts +16 -0
- package/dist/entry-hono.mjs +34 -0
- package/dist/entry-hono.mjs.map +1 -0
- package/dist/entry-hooks-log.cjs +22 -0
- package/dist/entry-hooks-log.cjs.map +1 -0
- package/dist/entry-hooks-log.d.cts +23 -0
- package/dist/entry-hooks-log.d.mts +23 -0
- package/dist/entry-hooks-log.mjs +21 -0
- package/dist/entry-hooks-log.mjs.map +1 -0
- package/dist/entry-storage-cloudflare-kv.cjs +47 -0
- package/dist/entry-storage-cloudflare-kv.cjs.map +1 -0
- package/dist/entry-storage-cloudflare-kv.d.cts +42 -0
- package/dist/entry-storage-cloudflare-kv.d.mts +42 -0
- package/dist/entry-storage-cloudflare-kv.mjs +46 -0
- package/dist/entry-storage-cloudflare-kv.mjs.map +1 -0
- package/dist/entry-storage-drizzle.cjs +78 -0
- package/dist/entry-storage-drizzle.cjs.map +1 -0
- package/dist/entry-storage-drizzle.d.cts +30 -0
- package/dist/entry-storage-drizzle.d.mts +30 -0
- package/dist/entry-storage-drizzle.mjs +77 -0
- package/dist/entry-storage-drizzle.mjs.map +1 -0
- package/dist/entry-storage-file.cjs +4 -0
- package/dist/entry-storage-file.d.cts +30 -0
- package/dist/entry-storage-file.d.mts +30 -0
- package/dist/entry-storage-file.mjs +2 -0
- package/dist/entry-storage-libsql.cjs +3 -0
- package/dist/entry-storage-libsql.d.cts +48 -0
- package/dist/entry-storage-libsql.d.mts +48 -0
- package/dist/entry-storage-libsql.mjs +2 -0
- package/dist/entry-storage-memory.cjs +3 -0
- package/dist/entry-storage-memory.d.cts +2 -0
- package/dist/entry-storage-memory.d.mts +2 -0
- package/dist/entry-storage-memory.mjs +2 -0
- package/dist/entry-storage-mongodb.cjs +3 -0
- package/dist/entry-storage-mongodb.d.cts +55 -0
- package/dist/entry-storage-mongodb.d.mts +55 -0
- package/dist/entry-storage-mongodb.mjs +2 -0
- package/dist/entry-storage-postgres.cjs +3 -0
- package/dist/entry-storage-postgres.d.cts +62 -0
- package/dist/entry-storage-postgres.d.mts +62 -0
- package/dist/entry-storage-postgres.mjs +2 -0
- package/dist/entry-storage-redis.cjs +4 -0
- package/dist/entry-storage-redis.d.cts +77 -0
- package/dist/entry-storage-redis.d.mts +77 -0
- package/dist/entry-storage-redis.mjs +2 -0
- package/dist/entry-storage-sqlite.cjs +3 -0
- package/dist/entry-storage-sqlite.d.cts +36 -0
- package/dist/entry-storage-sqlite.d.mts +36 -0
- package/dist/entry-storage-sqlite.mjs +2 -0
- package/dist/entry-storage-unstorage.cjs +42 -0
- package/dist/entry-storage-unstorage.cjs.map +1 -0
- package/dist/entry-storage-unstorage.d.cts +29 -0
- package/dist/entry-storage-unstorage.d.mts +29 -0
- package/dist/entry-storage-unstorage.mjs +41 -0
- package/dist/entry-storage-unstorage.mjs.map +1 -0
- package/dist/file-COBYZA4Q.cjs +148 -0
- package/dist/file-COBYZA4Q.cjs.map +1 -0
- package/dist/file-fi02eFHk.mjs +131 -0
- package/dist/file-fi02eFHk.mjs.map +1 -0
- package/dist/index.cjs +123 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +368 -0
- package/dist/index.d.mts +366 -0
- package/dist/index.mjs +61 -0
- package/dist/index.mjs.map +1 -0
- package/dist/keys-Byyj4quQ.mjs +111 -0
- package/dist/keys-Byyj4quQ.mjs.map +1 -0
- package/dist/keys-FiKpaVHX.cjs +302 -0
- package/dist/keys-FiKpaVHX.cjs.map +1 -0
- package/dist/libsql-bpVi0bXN.mjs +113 -0
- package/dist/libsql-bpVi0bXN.mjs.map +1 -0
- package/dist/libsql-pPJEo1e4.cjs +124 -0
- package/dist/libsql-pPJEo1e4.cjs.map +1 -0
- package/dist/memory-8Ef-PL5a.cjs +137 -0
- package/dist/memory-8Ef-PL5a.cjs.map +1 -0
- package/dist/memory-BMsSSwqn.mjs +127 -0
- package/dist/memory-BMsSSwqn.mjs.map +1 -0
- package/dist/memory-FnMJWCmB.d.cts +28 -0
- package/dist/memory-qIvANEs_.d.mts +28 -0
- package/dist/mongodb-Cy8yo0uk.cjs +108 -0
- package/dist/mongodb-Cy8yo0uk.cjs.map +1 -0
- package/dist/mongodb-Ddaq9mml.mjs +97 -0
- package/dist/mongodb-Ddaq9mml.mjs.map +1 -0
- package/dist/none-BnZtaGNJ.mjs +23 -0
- package/dist/none-BnZtaGNJ.mjs.map +1 -0
- package/dist/none-CAsxCOWN.cjs +49 -0
- package/dist/none-CAsxCOWN.cjs.map +1 -0
- package/dist/none-CZVrfnmF.cjs +33 -0
- package/dist/none-CZVrfnmF.cjs.map +1 -0
- package/dist/none-GhVIoh_s.mjs +33 -0
- package/dist/none-GhVIoh_s.mjs.map +1 -0
- package/dist/postgres-C8WbchFa.cjs +134 -0
- package/dist/postgres-C8WbchFa.cjs.map +1 -0
- package/dist/postgres-c3pAhmhr.mjs +123 -0
- package/dist/postgres-c3pAhmhr.mjs.map +1 -0
- package/dist/react.css +1 -0
- package/dist/react.js +31465 -0
- package/dist/receiver.cjs +43 -0
- package/dist/receiver.cjs.map +1 -0
- package/dist/receiver.d.cts +36 -0
- package/dist/receiver.d.mts +36 -0
- package/dist/receiver.mjs +40 -0
- package/dist/receiver.mjs.map +1 -0
- package/dist/redis-CFJkuSgB.cjs +270 -0
- package/dist/redis-CFJkuSgB.cjs.map +1 -0
- package/dist/redis-CvLi0KF7.mjs +254 -0
- package/dist/redis-CvLi0KF7.mjs.map +1 -0
- package/dist/roles-D0G9XqBq.cjs +128 -0
- package/dist/roles-D0G9XqBq.cjs.map +1 -0
- package/dist/roles-vp361lTk.mjs +99 -0
- package/dist/roles-vp361lTk.mjs.map +1 -0
- package/dist/schema-mo__wv4P.d.cts +233 -0
- package/dist/schema-mo__wv4P.d.mts +233 -0
- package/dist/schema.cjs +13 -0
- package/dist/schema.cjs.map +1 -0
- package/dist/schema.d.cts +2 -0
- package/dist/schema.d.mts +2 -0
- package/dist/schema.mjs +11 -0
- package/dist/schema.mjs.map +1 -0
- package/dist/signing.cjs +162 -0
- package/dist/signing.cjs.map +1 -0
- package/dist/signing.d.cts +73 -0
- package/dist/signing.d.mts +73 -0
- package/dist/signing.mjs +156 -0
- package/dist/signing.mjs.map +1 -0
- package/dist/sqlite-Cmqnrjes.mjs +67 -0
- package/dist/sqlite-Cmqnrjes.mjs.map +1 -0
- package/dist/sqlite-Dcufk0x3.cjs +78 -0
- package/dist/sqlite-Dcufk0x3.cjs.map +1 -0
- package/dist/table-Ce3Tzwqs.d.cts +11 -0
- package/dist/table-Ce3Tzwqs.d.mts +11 -0
- package/dist/testing.cjs +134 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +80 -0
- package/dist/testing.d.mts +80 -0
- package/dist/testing.mjs +131 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/types-react/react.d.ts +98 -0
- package/dist/types-react/schema.d.ts +229 -0
- package/dist/types-react/ui/App.d.ts +22 -0
- package/dist/types-react/ui/api.d.ts +97 -0
- package/dist/types-react/ui/components/JsonCodeEditor.d.ts +12 -0
- package/dist/types-react/ui/components/ThemeToggle.d.ts +2 -0
- package/dist/types-react/ui/components/Toast.d.ts +16 -0
- package/dist/types-react/ui/components/primitives.d.ts +50 -0
- package/dist/types-react/ui/components/ui-bits.d.ts +22 -0
- package/dist/types-react/ui/components/webhook-bits.d.ts +51 -0
- package/dist/types-react/ui/lib/format.d.ts +39 -0
- package/dist/types-react/ui/lib/nav-guard.d.ts +20 -0
- package/dist/types-react/ui/lib/utils.d.ts +3 -0
- package/dist/types-react/ui/theme.d.ts +12 -0
- package/dist/types-react/ui/types.d.ts +80 -0
- package/dist/types-react/ui/views/AuditView.d.ts +6 -0
- package/dist/types-react/ui/views/DeliveriesView.d.ts +12 -0
- package/dist/types-react/ui/views/EndpointsView.d.ts +11 -0
- package/dist/types-react/ui/views/EventTypesView.d.ts +11 -0
- package/dist/types-react/ui/views/MessagesView.d.ts +10 -0
- package/dist/types-react/ui/views/OverviewView.d.ts +12 -0
- package/dist/ui/assets/index-B0eoQX2U.css +1 -0
- package/dist/ui/assets/index-S5t_CLOe.js +209 -0
- package/dist/ui/index.html +14 -0
- package/package.json +487 -0
package/dist/cli.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.cjs","names":["parseDurationList","createWebhooksCore"],"sources":["../src/cli.ts"],"sourcesContent":["/**\n * `xtandard-webhooks` CLI. Operates on the same storage your app/panel uses\n * (configured via the `STORAGE_DRIVER` / `QUEUE_STORAGE_DRIVER` env vars,\n * mirroring the standalone app), so it slots into shell, CI, and split-worker\n * workflows.\n *\n * Commands: `serve` (panel + dispatcher, no Docker), `dispatch` (dispatcher\n * ONLY — the split-worker mode), `init`, `list-apps`, `list-endpoints`,\n * `publish`, `retry`, `verify`, `sign` (build a signed request — the signature\n * playground), and `listen` (a local inspecting receiver — the webhook.site\n * you run yourself).\n *\n * @module\n */\n\nimport type { AuthProvider } from \"./auth/contract.ts\";\nimport type { AuthorizationProvider } from \"./authorization/contract.ts\";\nimport {\n createWebhooksCore,\n type RetentionOptions,\n type RetentionRule,\n type WebhooksCore,\n} from \"./core.ts\";\nimport type { DispatcherOptions } from \"./dispatcher.ts\";\nimport { durationToMs, parseDurationList } from \"./duration.ts\";\nimport type { JsonValue, WebhookDuration } from \"./schema.ts\";\nimport type { WebhooksStorage } from \"./storage/contract.ts\";\n\ntype Driver = \"memory\" | \"file\" | \"redis\" | \"postgres\" | \"mongodb\" | \"sqlite\" | \"libsql\";\n\n/** The two storage roles: control plane (`STORAGE`) and delivery queue (`QUEUE`). */\ntype Role = \"STORAGE\" | \"QUEUE\";\n\nconst env = (key: string, fallback = \"\"): string => process.env[key] ?? fallback;\n\nconst isTruthy = (value: string): boolean => value === \"1\" || value.toLowerCase() === \"true\";\n\n/**\n * The driver env var for a role: `STORAGE_DRIVER` for the control plane,\n * `QUEUE_STORAGE_DRIVER` for the delivery queue.\n */\nconst driverEnv = (role: Role): string =>\n role === \"STORAGE\" ? \"STORAGE_DRIVER\" : \"QUEUE_STORAGE_DRIVER\";\n\n/**\n * Parse a duration env like `\"30d\"`, `\"34h\"`, `\"90m\"`, `\"10s\"` into a\n * {@link WebhookDuration}, warning and ignoring malformed values.\n */\nfunction parseDurationEnv(name: string): WebhookDuration | undefined {\n const raw = env(name);\n if (!raw) return undefined;\n try {\n durationToMs(raw as WebhookDuration); // validate eagerly\n return raw as WebhookDuration;\n } catch {\n process.stderr.write(\n `[xtandard/webhooks] Ignoring ${name}=\"${raw}\" — expected <number><unit> with unit ms|s|m|h|d (e.g. 34h, 30d).\\n`,\n );\n return undefined;\n }\n}\n\n/**\n * Retention from env: `MESSAGE_KEEP_LAST` / `MESSAGE_MAX_AGE` and\n * `AUDIT_KEEP_LAST` / `AUDIT_MAX_AGE`. Returns undefined when none are set.\n */\nfunction retentionFromEnv(): RetentionOptions | undefined {\n const rule = (keepVar: string, ageVar: string): RetentionRule | undefined => {\n const keepRaw = env(keepVar);\n const keepLast = keepRaw && /^\\d+$/.test(keepRaw) ? Number(keepRaw) : undefined;\n if (keepRaw && keepLast === undefined) {\n process.stderr.write(\n `[xtandard/webhooks] Ignoring ${keepVar}=\"${keepRaw}\" — expected a number.\\n`,\n );\n }\n const maxAge = parseDurationEnv(ageVar);\n if (keepLast === undefined && !maxAge) return undefined;\n return {\n ...(keepLast !== undefined ? { keepLast } : {}),\n ...(maxAge !== undefined ? { maxAge } : {}),\n };\n };\n const messages = rule(\"MESSAGE_KEEP_LAST\", \"MESSAGE_MAX_AGE\");\n const audit = rule(\"AUDIT_KEEP_LAST\", \"AUDIT_MAX_AGE\");\n if (!messages && !audit) return undefined;\n return {\n ...(messages ? { messages } : {}),\n ...(audit ? { audit } : {}),\n };\n}\n\n/** Dispatcher config from env: `RETRY_SCHEDULE` (comma list, e.g. `0s,5s,5m`). */\nfunction dispatcherOptionsFromEnv(): DispatcherOptions {\n const raw = env(\"RETRY_SCHEDULE\");\n if (!raw) return {};\n try {\n return { retrySchedule: parseDurationList(raw) };\n } catch {\n process.stderr.write(\n `[xtandard/webhooks] Ignoring RETRY_SCHEDULE=\"${raw}\" — expected a comma list of durations (e.g. \"0s,5s,5m,30m,2h,5h,10h\").\\n`,\n );\n return {};\n }\n}\n\n/** Whether the in-process dispatcher is enabled (`DISPATCHER=0|false` disables). */\nfunction dispatcherEnabled(): boolean {\n const raw = env(\"DISPATCHER\");\n if (!raw) return true;\n return !(raw === \"0\" || raw.toLowerCase() === \"false\");\n}\n\n/**\n * Build one storage role from env. `STORAGE` holds the control plane\n * (applications, event types, endpoints, messages, audit); `QUEUE` holds\n * deliveries + the due index and defaults to the same store (see\n * {@link buildQueueStorage}).\n */\nasync function buildStorage(role: Role): Promise<WebhooksStorage> {\n const driver = (env(driverEnv(role), \"file\") as Driver) || \"file\";\n const r = role.toLowerCase();\n switch (driver) {\n case \"redis\": {\n const { createRedisStorage } = await import(\"./storage/redis.ts\");\n return createRedisStorage({\n url: env(\"REDIS_URL\", \"redis://localhost:6379\"),\n prefix: env(`${role}_PREFIX`, `xtandard:webhooks:${r}`),\n });\n }\n case \"postgres\": {\n const { createPostgresStorage } = await import(\"./storage/postgres.ts\");\n return createPostgresStorage({\n connectionString:\n env(\"DATABASE_URL\") || env(\"POSTGRES_URL\", \"postgres://localhost:5432/postgres\"),\n table: env(`${role}_PG_TABLE`, `xtandard_webhooks_${r}`),\n });\n }\n case \"mongodb\": {\n const { createMongoStorage } = await import(\"./storage/mongodb.ts\");\n return createMongoStorage({\n url: env(\"MONGO_URL\", \"mongodb://localhost:27017\"),\n dbName: env(\"MONGO_DB\", \"xtandard_webhooks\"),\n collectionName: env(`${role}_MONGO_COLLECTION`, `webhooks_${r}`),\n });\n }\n case \"sqlite\": {\n // Requires running the CLI under Bun (`bunx xtandard-webhooks …`).\n const { createSqliteStorage } = await import(\"./storage/sqlite.ts\");\n return createSqliteStorage({\n path: env(`${role}_SQLITE_PATH`, `./.webhooks/${r}.sqlite`),\n });\n }\n case \"libsql\": {\n const { createLibsqlStorage } = await import(\"./storage/libsql.ts\");\n const authToken = env(\"LIBSQL_AUTH_TOKEN\");\n return createLibsqlStorage({\n url: env(`${role}_LIBSQL_URL`) || env(\"LIBSQL_URL\", `file:./.webhooks/${r}.db`),\n ...(authToken ? { authToken } : {}),\n });\n }\n case \"memory\": {\n const { createMemoryStorage } = await import(\"./storage/memory.ts\");\n return createMemoryStorage();\n }\n case \"file\":\n default: {\n const { createFileStorage } = await import(\"./storage/file.ts\");\n return createFileStorage({ dir: env(`${role}_FILE_DIR`, `./.webhooks/${r}`) });\n }\n }\n}\n\n/**\n * The queue store, or `undefined` to share the control-plane store. Only built\n * when `QUEUE_STORAGE_DRIVER` is explicitly set (split-plane deployments:\n * control data in Postgres, queue in Redis).\n */\nasync function buildQueueStorage(): Promise<WebhooksStorage | undefined> {\n if (!env(\"QUEUE_STORAGE_DRIVER\")) return undefined;\n return buildStorage(\"QUEUE\");\n}\n\n/**\n * A human-readable, log-safe description of where a storage role persists data\n * — for the `serve`/`dispatch` startup banner. File/SQLite paths are resolved\n * to absolute so \"where did my webhooks go?\" is obvious; connection-string\n * drivers print only the driver name (never the URL, which may carry\n * credentials).\n */\nasync function describeStorage(role: Role): Promise<string> {\n const { resolve } = await import(\"node:path\");\n const driver = (env(driverEnv(role), \"file\") as Driver) || \"file\";\n const r = role.toLowerCase();\n switch (driver) {\n case \"file\":\n return `file → ${resolve(env(`${role}_FILE_DIR`, `./.webhooks/${r}`))}`;\n case \"sqlite\":\n return `sqlite → ${resolve(env(`${role}_SQLITE_PATH`, `./.webhooks/${r}.sqlite`))}`;\n case \"memory\":\n return \"memory (ephemeral — not persisted)\";\n default:\n return driver;\n }\n}\n\n/** Build the auth + authorization providers from env (mirrors the standalone app). */\nasync function buildAuth(): Promise<{ auth: AuthProvider; authorization: AuthorizationProvider }> {\n const mode = env(\"AUTH_MODE\", \"none\");\n if (mode === \"basic\") {\n const [{ basicAuth }, { rolesAuthorization }] = await Promise.all([\n import(\"./auth/basic.ts\"),\n import(\"./authorization/roles.ts\"),\n ]);\n const passwordHash = env(\"AUTH_PASSWORD_HASH\");\n const password = env(\"AUTH_PASSWORD\");\n if (!passwordHash && !password) {\n process.stderr.write(\n \"[xtandard/webhooks] AUTH_MODE=basic but neither AUTH_PASSWORD_HASH nor AUTH_PASSWORD is set.\\n\",\n );\n }\n return {\n auth: basicAuth({\n users: [\n {\n username: env(\"AUTH_USERNAME\", \"admin\"),\n ...(passwordHash ? { passwordHash } : {}),\n ...(password ? { password } : {}),\n roles: [\"admin\"],\n },\n ],\n }),\n authorization: rolesAuthorization({}),\n };\n }\n const [{ noAuth }, { noAuthorization }] = await Promise.all([\n import(\"./auth/none.ts\"),\n import(\"./authorization/none.ts\"),\n ]);\n return { auth: noAuth(), authorization: noAuthorization() };\n}\n\ntype FetchHandler = (request: Request) => Response | Promise<Response>;\n\n/**\n * Serve a web-standard fetch handler under whatever runtime the CLI runs on:\n * `Bun.serve` under `bunx`, a `node:http` bridge under `npx`/Node. Resolves only\n * once the server is listening; the process then stays alive on the open socket.\n */\nasync function startServer(port: number, fetch: FetchHandler): Promise<void> {\n const bun = (globalThis as { Bun?: { serve: (options: unknown) => unknown } }).Bun;\n if (bun) {\n bun.serve({ port, fetch });\n return;\n }\n const { createServer } = await import(\"node:http\");\n const server = createServer((req, res) => {\n void (async () => {\n try {\n const chunks: Buffer[] = [];\n for await (const c of req) chunks.push(c as Buffer);\n const method = req.method ?? \"GET\";\n const headers = new Headers();\n for (const [k, v] of Object.entries(req.headers)) {\n if (v === undefined) continue;\n headers.set(k, Array.isArray(v) ? v.join(\", \") : v);\n }\n const host = req.headers.host ?? `localhost:${port}`;\n const url = `http://${host}${req.url ?? \"/\"}`;\n const hasBody = method !== \"GET\" && method !== \"HEAD\" && chunks.length > 0;\n const request = new Request(url, {\n method,\n headers,\n body: hasBody ? Buffer.concat(chunks) : undefined,\n });\n const response = await fetch(request);\n res.statusCode = response.status;\n response.headers.forEach((value, key) => res.setHeader(key, value));\n res.end(Buffer.from(await response.arrayBuffer()));\n } catch (err) {\n res.statusCode = 500;\n res.end(`Internal error: ${err instanceof Error ? err.message : String(err)}`);\n }\n })();\n });\n await new Promise<void>((resolve) => server.listen(port, resolve));\n}\n\n/** Verification outcome shown by `listen` for each captured request. */\nexport type InboundVerification =\n | { state: \"unchecked\" } // no --secret given\n | { state: \"ok\" }\n | { state: \"failed\"; reason: string };\n\n/**\n * Format one captured inbound webhook for the terminal — the `listen` command's\n * pretty-printer. Pure and side-effect-free so it can be unit-tested.\n */\nexport function formatInboundWebhook(input: {\n index: number;\n method: string;\n path: string;\n headers: Record<string, string>;\n body: string;\n verification: InboundVerification;\n at: string;\n}): string {\n const wh = (name: string) => input.headers[name] ?? input.headers[name.toLowerCase()] ?? \"—\";\n const badge =\n input.verification.state === \"ok\"\n ? \"signature: VERIFIED\"\n : input.verification.state === \"failed\"\n ? `signature: FAILED (${input.verification.reason})`\n : \"signature: not checked (pass --secret to verify)\";\n let prettyBody = input.body;\n try {\n prettyBody = JSON.stringify(JSON.parse(input.body), null, 2);\n } catch {\n // leave non-JSON bodies as-is\n }\n return [\n `\\n── #${input.index} ${input.method} ${input.path} ${input.at} ──`,\n `webhook-id: ${wh(\"webhook-id\")}`,\n `webhook-timestamp: ${wh(\"webhook-timestamp\")}`,\n `webhook-signature: ${wh(\"webhook-signature\")}`,\n badge,\n \"body:\",\n prettyBody,\n \"\",\n ].join(\"\\n\");\n}\n\n/** Minimal flag/value argv parser: `--key value` and `--flag`. */\nfunction parseArgs(argv: string[]): { _: string[]; flags: Record<string, string | boolean> } {\n const _: string[] = [];\n const flags: Record<string, string | boolean> = {};\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!;\n if (a.startsWith(\"--\")) {\n const key = a.slice(2);\n const next = argv[i + 1];\n if (next === undefined || next.startsWith(\"--\")) flags[key] = true;\n else {\n flags[key] = next;\n i++;\n }\n } else _.push(a);\n }\n return { _, flags };\n}\n\n/** A core over the env-configured storage (dispatcher NOT started). */\nasync function makeCore(): Promise<WebhooksCore> {\n const [storage, queueStorage] = await Promise.all([buildStorage(\"STORAGE\"), buildQueueStorage()]);\n const retention = retentionFromEnv();\n return createWebhooksCore({\n storage,\n ...(queueStorage ? { queueStorage } : {}),\n ...(retention ? { retention } : {}),\n dispatcher: dispatcherOptionsFromEnv(),\n });\n}\n\n/** Read this package's version from the nearest package.json (dist or src). */\nasync function pkgVersion(): Promise<string> {\n try {\n const { readFile } = await import(\"node:fs/promises\");\n const { fileURLToPath } = await import(\"node:url\");\n const pkg = JSON.parse(\n await readFile(fileURLToPath(new URL(\"../package.json\", import.meta.url)), \"utf8\"),\n ) as { version?: string };\n return pkg.version ?? \"unknown\";\n } catch {\n return \"unknown\";\n }\n}\n\nfunction helpText(version: string): string {\n return `xtandard-webhooks v${version} — self-hosted, Standard Webhooks-compliant outbound webhook control plane\n\nUsage:\n xtandard-webhooks <command> [options] # the binary, after: npm i -g @xtandard/webhooks\n npx @xtandard/webhooks <command> # without installing (or: bunx @xtandard/webhooks …)\n\nCommands:\n serve [--port <n>] Run the admin panel + API + delivery dispatcher (no Docker).\n dispatch [--port <n>] Run the delivery dispatcher ONLY (split-worker mode).\n With --port/$PORT: also serves GET /healthcheck.\n init [--app <key>] Create an application + an example event type.\n list-apps List applications.\n list-endpoints --app <key> List an application's endpoints.\n publish --app <key> --type <event> --data '<json>' [--idempotency-key <k>]\n Publish a message (ingest from shell/CI).\n retry --app <key> --delivery <id>\n Re-queue a dead-lettered delivery.\n verify --secret <whsec_…> --payload-file <path> --headers-file <path>\n Verify a captured webhook (receiver-side debugging):\n reads the raw payload + a JSON headers object,\n prints the envelope, exits 1 on failure.\n sign --secret <whsec_…> --data '<json>' [--id <msg_…>] [--timestamp <unix>] [--url <target>]\n Build a signed Standard Webhooks request (the\n signature playground): prints the headers + body,\n and a ready-to-run curl when --url is given.\n listen [--port <n>] [--secret <whsec_…>] [--status <code>]\n Run a local inspecting receiver (the webhook.site\n you host yourself): pretty-prints every incoming\n webhook; with --secret, verifies the signature.\n\nGlobal options:\n -h, --help Show this help.\n -v, --version Print the version.\n\n\\`serve\\` / \\`dispatch\\` options:\n --port <n> Port to listen on (default: $PORT or 3000).\n\nEnvironment variables\n Storage (control plane STORAGE_; delivery queue QUEUE_, defaults to the same store):\n STORAGE_DRIVER, QUEUE_STORAGE_DRIVER\n memory | file | redis | postgres | mongodb | sqlite | libsql\n (CLI default: file · Docker default: memory)\n REDIS_URL redis://localhost:6379 (driver: redis)\n STORAGE_PREFIX, QUEUE_PREFIX key namespace (driver: redis)\n DATABASE_URL | POSTGRES_URL postgres://… (driver: postgres)\n STORAGE_PG_TABLE, QUEUE_PG_TABLE (driver: postgres)\n MONGO_URL, MONGO_DB, STORAGE_MONGO_COLLECTION, QUEUE_MONGO_COLLECTION (driver: mongodb)\n STORAGE_FILE_DIR, QUEUE_FILE_DIR default ./.webhooks/{storage,queue} (driver: file)\n STORAGE_SQLITE_PATH, QUEUE_SQLITE_PATH (driver: sqlite, Bun only)\n LIBSQL_URL | STORAGE_LIBSQL_URL, QUEUE_LIBSQL_URL, LIBSQL_AUTH_TOKEN (driver: libsql)\n\n Server (\\`serve\\` / standalone):\n PORT 3000 Port to listen on (or --port).\n BASE_PATH \"\" URL prefix, e.g. \"/webhooks\".\n TITLE Navbar wordmark.\n LOGO_URL Logo image URL.\n READONLY 1|true Block all mutating operations.\n AUTH_MODE none|basic Authentication mode (default none).\n AUTH_USERNAME admin Username for basic auth.\n AUTH_PASSWORD_HASH scrypt hash (preferred; see docs/AUTH.md).\n AUTH_PASSWORD Plaintext password (dev only).\n PORTAL_SECRET Enables portal-token access (whpt_… bearer tokens).\n\n Delivery (\\`serve\\` / \\`dispatch\\` / standalone):\n DISPATCHER 1 0|false disables the in-process dispatcher\n (host publishes only; a split worker delivers).\n RETRY_SCHEDULE Comma list of retry delays, e.g. \"0s,5s,5m,30m,2h,5h,10h\".\n\n Retention (pruned opportunistically after publishes; kept if EITHER rule keeps it;\n messages with a non-terminal delivery are always kept):\n MESSAGE_KEEP_LAST Keep at most the N most recent messages per app.\n MESSAGE_MAX_AGE 30d Keep messages newer than this (ms|s|m|h|d, e.g. 34h).\n AUDIT_KEEP_LAST Keep at most the N most recent audit entries.\n AUDIT_MAX_AGE 90d Keep audit entries newer than this.\n\nExamples:\n # Quick local panel (file storage, no auth):\n npx @xtandard/webhooks serve --port 3004\n\n # Production-ish: Redis storage + basic auth:\n PORT=4000 AUTH_MODE=basic AUTH_USERNAME=admin AUTH_PASSWORD=secret \\\\\n STORAGE_DRIVER=redis REDIS_URL=redis://localhost:6379 \\\\\n npx @xtandard/webhooks serve\n\n # Split planes: Postgres control plane + Redis queue:\n STORAGE_DRIVER=postgres DATABASE_URL=postgres://localhost:5432/webhooks \\\\\n QUEUE_STORAGE_DRIVER=redis REDIS_URL=redis://localhost:6379 \\\\\n npx @xtandard/webhooks serve\n\n # Split worker: the web process publishes only (DISPATCHER=0); this delivers:\n STORAGE_DRIVER=redis REDIS_URL=redis://localhost:6379 \\\\\n npx @xtandard/webhooks dispatch\n\n # Publish from CI:\n xtandard-webhooks publish --app acme --type invoice.paid --data '{\"invoiceId\":\"inv_1\"}'\n\n # Debug a captured webhook on the receiving side:\n xtandard-webhooks verify --secret whsec_… --payload-file body.json --headers-file headers.json\n\n # Inspect webhooks locally (point an endpoint at http://localhost:4000):\n xtandard-webhooks listen --port 4000 --secret whsec_…\n\n # Build + fire a signed request by hand (the signature playground):\n xtandard-webhooks sign --secret whsec_… --data '{\"hi\":1}' --url http://localhost:4000\n\nReceivers verify with @xtandard/webhooks/receiver — or any Standard Webhooks\nlibrary. Docs: https://github.com/xantiagoma/xtandard-webhooks\n`;\n}\n\n/** Entry point. Returns the process exit code. */\nexport async function run(argv: string[]): Promise<number> {\n const { _, flags } = parseArgs(argv);\n const command = _[0];\n\n // `--version` (bare) / `-v` / `version` → print version. Only the boolean form\n // is treated as \"print version\" so a future `--version <value>` flag can coexist.\n if (flags.version === true || argv.includes(\"-v\") || command === \"version\") {\n process.stdout.write(`${await pkgVersion()}\\n`);\n return 0;\n }\n\n const wantsHelp = Boolean(flags.help) || argv.includes(\"-h\") || command === \"help\";\n if (!command || wantsHelp) {\n process.stdout.write(helpText(await pkgVersion()));\n // Explicit help request → success; bare invocation with no command → usage error.\n return wantsHelp ? 0 : 1;\n }\n\n try {\n switch (command) {\n case \"init\": {\n const core = await makeCore();\n const app = typeof flags.app === \"string\" ? flags.app : env(\"APP\", \"default\");\n const existing = await core.getApplication(app);\n if (!existing) await core.createApplication({ key: app });\n await core.upsertEventType({\n name: \"example.ping\",\n description: \"Example event type created by `xtandard-webhooks init`.\",\n });\n process.stdout.write(\n `Initialized application \"${app}\" with event type \"example.ping\".\\n` +\n `Add endpoints in the panel (xtandard-webhooks serve), then:\\n` +\n ` xtandard-webhooks publish --app ${app} --type example.ping --data '{\"hello\":\"world\"}'\\n`,\n );\n return 0;\n }\n case \"list-apps\": {\n const core = await makeCore();\n const apps = await core.listApplications();\n if (apps.length === 0) process.stdout.write(\"No applications.\\n\");\n for (const app of apps) {\n process.stdout.write(`${app.key}${app.name ? ` ${app.name}` : \"\"}\\n`);\n }\n return 0;\n }\n case \"list-endpoints\": {\n if (typeof flags.app !== \"string\") {\n process.stderr.write(\"Usage: xtandard-webhooks list-endpoints --app <key>\\n\");\n return 1;\n }\n const core = await makeCore();\n const endpoints = await core.listEndpoints(flags.app);\n if (endpoints.length === 0) process.stdout.write(\"No endpoints.\\n\");\n for (const endpoint of endpoints) {\n const subscriptions = endpoint.eventTypes?.length\n ? endpoint.eventTypes.join(\",\")\n : \"all events\";\n process.stdout.write(\n `${endpoint.disabled ? \"○\" : \"●\"} ${endpoint.id} ${endpoint.url} [${subscriptions}]\\n`,\n );\n }\n return 0;\n }\n case \"publish\": {\n if (typeof flags.app !== \"string\" || typeof flags.type !== \"string\") {\n process.stderr.write(\n \"Usage: xtandard-webhooks publish --app <key> --type <event> --data '<json>' [--idempotency-key <k>]\\n\",\n );\n return 1;\n }\n let payload: JsonValue = {};\n if (typeof flags.data === \"string\") {\n try {\n payload = JSON.parse(flags.data) as JsonValue;\n } catch {\n process.stderr.write(\"Invalid --data JSON.\\n\");\n return 1;\n }\n }\n const core = await makeCore();\n const idempotencyKey =\n typeof flags[\"idempotency-key\"] === \"string\" ? flags[\"idempotency-key\"] : undefined;\n const result = await core.publish(flags.app, {\n eventType: flags.type,\n payload,\n ...(idempotencyKey !== undefined ? { idempotencyKey } : {}),\n });\n process.stdout.write(\n `${result.deduplicated ? \"Deduplicated\" : \"Published\"} ${result.message.id} → ` +\n `${result.deliveries.length} deliver${result.deliveries.length === 1 ? \"y\" : \"ies\"} queued.\\n`,\n );\n return 0;\n }\n case \"retry\": {\n if (typeof flags.app !== \"string\" || typeof flags.delivery !== \"string\") {\n process.stderr.write(\"Usage: xtandard-webhooks retry --app <key> --delivery <id>\\n\");\n return 1;\n }\n const core = await makeCore();\n const delivery = await core.retryDelivery(flags.app, flags.delivery);\n process.stdout.write(`Re-queued delivery ${delivery.id} (status: ${delivery.status}).\\n`);\n return 0;\n }\n case \"verify\": {\n if (\n typeof flags.secret !== \"string\" ||\n typeof flags[\"payload-file\"] !== \"string\" ||\n typeof flags[\"headers-file\"] !== \"string\"\n ) {\n process.stderr.write(\n \"Usage: xtandard-webhooks verify --secret <whsec_…> --payload-file <path> --headers-file <path>\\n\",\n );\n return 1;\n }\n const { readFile } = await import(\"node:fs/promises\");\n const payload = await readFile(flags[\"payload-file\"], \"utf8\");\n let headers: Record<string, string>;\n try {\n headers = JSON.parse(await readFile(flags[\"headers-file\"], \"utf8\")) as Record<\n string,\n string\n >;\n } catch {\n process.stderr.write(\"Invalid --headers-file: expected a JSON object of headers.\\n\");\n return 1;\n }\n const { verify, WebhookVerificationError } = await import(\"./signing.ts\");\n try {\n const envelope = await verify({ payload, headers, secret: flags.secret });\n process.stdout.write(`Signature OK.\\n${JSON.stringify(envelope, null, 2)}\\n`);\n return 0;\n } catch (err) {\n if (err instanceof WebhookVerificationError) {\n process.stderr.write(`Verification FAILED: ${err.message}\\n`);\n return 1;\n }\n throw err;\n }\n }\n case \"sign\": {\n // The signature playground: build a fully signed Standard Webhooks\n // request from a secret + payload, so you can curl it at a receiver or\n // paste it into https://www.standardwebhooks.com/simulate.\n if (typeof flags.secret !== \"string\" || typeof flags.data !== \"string\") {\n process.stderr.write(\n \"Usage: xtandard-webhooks sign --secret <whsec_…> --data '<json>' [--id <msg_…>] [--timestamp <unix-seconds>] [--url <post-target>]\\n\",\n );\n return 1;\n }\n // Validate the payload is JSON, but sign the exact bytes given.\n try {\n JSON.parse(flags.data);\n } catch {\n process.stderr.write(\"Invalid --data: expected a JSON string.\\n\");\n return 1;\n }\n const { newId } = await import(\"./id.ts\");\n const { sign } = await import(\"./signing.ts\");\n const id = typeof flags.id === \"string\" ? flags.id : newId(\"msg\");\n const timestamp =\n typeof flags.timestamp === \"string\"\n ? Number(flags.timestamp)\n : Math.floor(Date.now() / 1000);\n const signature = await sign(flags.secret, id, timestamp, flags.data);\n const headerLines = [\n `webhook-id: ${id}`,\n `webhook-timestamp: ${timestamp}`,\n `webhook-signature: ${signature}`,\n ];\n process.stdout.write(`${headerLines.join(\"\\n\")}\\n\\n${flags.data}\\n`);\n if (typeof flags.url === \"string\") {\n const curl = [\n `curl -X POST ${flags.url} \\\\`,\n ` -H 'content-type: application/json' \\\\`,\n ` -H 'webhook-id: ${id}' \\\\`,\n ` -H 'webhook-timestamp: ${timestamp}' \\\\`,\n ` -H 'webhook-signature: ${signature}' \\\\`,\n ` -d '${flags.data.replace(/'/g, \"'\\\\''\")}'`,\n ].join(\"\\n\");\n process.stdout.write(`\\n${curl}\\n`);\n }\n return 0;\n }\n case \"listen\": {\n // A local inspecting receiver — the webhook.site you run yourself.\n // Prints every incoming request; with --secret it verifies the\n // signature and shows a VERIFIED/FAILED badge.\n const port = Number((flags.port as string) || env(\"PORT\", \"4000\"));\n const secret = typeof flags.secret === \"string\" ? flags.secret : undefined;\n const status = typeof flags.status === \"string\" ? Number(flags.status) : 200;\n const { verify, WebhookVerificationError } = await import(\"./signing.ts\");\n let count = 0;\n\n await startServer(port, async (request) => {\n const url = new URL(request.url);\n if (url.pathname === \"/healthcheck\") {\n return new Response(JSON.stringify({ status: \"ok\" }), {\n headers: { \"content-type\": \"application/json\" },\n });\n }\n const body = await request.text();\n const headers: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headers[key] = value;\n });\n let verification: InboundVerification = { state: \"unchecked\" };\n if (secret) {\n try {\n await verify({ payload: body, headers, secret });\n verification = { state: \"ok\" };\n } catch (err) {\n verification = {\n state: \"failed\",\n reason: err instanceof WebhookVerificationError ? err.message : String(err),\n };\n }\n }\n count += 1;\n process.stdout.write(\n formatInboundWebhook({\n index: count,\n method: request.method,\n path: url.pathname,\n headers,\n body,\n verification,\n at: new Date().toISOString(),\n }),\n );\n // A signature failure answers 401 so senders exercise their retry path;\n // otherwise echo the configured status (default 200).\n if (verification.state === \"failed\")\n return new Response(\"invalid signature\", { status: 401 });\n return new Response(\"ok\", { status });\n });\n process.stdout.write(\n `[xtandard/webhooks] listening for webhooks on http://localhost:${port}` +\n `${secret ? \" (verifying signatures)\" : \" (not verifying — pass --secret)\"}\\n`,\n );\n return await new Promise<number>(() => {});\n }\n case \"dispatch\": {\n const core = await makeCore();\n const { createDispatcher } = await import(\"./dispatcher.ts\");\n const dispatcher = createDispatcher(core); // merges core.options.dispatcher (RETRY_SCHEDULE)\n dispatcher.start();\n\n const [storageDesc, queueDesc] = await Promise.all([\n describeStorage(\"STORAGE\"),\n env(\"QUEUE_STORAGE_DRIVER\") ? describeStorage(\"QUEUE\") : Promise.resolve(\"(same store)\"),\n ]);\n process.stdout.write(`[xtandard/webhooks] storage: ${storageDesc}\\n`);\n process.stdout.write(`[xtandard/webhooks] queue: ${queueDesc}\\n`);\n\n // Optional minimal healthcheck server — only when a port was asked for.\n const portRaw = typeof flags.port === \"string\" ? flags.port : env(\"PORT\");\n if (portRaw) {\n const port = Number(portRaw);\n await startServer(port, (request) => {\n const url = new URL(request.url);\n if (url.pathname === \"/healthcheck\") {\n return new Response(JSON.stringify({ status: \"ok\", dispatcher: \"running\" }), {\n headers: { \"content-type\": \"application/json\" },\n });\n }\n return new Response(\"Not Found\", { status: 404 });\n });\n process.stdout.write(\n `[xtandard/webhooks] dispatcher running; healthcheck on http://localhost:${port}/healthcheck\\n`,\n );\n } else {\n // Dispatcher timers are unref()ed by design; hold the event loop open.\n setInterval(() => {}, 2 ** 30);\n process.stdout.write(\"[xtandard/webhooks] dispatcher running.\\n\");\n }\n // The worker owns the process now; never resolve so the bin doesn't exit.\n return await new Promise<number>(() => {});\n }\n case \"serve\": {\n const port = Number((flags.port as string) || env(\"PORT\", \"3000\"));\n const basePath = env(\"BASE_PATH\", \"\");\n const title = env(\"TITLE\", \"@xtandard/webhooks\");\n const logoUrl = env(\"LOGO_URL\");\n const readonly = isTruthy(env(\"READONLY\"));\n const authMode = env(\"AUTH_MODE\", \"none\");\n const portalSecret = env(\"PORTAL_SECRET\");\n\n const { createFetchHandler } = await import(\"./server/create-fetch-handler.ts\");\n const [storage, queueStorage] = await Promise.all([\n buildStorage(\"STORAGE\"),\n buildQueueStorage(),\n ]);\n const { auth, authorization } = await buildAuth();\n\n if (authMode === \"none\") {\n process.stderr.write(\n \"[xtandard/webhooks] AUTH_MODE=none — do NOT expose this publicly without authentication.\\n\",\n );\n }\n\n const retention = retentionFromEnv();\n const panel = createFetchHandler({\n storage,\n ...(queueStorage ? { queueStorage } : {}),\n basePath,\n title,\n ...(logoUrl ? { logoUrl } : {}),\n readonly,\n auth,\n authorization,\n ...(portalSecret ? { portal: { secret: portalSecret } } : {}),\n ...(retention ? { retention } : {}),\n dispatcher: dispatcherEnabled() ? dispatcherOptionsFromEnv() : false,\n });\n\n const normalizedBase =\n basePath && basePath !== \"/\"\n ? basePath.startsWith(\"/\")\n ? basePath\n : `/${basePath}`\n : \"\";\n\n const handler: FetchHandler = (request) => {\n const url = new URL(request.url);\n if (url.pathname === \"/healthcheck\" || url.pathname === `${normalizedBase}/healthcheck`) {\n return new Response(JSON.stringify({ status: \"ok\", title }), {\n headers: { \"content-type\": \"application/json\" },\n });\n }\n return panel.fetch(request);\n };\n\n const [storageDesc, queueDesc] = await Promise.all([\n describeStorage(\"STORAGE\"),\n env(\"QUEUE_STORAGE_DRIVER\") ? describeStorage(\"QUEUE\") : Promise.resolve(\"(same store)\"),\n ]);\n process.stdout.write(`[xtandard/webhooks] storage: ${storageDesc}\\n`);\n process.stdout.write(`[xtandard/webhooks] queue: ${queueDesc}\\n`);\n process.stdout.write(\n `[xtandard/webhooks] dispatcher: ${panel.dispatcher ? \"running\" : \"disabled (DISPATCHER=0)\"}\\n`,\n );\n\n await startServer(port, handler);\n process.stdout.write(\n `[xtandard/webhooks] listening on http://localhost:${port}${normalizedBase || \"/\"}\\n`,\n );\n // The server owns the process now; never resolve so the bin doesn't exit.\n return await new Promise<number>(() => {});\n }\n default:\n process.stderr.write(`Unknown command: ${command}\\n\\n${helpText(await pkgVersion())}`);\n return 1;\n }\n } catch (err) {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n return 1;\n }\n}\n"],"mappings":"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"}
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/cli.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* `xtandard-webhooks` CLI. Operates on the same storage your app/panel uses
|
|
4
|
+
* (configured via the `STORAGE_DRIVER` / `QUEUE_STORAGE_DRIVER` env vars,
|
|
5
|
+
* mirroring the standalone app), so it slots into shell, CI, and split-worker
|
|
6
|
+
* workflows.
|
|
7
|
+
*
|
|
8
|
+
* Commands: `serve` (panel + dispatcher, no Docker), `dispatch` (dispatcher
|
|
9
|
+
* ONLY — the split-worker mode), `init`, `list-apps`, `list-endpoints`,
|
|
10
|
+
* `publish`, `retry`, `verify`, `sign` (build a signed request — the signature
|
|
11
|
+
* playground), and `listen` (a local inspecting receiver — the webhook.site
|
|
12
|
+
* you run yourself).
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
/** Verification outcome shown by `listen` for each captured request. */
|
|
17
|
+
type InboundVerification = {
|
|
18
|
+
state: "unchecked";
|
|
19
|
+
} | {
|
|
20
|
+
state: "ok";
|
|
21
|
+
} | {
|
|
22
|
+
state: "failed";
|
|
23
|
+
reason: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Format one captured inbound webhook for the terminal — the `listen` command's
|
|
27
|
+
* pretty-printer. Pure and side-effect-free so it can be unit-tested.
|
|
28
|
+
*/
|
|
29
|
+
declare function formatInboundWebhook(input: {
|
|
30
|
+
index: number;
|
|
31
|
+
method: string;
|
|
32
|
+
path: string;
|
|
33
|
+
headers: Record<string, string>;
|
|
34
|
+
body: string;
|
|
35
|
+
verification: InboundVerification;
|
|
36
|
+
at: string;
|
|
37
|
+
}): string;
|
|
38
|
+
/** Entry point. Returns the process exit code. */
|
|
39
|
+
declare function run(argv: string[]): Promise<number>;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { InboundVerification, formatInboundWebhook, run };
|
|
42
|
+
//# sourceMappingURL=cli.d.cts.map
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/cli.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* `xtandard-webhooks` CLI. Operates on the same storage your app/panel uses
|
|
4
|
+
* (configured via the `STORAGE_DRIVER` / `QUEUE_STORAGE_DRIVER` env vars,
|
|
5
|
+
* mirroring the standalone app), so it slots into shell, CI, and split-worker
|
|
6
|
+
* workflows.
|
|
7
|
+
*
|
|
8
|
+
* Commands: `serve` (panel + dispatcher, no Docker), `dispatch` (dispatcher
|
|
9
|
+
* ONLY — the split-worker mode), `init`, `list-apps`, `list-endpoints`,
|
|
10
|
+
* `publish`, `retry`, `verify`, `sign` (build a signed request — the signature
|
|
11
|
+
* playground), and `listen` (a local inspecting receiver — the webhook.site
|
|
12
|
+
* you run yourself).
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
/** Verification outcome shown by `listen` for each captured request. */
|
|
17
|
+
type InboundVerification = {
|
|
18
|
+
state: "unchecked";
|
|
19
|
+
} | {
|
|
20
|
+
state: "ok";
|
|
21
|
+
} | {
|
|
22
|
+
state: "failed";
|
|
23
|
+
reason: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Format one captured inbound webhook for the terminal — the `listen` command's
|
|
27
|
+
* pretty-printer. Pure and side-effect-free so it can be unit-tested.
|
|
28
|
+
*/
|
|
29
|
+
declare function formatInboundWebhook(input: {
|
|
30
|
+
index: number;
|
|
31
|
+
method: string;
|
|
32
|
+
path: string;
|
|
33
|
+
headers: Record<string, string>;
|
|
34
|
+
body: string;
|
|
35
|
+
verification: InboundVerification;
|
|
36
|
+
at: string;
|
|
37
|
+
}): string;
|
|
38
|
+
/** Entry point. Returns the process exit code. */
|
|
39
|
+
declare function run(argv: string[]): Promise<number>;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { InboundVerification, formatInboundWebhook, run };
|
|
42
|
+
//# sourceMappingURL=cli.d.mts.map
|