@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.
Files changed (279) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +315 -0
  3. package/bin/xtandard-webhooks.mjs +3 -0
  4. package/dist/basic-BIW3Rvuz.cjs +199 -0
  5. package/dist/basic-BIW3Rvuz.cjs.map +1 -0
  6. package/dist/basic-DKk0Xfuu.mjs +176 -0
  7. package/dist/basic-DKk0Xfuu.mjs.map +1 -0
  8. package/dist/chunk-D7D4PA-g.mjs +13 -0
  9. package/dist/cli.cjs +655 -0
  10. package/dist/cli.cjs.map +1 -0
  11. package/dist/cli.d.cts +42 -0
  12. package/dist/cli.d.mts +42 -0
  13. package/dist/cli.mjs +653 -0
  14. package/dist/cli.mjs.map +1 -0
  15. package/dist/contract-8h-Azxa5.d.cts +71 -0
  16. package/dist/contract-9XpcwcCn.mjs +22 -0
  17. package/dist/contract-9XpcwcCn.mjs.map +1 -0
  18. package/dist/contract-B2d5dNU3.cjs +33 -0
  19. package/dist/contract-B2d5dNU3.cjs.map +1 -0
  20. package/dist/contract-BEhDcd_5.mjs +28 -0
  21. package/dist/contract-BEhDcd_5.mjs.map +1 -0
  22. package/dist/contract-Bf1qguwt.cjs +57 -0
  23. package/dist/contract-Bf1qguwt.cjs.map +1 -0
  24. package/dist/contract-Bnb3fgRJ.d.cts +177 -0
  25. package/dist/contract-C2r2Xzwp.d.mts +46 -0
  26. package/dist/contract-CiPskNvS.d.cts +46 -0
  27. package/dist/contract-DhQ4JjGG.d.mts +71 -0
  28. package/dist/contract-T1kcZNdG.d.mts +177 -0
  29. package/dist/contract-lETlIuXo.d.cts +30 -0
  30. package/dist/contract-lETlIuXo.d.mts +30 -0
  31. package/dist/core-CMpnmI5Q.mjs +1605 -0
  32. package/dist/core-CMpnmI5Q.mjs.map +1 -0
  33. package/dist/core-DT4ppWh8.d.mts +502 -0
  34. package/dist/core-KJawHjFF.d.cts +502 -0
  35. package/dist/core-ZGhH6Vs2.cjs +1790 -0
  36. package/dist/core-ZGhH6Vs2.cjs.map +1 -0
  37. package/dist/core.cjs +8 -0
  38. package/dist/core.d.cts +2 -0
  39. package/dist/core.d.mts +2 -0
  40. package/dist/core.mjs +2 -0
  41. package/dist/create-fetch-handler-BIdk9P30.mjs +1724 -0
  42. package/dist/create-fetch-handler-BIdk9P30.mjs.map +1 -0
  43. package/dist/create-fetch-handler-CmooujQo.cjs +1771 -0
  44. package/dist/create-fetch-handler-CmooujQo.cjs.map +1 -0
  45. package/dist/create-fetch-handler-Dlkhustu.d.cts +162 -0
  46. package/dist/create-fetch-handler-jy3hy5nZ.d.mts +162 -0
  47. package/dist/dispatcher-B0xTEHt1.cjs +212 -0
  48. package/dist/dispatcher-B0xTEHt1.cjs.map +1 -0
  49. package/dist/dispatcher-Coubwrka.mjs +196 -0
  50. package/dist/dispatcher-Coubwrka.mjs.map +1 -0
  51. package/dist/entry-auth-basic.cjs +5 -0
  52. package/dist/entry-auth-basic.d.cts +83 -0
  53. package/dist/entry-auth-basic.d.mts +83 -0
  54. package/dist/entry-auth-basic.mjs +2 -0
  55. package/dist/entry-auth-delegated.cjs +28 -0
  56. package/dist/entry-auth-delegated.cjs.map +1 -0
  57. package/dist/entry-auth-delegated.d.cts +36 -0
  58. package/dist/entry-auth-delegated.d.mts +36 -0
  59. package/dist/entry-auth-delegated.mjs +27 -0
  60. package/dist/entry-auth-delegated.mjs.map +1 -0
  61. package/dist/entry-auth-none.cjs +4 -0
  62. package/dist/entry-auth-none.d.cts +25 -0
  63. package/dist/entry-auth-none.d.mts +25 -0
  64. package/dist/entry-auth-none.mjs +2 -0
  65. package/dist/entry-authorization-delegated.cjs +27 -0
  66. package/dist/entry-authorization-delegated.cjs.map +1 -0
  67. package/dist/entry-authorization-delegated.d.cts +31 -0
  68. package/dist/entry-authorization-delegated.d.mts +31 -0
  69. package/dist/entry-authorization-delegated.mjs +26 -0
  70. package/dist/entry-authorization-delegated.mjs.map +1 -0
  71. package/dist/entry-authorization-none.cjs +3 -0
  72. package/dist/entry-authorization-none.d.cts +18 -0
  73. package/dist/entry-authorization-none.d.mts +18 -0
  74. package/dist/entry-authorization-none.mjs +2 -0
  75. package/dist/entry-authorization-roles.cjs +6 -0
  76. package/dist/entry-authorization-roles.d.cts +65 -0
  77. package/dist/entry-authorization-roles.d.mts +65 -0
  78. package/dist/entry-authorization-roles.mjs +2 -0
  79. package/dist/entry-bun.cjs +24 -0
  80. package/dist/entry-bun.cjs.map +1 -0
  81. package/dist/entry-bun.d.cts +8 -0
  82. package/dist/entry-bun.d.mts +8 -0
  83. package/dist/entry-bun.mjs +23 -0
  84. package/dist/entry-bun.mjs.map +1 -0
  85. package/dist/entry-drizzle-mysql.cjs +20 -0
  86. package/dist/entry-drizzle-mysql.cjs.map +1 -0
  87. package/dist/entry-drizzle-mysql.d.cts +27 -0
  88. package/dist/entry-drizzle-mysql.d.mts +27 -0
  89. package/dist/entry-drizzle-mysql.mjs +19 -0
  90. package/dist/entry-drizzle-mysql.mjs.map +1 -0
  91. package/dist/entry-drizzle-pg.cjs +21 -0
  92. package/dist/entry-drizzle-pg.cjs.map +1 -0
  93. package/dist/entry-drizzle-pg.d.cts +26 -0
  94. package/dist/entry-drizzle-pg.d.mts +26 -0
  95. package/dist/entry-drizzle-pg.mjs +20 -0
  96. package/dist/entry-drizzle-pg.mjs.map +1 -0
  97. package/dist/entry-drizzle-sqlite.cjs +21 -0
  98. package/dist/entry-drizzle-sqlite.cjs.map +1 -0
  99. package/dist/entry-drizzle-sqlite.d.cts +23 -0
  100. package/dist/entry-drizzle-sqlite.d.mts +23 -0
  101. package/dist/entry-drizzle-sqlite.mjs +20 -0
  102. package/dist/entry-drizzle-sqlite.mjs.map +1 -0
  103. package/dist/entry-elysia.cjs +125 -0
  104. package/dist/entry-elysia.cjs.map +1 -0
  105. package/dist/entry-elysia.d.cts +1017 -0
  106. package/dist/entry-elysia.d.mts +1017 -0
  107. package/dist/entry-elysia.mjs +123 -0
  108. package/dist/entry-elysia.mjs.map +1 -0
  109. package/dist/entry-express.cjs +57 -0
  110. package/dist/entry-express.cjs.map +1 -0
  111. package/dist/entry-express.d.cts +15 -0
  112. package/dist/entry-express.d.mts +15 -0
  113. package/dist/entry-express.mjs +56 -0
  114. package/dist/entry-express.mjs.map +1 -0
  115. package/dist/entry-hono.cjs +35 -0
  116. package/dist/entry-hono.cjs.map +1 -0
  117. package/dist/entry-hono.d.cts +16 -0
  118. package/dist/entry-hono.d.mts +16 -0
  119. package/dist/entry-hono.mjs +34 -0
  120. package/dist/entry-hono.mjs.map +1 -0
  121. package/dist/entry-hooks-log.cjs +22 -0
  122. package/dist/entry-hooks-log.cjs.map +1 -0
  123. package/dist/entry-hooks-log.d.cts +23 -0
  124. package/dist/entry-hooks-log.d.mts +23 -0
  125. package/dist/entry-hooks-log.mjs +21 -0
  126. package/dist/entry-hooks-log.mjs.map +1 -0
  127. package/dist/entry-storage-cloudflare-kv.cjs +47 -0
  128. package/dist/entry-storage-cloudflare-kv.cjs.map +1 -0
  129. package/dist/entry-storage-cloudflare-kv.d.cts +42 -0
  130. package/dist/entry-storage-cloudflare-kv.d.mts +42 -0
  131. package/dist/entry-storage-cloudflare-kv.mjs +46 -0
  132. package/dist/entry-storage-cloudflare-kv.mjs.map +1 -0
  133. package/dist/entry-storage-drizzle.cjs +78 -0
  134. package/dist/entry-storage-drizzle.cjs.map +1 -0
  135. package/dist/entry-storage-drizzle.d.cts +30 -0
  136. package/dist/entry-storage-drizzle.d.mts +30 -0
  137. package/dist/entry-storage-drizzle.mjs +77 -0
  138. package/dist/entry-storage-drizzle.mjs.map +1 -0
  139. package/dist/entry-storage-file.cjs +4 -0
  140. package/dist/entry-storage-file.d.cts +30 -0
  141. package/dist/entry-storage-file.d.mts +30 -0
  142. package/dist/entry-storage-file.mjs +2 -0
  143. package/dist/entry-storage-libsql.cjs +3 -0
  144. package/dist/entry-storage-libsql.d.cts +48 -0
  145. package/dist/entry-storage-libsql.d.mts +48 -0
  146. package/dist/entry-storage-libsql.mjs +2 -0
  147. package/dist/entry-storage-memory.cjs +3 -0
  148. package/dist/entry-storage-memory.d.cts +2 -0
  149. package/dist/entry-storage-memory.d.mts +2 -0
  150. package/dist/entry-storage-memory.mjs +2 -0
  151. package/dist/entry-storage-mongodb.cjs +3 -0
  152. package/dist/entry-storage-mongodb.d.cts +55 -0
  153. package/dist/entry-storage-mongodb.d.mts +55 -0
  154. package/dist/entry-storage-mongodb.mjs +2 -0
  155. package/dist/entry-storage-postgres.cjs +3 -0
  156. package/dist/entry-storage-postgres.d.cts +62 -0
  157. package/dist/entry-storage-postgres.d.mts +62 -0
  158. package/dist/entry-storage-postgres.mjs +2 -0
  159. package/dist/entry-storage-redis.cjs +4 -0
  160. package/dist/entry-storage-redis.d.cts +77 -0
  161. package/dist/entry-storage-redis.d.mts +77 -0
  162. package/dist/entry-storage-redis.mjs +2 -0
  163. package/dist/entry-storage-sqlite.cjs +3 -0
  164. package/dist/entry-storage-sqlite.d.cts +36 -0
  165. package/dist/entry-storage-sqlite.d.mts +36 -0
  166. package/dist/entry-storage-sqlite.mjs +2 -0
  167. package/dist/entry-storage-unstorage.cjs +42 -0
  168. package/dist/entry-storage-unstorage.cjs.map +1 -0
  169. package/dist/entry-storage-unstorage.d.cts +29 -0
  170. package/dist/entry-storage-unstorage.d.mts +29 -0
  171. package/dist/entry-storage-unstorage.mjs +41 -0
  172. package/dist/entry-storage-unstorage.mjs.map +1 -0
  173. package/dist/file-COBYZA4Q.cjs +148 -0
  174. package/dist/file-COBYZA4Q.cjs.map +1 -0
  175. package/dist/file-fi02eFHk.mjs +131 -0
  176. package/dist/file-fi02eFHk.mjs.map +1 -0
  177. package/dist/index.cjs +123 -0
  178. package/dist/index.cjs.map +1 -0
  179. package/dist/index.d.cts +368 -0
  180. package/dist/index.d.mts +366 -0
  181. package/dist/index.mjs +61 -0
  182. package/dist/index.mjs.map +1 -0
  183. package/dist/keys-Byyj4quQ.mjs +111 -0
  184. package/dist/keys-Byyj4quQ.mjs.map +1 -0
  185. package/dist/keys-FiKpaVHX.cjs +302 -0
  186. package/dist/keys-FiKpaVHX.cjs.map +1 -0
  187. package/dist/libsql-bpVi0bXN.mjs +113 -0
  188. package/dist/libsql-bpVi0bXN.mjs.map +1 -0
  189. package/dist/libsql-pPJEo1e4.cjs +124 -0
  190. package/dist/libsql-pPJEo1e4.cjs.map +1 -0
  191. package/dist/memory-8Ef-PL5a.cjs +137 -0
  192. package/dist/memory-8Ef-PL5a.cjs.map +1 -0
  193. package/dist/memory-BMsSSwqn.mjs +127 -0
  194. package/dist/memory-BMsSSwqn.mjs.map +1 -0
  195. package/dist/memory-FnMJWCmB.d.cts +28 -0
  196. package/dist/memory-qIvANEs_.d.mts +28 -0
  197. package/dist/mongodb-Cy8yo0uk.cjs +108 -0
  198. package/dist/mongodb-Cy8yo0uk.cjs.map +1 -0
  199. package/dist/mongodb-Ddaq9mml.mjs +97 -0
  200. package/dist/mongodb-Ddaq9mml.mjs.map +1 -0
  201. package/dist/none-BnZtaGNJ.mjs +23 -0
  202. package/dist/none-BnZtaGNJ.mjs.map +1 -0
  203. package/dist/none-CAsxCOWN.cjs +49 -0
  204. package/dist/none-CAsxCOWN.cjs.map +1 -0
  205. package/dist/none-CZVrfnmF.cjs +33 -0
  206. package/dist/none-CZVrfnmF.cjs.map +1 -0
  207. package/dist/none-GhVIoh_s.mjs +33 -0
  208. package/dist/none-GhVIoh_s.mjs.map +1 -0
  209. package/dist/postgres-C8WbchFa.cjs +134 -0
  210. package/dist/postgres-C8WbchFa.cjs.map +1 -0
  211. package/dist/postgres-c3pAhmhr.mjs +123 -0
  212. package/dist/postgres-c3pAhmhr.mjs.map +1 -0
  213. package/dist/react.css +1 -0
  214. package/dist/react.js +31465 -0
  215. package/dist/receiver.cjs +43 -0
  216. package/dist/receiver.cjs.map +1 -0
  217. package/dist/receiver.d.cts +36 -0
  218. package/dist/receiver.d.mts +36 -0
  219. package/dist/receiver.mjs +40 -0
  220. package/dist/receiver.mjs.map +1 -0
  221. package/dist/redis-CFJkuSgB.cjs +270 -0
  222. package/dist/redis-CFJkuSgB.cjs.map +1 -0
  223. package/dist/redis-CvLi0KF7.mjs +254 -0
  224. package/dist/redis-CvLi0KF7.mjs.map +1 -0
  225. package/dist/roles-D0G9XqBq.cjs +128 -0
  226. package/dist/roles-D0G9XqBq.cjs.map +1 -0
  227. package/dist/roles-vp361lTk.mjs +99 -0
  228. package/dist/roles-vp361lTk.mjs.map +1 -0
  229. package/dist/schema-mo__wv4P.d.cts +233 -0
  230. package/dist/schema-mo__wv4P.d.mts +233 -0
  231. package/dist/schema.cjs +13 -0
  232. package/dist/schema.cjs.map +1 -0
  233. package/dist/schema.d.cts +2 -0
  234. package/dist/schema.d.mts +2 -0
  235. package/dist/schema.mjs +11 -0
  236. package/dist/schema.mjs.map +1 -0
  237. package/dist/signing.cjs +162 -0
  238. package/dist/signing.cjs.map +1 -0
  239. package/dist/signing.d.cts +73 -0
  240. package/dist/signing.d.mts +73 -0
  241. package/dist/signing.mjs +156 -0
  242. package/dist/signing.mjs.map +1 -0
  243. package/dist/sqlite-Cmqnrjes.mjs +67 -0
  244. package/dist/sqlite-Cmqnrjes.mjs.map +1 -0
  245. package/dist/sqlite-Dcufk0x3.cjs +78 -0
  246. package/dist/sqlite-Dcufk0x3.cjs.map +1 -0
  247. package/dist/table-Ce3Tzwqs.d.cts +11 -0
  248. package/dist/table-Ce3Tzwqs.d.mts +11 -0
  249. package/dist/testing.cjs +134 -0
  250. package/dist/testing.cjs.map +1 -0
  251. package/dist/testing.d.cts +80 -0
  252. package/dist/testing.d.mts +80 -0
  253. package/dist/testing.mjs +131 -0
  254. package/dist/testing.mjs.map +1 -0
  255. package/dist/types-react/react.d.ts +98 -0
  256. package/dist/types-react/schema.d.ts +229 -0
  257. package/dist/types-react/ui/App.d.ts +22 -0
  258. package/dist/types-react/ui/api.d.ts +97 -0
  259. package/dist/types-react/ui/components/JsonCodeEditor.d.ts +12 -0
  260. package/dist/types-react/ui/components/ThemeToggle.d.ts +2 -0
  261. package/dist/types-react/ui/components/Toast.d.ts +16 -0
  262. package/dist/types-react/ui/components/primitives.d.ts +50 -0
  263. package/dist/types-react/ui/components/ui-bits.d.ts +22 -0
  264. package/dist/types-react/ui/components/webhook-bits.d.ts +51 -0
  265. package/dist/types-react/ui/lib/format.d.ts +39 -0
  266. package/dist/types-react/ui/lib/nav-guard.d.ts +20 -0
  267. package/dist/types-react/ui/lib/utils.d.ts +3 -0
  268. package/dist/types-react/ui/theme.d.ts +12 -0
  269. package/dist/types-react/ui/types.d.ts +80 -0
  270. package/dist/types-react/ui/views/AuditView.d.ts +6 -0
  271. package/dist/types-react/ui/views/DeliveriesView.d.ts +12 -0
  272. package/dist/types-react/ui/views/EndpointsView.d.ts +11 -0
  273. package/dist/types-react/ui/views/EventTypesView.d.ts +11 -0
  274. package/dist/types-react/ui/views/MessagesView.d.ts +10 -0
  275. package/dist/types-react/ui/views/OverviewView.d.ts +12 -0
  276. package/dist/ui/assets/index-B0eoQX2U.css +1 -0
  277. package/dist/ui/assets/index-S5t_CLOe.js +209 -0
  278. package/dist/ui/index.html +14 -0
  279. package/package.json +487 -0
@@ -0,0 +1,123 @@
1
+ import { t as createFetchHandler } from "./create-fetch-handler-BIdk9P30.mjs";
2
+ import { Elysia, t } from "elysia";
3
+ //#region src/adapters/elysia.ts
4
+ /**
5
+ * Elysia adapter. Two ways to mount:
6
+ *
7
+ * 1. {@link webhooksPanel} — a web-standard handler for `Elysia.mount(path, handler)`.
8
+ * Simplest, but opaque to Eden (the typed client can't see the routes).
9
+ *
10
+ * ```ts
11
+ * new Elysia().mount("/webhooks", webhooksPanel({ basePath: "/webhooks", storage }));
12
+ * ```
13
+ *
14
+ * 2. {@link webhooksElysia} — a typed Elysia plugin that *declares* the admin routes,
15
+ * so **Eden treaty** infers them: `edenClient.webhooks.api.applications.get()`, etc.
16
+ * Each handler delegates to the same pipeline (auth/validation/logic reused).
17
+ *
18
+ * ```ts
19
+ * import { treaty } from "@elysiajs/eden";
20
+ * const app = new Elysia().use(webhooksElysia({ prefix: "/webhooks", storage }));
21
+ * const client = treaty<typeof app>("localhost:3000");
22
+ * await client.webhooks.api.applications.get();
23
+ * ```
24
+ *
25
+ * The panel starts the delivery dispatcher by default; pass `dispatcher: false`
26
+ * for split-worker deployments.
27
+ *
28
+ * @module
29
+ */
30
+ /** Create a panel handler suitable for `Elysia.mount(path, handler)`. */
31
+ function webhooksPanel(options) {
32
+ const handler = createFetchHandler(options);
33
+ const fn = ((request) => handler.fetch(request));
34
+ fn.core = handler.core;
35
+ fn.dispatcher = handler.dispatcher;
36
+ fn.openapi = handler.openapi;
37
+ return fn;
38
+ }
39
+ const appParams = t.Object({ app: t.String() });
40
+ const endpointParams = t.Object({
41
+ app: t.String(),
42
+ id: t.String()
43
+ });
44
+ const nameParams = t.Object({ name: t.String() });
45
+ /**
46
+ * Typed Elysia plugin exposing the admin API so the **Eden** client can call it
47
+ * with full path/method/param typing (`edenClient.webhooks.api.applications.get()`).
48
+ * Routes are declared for the typed surface; every handler delegates to the
49
+ * shared fetch pipeline (auth, authorization, portal scoping, error mapping
50
+ * reused). A catch-all also serves the bundled UI.
51
+ */
52
+ function webhooksElysia(options) {
53
+ const prefix = options.prefix ?? "/webhooks";
54
+ const handler = createFetchHandler({
55
+ ...options,
56
+ basePath: options.basePath ?? prefix
57
+ });
58
+ const pass = (ctx) => {
59
+ const r = ctx.request;
60
+ if (ctx.body != null && (r.method === "POST" || r.method === "PUT")) return handler.fetch(new Request(r.url, {
61
+ method: r.method,
62
+ headers: r.headers,
63
+ body: JSON.stringify(ctx.body)
64
+ }));
65
+ return handler.fetch(r);
66
+ };
67
+ const app = "/api/applications/:app";
68
+ const endpoint = `${app}/endpoints/:id`;
69
+ return new Elysia({
70
+ prefix,
71
+ name: "xtandard-webhooks"
72
+ }).get("/config", pass).get("/api/openapi.json", pass).get("/api/event-types.json", pass).get("/api/applications", pass).post("/api/applications", pass, { body: t.Object({
73
+ key: t.String(),
74
+ name: t.Optional(t.String()),
75
+ metadata: t.Optional(t.Any())
76
+ }) }).get(app, pass, { params: appParams }).put(app, pass, {
77
+ params: appParams,
78
+ body: t.Any()
79
+ }).delete(app, pass, { params: appParams }).get("/api/event-types", pass).post("/api/event-types", pass, { body: t.Object({
80
+ name: t.String(),
81
+ description: t.Optional(t.String()),
82
+ groupName: t.Optional(t.String()),
83
+ schema: t.Optional(t.Any()),
84
+ deprecated: t.Optional(t.Boolean())
85
+ }) }).get("/api/event-types/:name", pass, { params: nameParams }).put("/api/event-types/:name", pass, {
86
+ params: nameParams,
87
+ body: t.Any()
88
+ }).delete("/api/event-types/:name", pass, { params: nameParams }).get(`${app}/endpoints`, pass, { params: appParams }).post(`${app}/endpoints`, pass, {
89
+ params: appParams,
90
+ body: t.Object({
91
+ url: t.String(),
92
+ description: t.Optional(t.String()),
93
+ eventTypes: t.Optional(t.Array(t.String())),
94
+ headers: t.Optional(t.Record(t.String(), t.String())),
95
+ metadata: t.Optional(t.Any()),
96
+ disabled: t.Optional(t.Boolean())
97
+ })
98
+ }).get(endpoint, pass, { params: endpointParams }).put(endpoint, pass, {
99
+ params: endpointParams,
100
+ body: t.Any()
101
+ }).delete(endpoint, pass, { params: endpointParams }).get(`${endpoint}/secret`, pass, { params: endpointParams }).post(`${endpoint}/rotate-secret`, pass, { params: endpointParams }).post(`${endpoint}/enable`, pass, { params: endpointParams }).post(`${endpoint}/disable`, pass, { params: endpointParams }).post(`${endpoint}/test`, pass, {
102
+ params: endpointParams,
103
+ body: t.Object({
104
+ eventType: t.String(),
105
+ payload: t.Optional(t.Any())
106
+ })
107
+ }).post(`${endpoint}/recover`, pass, {
108
+ params: endpointParams,
109
+ body: t.Object({ since: t.String() })
110
+ }).get(`${app}/messages`, pass, { params: appParams }).post(`${app}/messages`, pass, {
111
+ params: appParams,
112
+ body: t.Object({
113
+ eventType: t.String(),
114
+ payload: t.Any(),
115
+ timestamp: t.Optional(t.String()),
116
+ idempotencyKey: t.Optional(t.String())
117
+ })
118
+ }).get(`${app}/messages/:id`, pass, { params: endpointParams }).get(`${app}/deliveries`, pass, { params: appParams }).get(`${app}/deliveries/:id`, pass, { params: endpointParams }).post(`${app}/deliveries/:id/retry`, pass, { params: endpointParams }).get(`${app}/audit`, pass, { params: appParams }).all("/*", pass);
119
+ }
120
+ //#endregion
121
+ export { webhooksElysia, webhooksPanel };
122
+
123
+ //# sourceMappingURL=entry-elysia.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-elysia.mjs","names":[],"sources":["../src/adapters/elysia.ts"],"sourcesContent":["/**\n * Elysia adapter. Two ways to mount:\n *\n * 1. {@link webhooksPanel} — a web-standard handler for `Elysia.mount(path, handler)`.\n * Simplest, but opaque to Eden (the typed client can't see the routes).\n *\n * ```ts\n * new Elysia().mount(\"/webhooks\", webhooksPanel({ basePath: \"/webhooks\", storage }));\n * ```\n *\n * 2. {@link webhooksElysia} — a typed Elysia plugin that *declares* the admin routes,\n * so **Eden treaty** infers them: `edenClient.webhooks.api.applications.get()`, etc.\n * Each handler delegates to the same pipeline (auth/validation/logic reused).\n *\n * ```ts\n * import { treaty } from \"@elysiajs/eden\";\n * const app = new Elysia().use(webhooksElysia({ prefix: \"/webhooks\", storage }));\n * const client = treaty<typeof app>(\"localhost:3000\");\n * await client.webhooks.api.applications.get();\n * ```\n *\n * The panel starts the delivery dispatcher by default; pass `dispatcher: false`\n * for split-worker deployments.\n *\n * @module\n */\n\nimport { Elysia, t } from \"elysia\";\nimport { createFetchHandler, type WebhooksPanelOptions } from \"../server/create-fetch-handler.ts\";\n\n/** A web-standard fetch handler with `core` + `dispatcher` + `openapi()` attached. */\nexport type ElysiaWebhooksHandler = ((request: Request) => Promise<Response>) & {\n core: ReturnType<typeof createFetchHandler>[\"core\"];\n dispatcher: ReturnType<typeof createFetchHandler>[\"dispatcher\"];\n openapi: ReturnType<typeof createFetchHandler>[\"openapi\"];\n};\n\n/** Create a panel handler suitable for `Elysia.mount(path, handler)`. */\nexport function webhooksPanel(options: WebhooksPanelOptions): ElysiaWebhooksHandler {\n const handler = createFetchHandler(options);\n const fn = ((request: Request) => handler.fetch(request)) as ElysiaWebhooksHandler;\n fn.core = handler.core;\n fn.dispatcher = handler.dispatcher;\n fn.openapi = handler.openapi;\n return fn;\n}\n\n/** Options for {@link webhooksElysia}. */\nexport interface WebhooksElysiaOptions extends WebhooksPanelOptions {\n /** Mount prefix; also used as the panel basePath. Default `\"/webhooks\"`. */\n prefix?: string;\n}\n\nconst appParams = t.Object({ app: t.String() });\nconst endpointParams = t.Object({ app: t.String(), id: t.String() });\nconst nameParams = t.Object({ name: t.String() });\n\n/**\n * Typed Elysia plugin exposing the admin API so the **Eden** client can call it\n * with full path/method/param typing (`edenClient.webhooks.api.applications.get()`).\n * Routes are declared for the typed surface; every handler delegates to the\n * shared fetch pipeline (auth, authorization, portal scoping, error mapping\n * reused). A catch-all also serves the bundled UI.\n */\nexport function webhooksElysia(options: WebhooksElysiaOptions) {\n const prefix = options.prefix ?? \"/webhooks\";\n const handler = createFetchHandler({ ...options, basePath: options.basePath ?? prefix });\n\n // Elysia parses the body for declared routes, draining the stream; rebuild the\n // Request from the parsed body before delegating (mirrors the Express adapter).\n const pass = (ctx: { request: Request; body?: unknown }): Promise<Response> => {\n const r = ctx.request;\n if (ctx.body != null && (r.method === \"POST\" || r.method === \"PUT\")) {\n return handler.fetch(\n new Request(r.url, {\n method: r.method,\n headers: r.headers,\n body: JSON.stringify(ctx.body),\n }),\n );\n }\n return handler.fetch(r);\n };\n\n const app = \"/api/applications/:app\";\n const endpoint = `${app}/endpoints/:id`;\n\n return new Elysia({ prefix, name: \"xtandard-webhooks\" })\n .get(\"/config\", pass)\n .get(\"/api/openapi.json\", pass)\n .get(\"/api/event-types.json\", pass)\n .get(\"/api/applications\", pass)\n .post(\"/api/applications\", pass, {\n body: t.Object({\n key: t.String(),\n name: t.Optional(t.String()),\n metadata: t.Optional(t.Any()),\n }),\n })\n .get(app, pass, { params: appParams })\n .put(app, pass, { params: appParams, body: t.Any() })\n .delete(app, pass, { params: appParams })\n .get(\"/api/event-types\", pass)\n .post(\"/api/event-types\", pass, {\n body: t.Object({\n name: t.String(),\n description: t.Optional(t.String()),\n groupName: t.Optional(t.String()),\n schema: t.Optional(t.Any()),\n deprecated: t.Optional(t.Boolean()),\n }),\n })\n .get(\"/api/event-types/:name\", pass, { params: nameParams })\n .put(\"/api/event-types/:name\", pass, { params: nameParams, body: t.Any() })\n .delete(\"/api/event-types/:name\", pass, { params: nameParams })\n .get(`${app}/endpoints`, pass, { params: appParams })\n .post(`${app}/endpoints`, pass, {\n params: appParams,\n body: t.Object({\n url: t.String(),\n description: t.Optional(t.String()),\n eventTypes: t.Optional(t.Array(t.String())),\n headers: t.Optional(t.Record(t.String(), t.String())),\n metadata: t.Optional(t.Any()),\n disabled: t.Optional(t.Boolean()),\n }),\n })\n .get(endpoint, pass, { params: endpointParams })\n .put(endpoint, pass, { params: endpointParams, body: t.Any() })\n .delete(endpoint, pass, { params: endpointParams })\n .get(`${endpoint}/secret`, pass, { params: endpointParams })\n .post(`${endpoint}/rotate-secret`, pass, { params: endpointParams })\n .post(`${endpoint}/enable`, pass, { params: endpointParams })\n .post(`${endpoint}/disable`, pass, { params: endpointParams })\n .post(`${endpoint}/test`, pass, {\n params: endpointParams,\n body: t.Object({ eventType: t.String(), payload: t.Optional(t.Any()) }),\n })\n .post(`${endpoint}/recover`, pass, {\n params: endpointParams,\n body: t.Object({ since: t.String() }),\n })\n .get(`${app}/messages`, pass, { params: appParams })\n .post(`${app}/messages`, pass, {\n params: appParams,\n body: t.Object({\n eventType: t.String(),\n payload: t.Any(),\n timestamp: t.Optional(t.String()),\n idempotencyKey: t.Optional(t.String()),\n }),\n })\n .get(`${app}/messages/:id`, pass, { params: endpointParams })\n .get(`${app}/deliveries`, pass, { params: appParams })\n .get(`${app}/deliveries/:id`, pass, { params: endpointParams })\n .post(`${app}/deliveries/:id/retry`, pass, { params: endpointParams })\n .get(`${app}/audit`, pass, { params: appParams })\n .all(\"/*\", pass); // bundled UI assets + SPA fallback\n}\n\nexport type { WebhooksPanelOptions };\n"],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_create_fetch_handler = require("./create-fetch-handler-CmooujQo.cjs");
3
+ //#region src/adapters/express.ts
4
+ function headersFrom(req) {
5
+ const headers = new Headers();
6
+ for (const [key, value] of Object.entries(req.headers)) {
7
+ if (value === void 0) continue;
8
+ headers.set(key, Array.isArray(value) ? value.join(", ") : value);
9
+ }
10
+ return headers;
11
+ }
12
+ async function readBody(req) {
13
+ const method = (req.method ?? "GET").toUpperCase();
14
+ if (method === "GET" || method === "HEAD") return void 0;
15
+ if (req.readableEnded) {
16
+ const body = req.body;
17
+ if (body === void 0 || body === null) return void 0;
18
+ const text = typeof body === "string" ? body : JSON.stringify(body);
19
+ return new TextEncoder().encode(text);
20
+ }
21
+ const chunks = [];
22
+ for await (const chunk of req) chunks.push(chunk);
23
+ return chunks.length ? new Uint8Array(Buffer.concat(chunks)) : void 0;
24
+ }
25
+ function toWebRequest(req, body) {
26
+ const url = `${req.protocol || "http"}://${req.get?.("host") ?? req.headers.host ?? "localhost"}${req.originalUrl ?? req.url ?? "/"}`;
27
+ return new Request(url, {
28
+ method: req.method,
29
+ headers: headersFrom(req),
30
+ body
31
+ });
32
+ }
33
+ async function writeWebResponse(res, response) {
34
+ res.status(response.status);
35
+ response.headers.forEach((value, key) => res.setHeader(key, value));
36
+ const buffer = Buffer.from(await response.arrayBuffer());
37
+ res.end(buffer);
38
+ }
39
+ /** Create an Express handler serving the panel. Use with `app.use(path, handler)`. */
40
+ function webhooksPanel(options) {
41
+ const handler = require_create_fetch_handler.createFetchHandler(options);
42
+ const middleware = (req, res, next) => {
43
+ (async () => {
44
+ const request = toWebRequest(req, await readBody(req));
45
+ await writeWebResponse(res, await handler.fetch(request));
46
+ })().catch(next);
47
+ };
48
+ return Object.assign(middleware, {
49
+ core: handler.core,
50
+ dispatcher: handler.dispatcher,
51
+ openapi: handler.openapi
52
+ });
53
+ }
54
+ //#endregion
55
+ exports.webhooksPanel = webhooksPanel;
56
+
57
+ //# sourceMappingURL=entry-express.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-express.cjs","names":["createFetchHandler"],"sources":["../src/adapters/express.ts"],"sourcesContent":["/**\n * Express adapter. Express predates the web Fetch API, so this bridges Node's\n * `req`/`res` to the web-standard handler: it builds a `Request` from the\n * incoming message, runs {@link createFetchHandler}, and writes the `Response`\n * back. No `express` import at runtime — only its types.\n *\n * Mount it BEFORE any body-parser middleware (it reads the raw request body):\n *\n * ```ts\n * import express from \"express\";\n * import { webhooksPanel } from \"@xtandard/webhooks/express\";\n * const app = express();\n * app.use(\"/webhooks\", webhooksPanel({ basePath: \"/webhooks\", storage }));\n * ```\n *\n * The panel starts the delivery dispatcher by default; pass `dispatcher: false`\n * for split-worker deployments.\n *\n * @module\n */\n\nimport type { NextFunction, Request as ExRequest, Response as ExResponse } from \"express\";\nimport { createFetchHandler, type WebhooksPanelOptions } from \"../server/create-fetch-handler.ts\";\n\n/** An Express request handler with the admin `core` + `dispatcher` + `openapi` attached. */\nexport type ExpressWebhooksHandler = ((\n req: ExRequest,\n res: ExResponse,\n next: NextFunction,\n) => void) & {\n core: ReturnType<typeof createFetchHandler>[\"core\"];\n dispatcher: ReturnType<typeof createFetchHandler>[\"dispatcher\"];\n openapi: ReturnType<typeof createFetchHandler>[\"openapi\"];\n};\n\nfunction headersFrom(req: ExRequest): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n headers.set(key, Array.isArray(value) ? value.join(\", \") : value);\n }\n return headers;\n}\n\nasync function readBody(req: ExRequest): Promise<Uint8Array | undefined> {\n const method = (req.method ?? \"GET\").toUpperCase();\n if (method === \"GET\" || method === \"HEAD\") return undefined;\n\n // If an upstream body parser already consumed the stream, re-serialize req.body.\n if (req.readableEnded) {\n const body = (req as { body?: unknown }).body;\n if (body === undefined || body === null) return undefined;\n const text = typeof body === \"string\" ? body : JSON.stringify(body);\n return new TextEncoder().encode(text);\n }\n\n const chunks: Buffer[] = [];\n for await (const chunk of req as AsyncIterable<Buffer>) chunks.push(chunk);\n return chunks.length ? new Uint8Array(Buffer.concat(chunks)) : undefined;\n}\n\nfunction toWebRequest(req: ExRequest, body: Uint8Array | undefined): Request {\n const protocol = req.protocol || \"http\";\n const host = req.get?.(\"host\") ?? req.headers.host ?? \"localhost\";\n // originalUrl preserves the mount prefix (e.g. /webhooks/api/...) and query string.\n const url = `${protocol}://${host}${req.originalUrl ?? req.url ?? \"/\"}`;\n return new Request(url, {\n method: req.method,\n headers: headersFrom(req),\n // Uint8Array is a valid BodyInit; the cast satisfies TS 5.7's generic typing.\n body: body as BodyInit | undefined,\n });\n}\n\nasync function writeWebResponse(res: ExResponse, response: Response): Promise<void> {\n res.status(response.status);\n response.headers.forEach((value, key) => res.setHeader(key, value));\n const buffer = Buffer.from(await response.arrayBuffer());\n res.end(buffer);\n}\n\n/** Create an Express handler serving the panel. Use with `app.use(path, handler)`. */\nexport function webhooksPanel(options: WebhooksPanelOptions): ExpressWebhooksHandler {\n const handler = createFetchHandler(options);\n\n const middleware = (req: ExRequest, res: ExResponse, next: NextFunction): void => {\n (async () => {\n const body = await readBody(req);\n const request = toWebRequest(req, body);\n const response = await handler.fetch(request);\n await writeWebResponse(res, response);\n })().catch(next);\n };\n\n return Object.assign(middleware, {\n core: handler.core,\n dispatcher: handler.dispatcher,\n openapi: handler.openapi,\n });\n}\n\nexport type { WebhooksPanelOptions };\n"],"mappings":";;;AAmCA,SAAS,YAAY,KAAyB;CAC5C,MAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,OAAO,GAAG;EACtD,IAAI,UAAU,KAAA,GAAW;EACzB,QAAQ,IAAI,KAAK,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK;CAClE;CACA,OAAO;AACT;AAEA,eAAe,SAAS,KAAiD;CACvE,MAAM,UAAU,IAAI,UAAU,OAAO,YAAY;CACjD,IAAI,WAAW,SAAS,WAAW,QAAQ,OAAO,KAAA;CAGlD,IAAI,IAAI,eAAe;EACrB,MAAM,OAAQ,IAA2B;EACzC,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM,OAAO,KAAA;EAChD,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,IAAI;EAClE,OAAO,IAAI,YAAY,EAAE,OAAO,IAAI;CACtC;CAEA,MAAM,SAAmB,CAAC;CAC1B,WAAW,MAAM,SAAS,KAA8B,OAAO,KAAK,KAAK;CACzE,OAAO,OAAO,SAAS,IAAI,WAAW,OAAO,OAAO,MAAM,CAAC,IAAI,KAAA;AACjE;AAEA,SAAS,aAAa,KAAgB,MAAuC;CAI3E,MAAM,MAAM,GAHK,IAAI,YAAY,OAGT,KAFX,IAAI,MAAM,MAAM,KAAK,IAAI,QAAQ,QAAQ,cAElB,IAAI,eAAe,IAAI,OAAO;CAClE,OAAO,IAAI,QAAQ,KAAK;EACtB,QAAQ,IAAI;EACZ,SAAS,YAAY,GAAG;EAElB;CACR,CAAC;AACH;AAEA,eAAe,iBAAiB,KAAiB,UAAmC;CAClF,IAAI,OAAO,SAAS,MAAM;CAC1B,SAAS,QAAQ,SAAS,OAAO,QAAQ,IAAI,UAAU,KAAK,KAAK,CAAC;CAClE,MAAM,SAAS,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;CACvD,IAAI,IAAI,MAAM;AAChB;;AAGA,SAAgB,cAAc,SAAuD;CACnF,MAAM,UAAUA,6BAAAA,mBAAmB,OAAO;CAE1C,MAAM,cAAc,KAAgB,KAAiB,SAA6B;EAChF,CAAC,YAAY;GAEX,MAAM,UAAU,aAAa,KAAK,MADf,SAAS,GAAG,CACO;GAEtC,MAAM,iBAAiB,KAAK,MADL,QAAQ,MAAM,OAAO,CACR;EACtC,GAAG,EAAE,MAAM,IAAI;CACjB;CAEA,OAAO,OAAO,OAAO,YAAY;EAC/B,MAAM,QAAQ;EACd,YAAY,QAAQ;EACpB,SAAS,QAAQ;CACnB,CAAC;AACH"}
@@ -0,0 +1,15 @@
1
+ import { n as WebhooksPanelOptions, r as createFetchHandler } from "./create-fetch-handler-Dlkhustu.cjs";
2
+ import { NextFunction, Request, Response } from "express";
3
+
4
+ //#region src/adapters/express.d.ts
5
+ /** An Express request handler with the admin `core` + `dispatcher` + `openapi` attached. */
6
+ type ExpressWebhooksHandler = ((req: Request, res: Response, next: NextFunction) => void) & {
7
+ core: ReturnType<typeof createFetchHandler>["core"];
8
+ dispatcher: ReturnType<typeof createFetchHandler>["dispatcher"];
9
+ openapi: ReturnType<typeof createFetchHandler>["openapi"];
10
+ };
11
+ /** Create an Express handler serving the panel. Use with `app.use(path, handler)`. */
12
+ declare function webhooksPanel(options: WebhooksPanelOptions): ExpressWebhooksHandler;
13
+ //#endregion
14
+ export { ExpressWebhooksHandler, type WebhooksPanelOptions, webhooksPanel };
15
+ //# sourceMappingURL=entry-express.d.cts.map
@@ -0,0 +1,15 @@
1
+ import { n as WebhooksPanelOptions, r as createFetchHandler } from "./create-fetch-handler-jy3hy5nZ.mjs";
2
+ import { NextFunction, Request, Response } from "express";
3
+
4
+ //#region src/adapters/express.d.ts
5
+ /** An Express request handler with the admin `core` + `dispatcher` + `openapi` attached. */
6
+ type ExpressWebhooksHandler = ((req: Request, res: Response, next: NextFunction) => void) & {
7
+ core: ReturnType<typeof createFetchHandler>["core"];
8
+ dispatcher: ReturnType<typeof createFetchHandler>["dispatcher"];
9
+ openapi: ReturnType<typeof createFetchHandler>["openapi"];
10
+ };
11
+ /** Create an Express handler serving the panel. Use with `app.use(path, handler)`. */
12
+ declare function webhooksPanel(options: WebhooksPanelOptions): ExpressWebhooksHandler;
13
+ //#endregion
14
+ export { ExpressWebhooksHandler, type WebhooksPanelOptions, webhooksPanel };
15
+ //# sourceMappingURL=entry-express.d.mts.map
@@ -0,0 +1,56 @@
1
+ import { t as createFetchHandler } from "./create-fetch-handler-BIdk9P30.mjs";
2
+ //#region src/adapters/express.ts
3
+ function headersFrom(req) {
4
+ const headers = new Headers();
5
+ for (const [key, value] of Object.entries(req.headers)) {
6
+ if (value === void 0) continue;
7
+ headers.set(key, Array.isArray(value) ? value.join(", ") : value);
8
+ }
9
+ return headers;
10
+ }
11
+ async function readBody(req) {
12
+ const method = (req.method ?? "GET").toUpperCase();
13
+ if (method === "GET" || method === "HEAD") return void 0;
14
+ if (req.readableEnded) {
15
+ const body = req.body;
16
+ if (body === void 0 || body === null) return void 0;
17
+ const text = typeof body === "string" ? body : JSON.stringify(body);
18
+ return new TextEncoder().encode(text);
19
+ }
20
+ const chunks = [];
21
+ for await (const chunk of req) chunks.push(chunk);
22
+ return chunks.length ? new Uint8Array(Buffer.concat(chunks)) : void 0;
23
+ }
24
+ function toWebRequest(req, body) {
25
+ const url = `${req.protocol || "http"}://${req.get?.("host") ?? req.headers.host ?? "localhost"}${req.originalUrl ?? req.url ?? "/"}`;
26
+ return new Request(url, {
27
+ method: req.method,
28
+ headers: headersFrom(req),
29
+ body
30
+ });
31
+ }
32
+ async function writeWebResponse(res, response) {
33
+ res.status(response.status);
34
+ response.headers.forEach((value, key) => res.setHeader(key, value));
35
+ const buffer = Buffer.from(await response.arrayBuffer());
36
+ res.end(buffer);
37
+ }
38
+ /** Create an Express handler serving the panel. Use with `app.use(path, handler)`. */
39
+ function webhooksPanel(options) {
40
+ const handler = createFetchHandler(options);
41
+ const middleware = (req, res, next) => {
42
+ (async () => {
43
+ const request = toWebRequest(req, await readBody(req));
44
+ await writeWebResponse(res, await handler.fetch(request));
45
+ })().catch(next);
46
+ };
47
+ return Object.assign(middleware, {
48
+ core: handler.core,
49
+ dispatcher: handler.dispatcher,
50
+ openapi: handler.openapi
51
+ });
52
+ }
53
+ //#endregion
54
+ export { webhooksPanel };
55
+
56
+ //# sourceMappingURL=entry-express.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-express.mjs","names":[],"sources":["../src/adapters/express.ts"],"sourcesContent":["/**\n * Express adapter. Express predates the web Fetch API, so this bridges Node's\n * `req`/`res` to the web-standard handler: it builds a `Request` from the\n * incoming message, runs {@link createFetchHandler}, and writes the `Response`\n * back. No `express` import at runtime — only its types.\n *\n * Mount it BEFORE any body-parser middleware (it reads the raw request body):\n *\n * ```ts\n * import express from \"express\";\n * import { webhooksPanel } from \"@xtandard/webhooks/express\";\n * const app = express();\n * app.use(\"/webhooks\", webhooksPanel({ basePath: \"/webhooks\", storage }));\n * ```\n *\n * The panel starts the delivery dispatcher by default; pass `dispatcher: false`\n * for split-worker deployments.\n *\n * @module\n */\n\nimport type { NextFunction, Request as ExRequest, Response as ExResponse } from \"express\";\nimport { createFetchHandler, type WebhooksPanelOptions } from \"../server/create-fetch-handler.ts\";\n\n/** An Express request handler with the admin `core` + `dispatcher` + `openapi` attached. */\nexport type ExpressWebhooksHandler = ((\n req: ExRequest,\n res: ExResponse,\n next: NextFunction,\n) => void) & {\n core: ReturnType<typeof createFetchHandler>[\"core\"];\n dispatcher: ReturnType<typeof createFetchHandler>[\"dispatcher\"];\n openapi: ReturnType<typeof createFetchHandler>[\"openapi\"];\n};\n\nfunction headersFrom(req: ExRequest): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n headers.set(key, Array.isArray(value) ? value.join(\", \") : value);\n }\n return headers;\n}\n\nasync function readBody(req: ExRequest): Promise<Uint8Array | undefined> {\n const method = (req.method ?? \"GET\").toUpperCase();\n if (method === \"GET\" || method === \"HEAD\") return undefined;\n\n // If an upstream body parser already consumed the stream, re-serialize req.body.\n if (req.readableEnded) {\n const body = (req as { body?: unknown }).body;\n if (body === undefined || body === null) return undefined;\n const text = typeof body === \"string\" ? body : JSON.stringify(body);\n return new TextEncoder().encode(text);\n }\n\n const chunks: Buffer[] = [];\n for await (const chunk of req as AsyncIterable<Buffer>) chunks.push(chunk);\n return chunks.length ? new Uint8Array(Buffer.concat(chunks)) : undefined;\n}\n\nfunction toWebRequest(req: ExRequest, body: Uint8Array | undefined): Request {\n const protocol = req.protocol || \"http\";\n const host = req.get?.(\"host\") ?? req.headers.host ?? \"localhost\";\n // originalUrl preserves the mount prefix (e.g. /webhooks/api/...) and query string.\n const url = `${protocol}://${host}${req.originalUrl ?? req.url ?? \"/\"}`;\n return new Request(url, {\n method: req.method,\n headers: headersFrom(req),\n // Uint8Array is a valid BodyInit; the cast satisfies TS 5.7's generic typing.\n body: body as BodyInit | undefined,\n });\n}\n\nasync function writeWebResponse(res: ExResponse, response: Response): Promise<void> {\n res.status(response.status);\n response.headers.forEach((value, key) => res.setHeader(key, value));\n const buffer = Buffer.from(await response.arrayBuffer());\n res.end(buffer);\n}\n\n/** Create an Express handler serving the panel. Use with `app.use(path, handler)`. */\nexport function webhooksPanel(options: WebhooksPanelOptions): ExpressWebhooksHandler {\n const handler = createFetchHandler(options);\n\n const middleware = (req: ExRequest, res: ExResponse, next: NextFunction): void => {\n (async () => {\n const body = await readBody(req);\n const request = toWebRequest(req, body);\n const response = await handler.fetch(request);\n await writeWebResponse(res, response);\n })().catch(next);\n };\n\n return Object.assign(middleware, {\n core: handler.core,\n dispatcher: handler.dispatcher,\n openapi: handler.openapi,\n });\n}\n\nexport type { WebhooksPanelOptions };\n"],"mappings":";;AAmCA,SAAS,YAAY,KAAyB;CAC5C,MAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,OAAO,GAAG;EACtD,IAAI,UAAU,KAAA,GAAW;EACzB,QAAQ,IAAI,KAAK,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK;CAClE;CACA,OAAO;AACT;AAEA,eAAe,SAAS,KAAiD;CACvE,MAAM,UAAU,IAAI,UAAU,OAAO,YAAY;CACjD,IAAI,WAAW,SAAS,WAAW,QAAQ,OAAO,KAAA;CAGlD,IAAI,IAAI,eAAe;EACrB,MAAM,OAAQ,IAA2B;EACzC,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM,OAAO,KAAA;EAChD,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,IAAI;EAClE,OAAO,IAAI,YAAY,EAAE,OAAO,IAAI;CACtC;CAEA,MAAM,SAAmB,CAAC;CAC1B,WAAW,MAAM,SAAS,KAA8B,OAAO,KAAK,KAAK;CACzE,OAAO,OAAO,SAAS,IAAI,WAAW,OAAO,OAAO,MAAM,CAAC,IAAI,KAAA;AACjE;AAEA,SAAS,aAAa,KAAgB,MAAuC;CAI3E,MAAM,MAAM,GAHK,IAAI,YAAY,OAGT,KAFX,IAAI,MAAM,MAAM,KAAK,IAAI,QAAQ,QAAQ,cAElB,IAAI,eAAe,IAAI,OAAO;CAClE,OAAO,IAAI,QAAQ,KAAK;EACtB,QAAQ,IAAI;EACZ,SAAS,YAAY,GAAG;EAElB;CACR,CAAC;AACH;AAEA,eAAe,iBAAiB,KAAiB,UAAmC;CAClF,IAAI,OAAO,SAAS,MAAM;CAC1B,SAAS,QAAQ,SAAS,OAAO,QAAQ,IAAI,UAAU,KAAK,KAAK,CAAC;CAClE,MAAM,SAAS,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;CACvD,IAAI,IAAI,MAAM;AAChB;;AAGA,SAAgB,cAAc,SAAuD;CACnF,MAAM,UAAU,mBAAmB,OAAO;CAE1C,MAAM,cAAc,KAAgB,KAAiB,SAA6B;EAChF,CAAC,YAAY;GAEX,MAAM,UAAU,aAAa,KAAK,MADf,SAAS,GAAG,CACO;GAEtC,MAAM,iBAAiB,KAAK,MADL,QAAQ,MAAM,OAAO,CACR;EACtC,GAAG,EAAE,MAAM,IAAI;CACjB;CAEA,OAAO,OAAO,OAAO,YAAY;EAC/B,MAAM,QAAQ;EACd,YAAY,QAAQ;EACpB,SAAS,QAAQ;CACnB,CAAC;AACH"}
@@ -0,0 +1,35 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_create_fetch_handler = require("./create-fetch-handler-CmooujQo.cjs");
3
+ let hono = require("hono");
4
+ //#region src/adapters/hono.ts
5
+ /**
6
+ * Hono adapter. Returns a `Hono` instance whose catch-all delegates to the
7
+ * web-standard panel handler, so it composes via `app.route(path, panel)`.
8
+ * The panel starts the delivery dispatcher by default; pass `dispatcher: false`
9
+ * for split-worker deployments.
10
+ *
11
+ * ```ts
12
+ * import { webhooksPanel } from "@xtandard/webhooks/hono";
13
+ * app.route("/webhooks", webhooksPanel({ basePath: "/webhooks", storage }));
14
+ * ```
15
+ *
16
+ * @module
17
+ */
18
+ /**
19
+ * Create a Hono sub-app serving the panel. The admin `core`, the started
20
+ * `dispatcher` (or `null`), and the `openapi()` document builder are attached.
21
+ */
22
+ function webhooksPanel(options) {
23
+ const handler = require_create_fetch_handler.createFetchHandler(options);
24
+ const app = new hono.Hono();
25
+ app.all("*", (c) => handler.fetch(c.req.raw));
26
+ return Object.assign(app, {
27
+ core: handler.core,
28
+ dispatcher: handler.dispatcher,
29
+ openapi: handler.openapi
30
+ });
31
+ }
32
+ //#endregion
33
+ exports.webhooksPanel = webhooksPanel;
34
+
35
+ //# sourceMappingURL=entry-hono.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-hono.cjs","names":["createFetchHandler","Hono"],"sources":["../src/adapters/hono.ts"],"sourcesContent":["/**\n * Hono adapter. Returns a `Hono` instance whose catch-all delegates to the\n * web-standard panel handler, so it composes via `app.route(path, panel)`.\n * The panel starts the delivery dispatcher by default; pass `dispatcher: false`\n * for split-worker deployments.\n *\n * ```ts\n * import { webhooksPanel } from \"@xtandard/webhooks/hono\";\n * app.route(\"/webhooks\", webhooksPanel({ basePath: \"/webhooks\", storage }));\n * ```\n *\n * @module\n */\n\nimport { Hono } from \"hono\";\nimport { createFetchHandler, type WebhooksPanelOptions } from \"../server/create-fetch-handler.ts\";\n\n/**\n * Create a Hono sub-app serving the panel. The admin `core`, the started\n * `dispatcher` (or `null`), and the `openapi()` document builder are attached.\n */\nexport function webhooksPanel(options: WebhooksPanelOptions): Hono & {\n core: ReturnType<typeof createFetchHandler>[\"core\"];\n dispatcher: ReturnType<typeof createFetchHandler>[\"dispatcher\"];\n openapi: ReturnType<typeof createFetchHandler>[\"openapi\"];\n} {\n const handler = createFetchHandler(options);\n const app = new Hono();\n app.all(\"*\", (c) => handler.fetch(c.req.raw));\n return Object.assign(app, {\n core: handler.core,\n dispatcher: handler.dispatcher,\n openapi: handler.openapi,\n });\n}\n\nexport type { WebhooksPanelOptions };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cAAc,SAI5B;CACA,MAAM,UAAUA,6BAAAA,mBAAmB,OAAO;CAC1C,MAAM,MAAM,IAAIC,KAAAA,KAAK;CACrB,IAAI,IAAI,MAAM,MAAM,QAAQ,MAAM,EAAE,IAAI,GAAG,CAAC;CAC5C,OAAO,OAAO,OAAO,KAAK;EACxB,MAAM,QAAQ;EACd,YAAY,QAAQ;EACpB,SAAS,QAAQ;CACnB,CAAC;AACH"}
@@ -0,0 +1,16 @@
1
+ import { n as WebhooksPanelOptions, r as createFetchHandler } from "./create-fetch-handler-Dlkhustu.cjs";
2
+ import { Hono } from "hono";
3
+
4
+ //#region src/adapters/hono.d.ts
5
+ /**
6
+ * Create a Hono sub-app serving the panel. The admin `core`, the started
7
+ * `dispatcher` (or `null`), and the `openapi()` document builder are attached.
8
+ */
9
+ declare function webhooksPanel(options: WebhooksPanelOptions): Hono & {
10
+ core: ReturnType<typeof createFetchHandler>["core"];
11
+ dispatcher: ReturnType<typeof createFetchHandler>["dispatcher"];
12
+ openapi: ReturnType<typeof createFetchHandler>["openapi"];
13
+ };
14
+ //#endregion
15
+ export { type WebhooksPanelOptions, webhooksPanel };
16
+ //# sourceMappingURL=entry-hono.d.cts.map
@@ -0,0 +1,16 @@
1
+ import { n as WebhooksPanelOptions, r as createFetchHandler } from "./create-fetch-handler-jy3hy5nZ.mjs";
2
+ import { Hono } from "hono";
3
+
4
+ //#region src/adapters/hono.d.ts
5
+ /**
6
+ * Create a Hono sub-app serving the panel. The admin `core`, the started
7
+ * `dispatcher` (or `null`), and the `openapi()` document builder are attached.
8
+ */
9
+ declare function webhooksPanel(options: WebhooksPanelOptions): Hono & {
10
+ core: ReturnType<typeof createFetchHandler>["core"];
11
+ dispatcher: ReturnType<typeof createFetchHandler>["dispatcher"];
12
+ openapi: ReturnType<typeof createFetchHandler>["openapi"];
13
+ };
14
+ //#endregion
15
+ export { type WebhooksPanelOptions, webhooksPanel };
16
+ //# sourceMappingURL=entry-hono.d.mts.map
@@ -0,0 +1,34 @@
1
+ import { t as createFetchHandler } from "./create-fetch-handler-BIdk9P30.mjs";
2
+ import { Hono } from "hono";
3
+ //#region src/adapters/hono.ts
4
+ /**
5
+ * Hono adapter. Returns a `Hono` instance whose catch-all delegates to the
6
+ * web-standard panel handler, so it composes via `app.route(path, panel)`.
7
+ * The panel starts the delivery dispatcher by default; pass `dispatcher: false`
8
+ * for split-worker deployments.
9
+ *
10
+ * ```ts
11
+ * import { webhooksPanel } from "@xtandard/webhooks/hono";
12
+ * app.route("/webhooks", webhooksPanel({ basePath: "/webhooks", storage }));
13
+ * ```
14
+ *
15
+ * @module
16
+ */
17
+ /**
18
+ * Create a Hono sub-app serving the panel. The admin `core`, the started
19
+ * `dispatcher` (or `null`), and the `openapi()` document builder are attached.
20
+ */
21
+ function webhooksPanel(options) {
22
+ const handler = createFetchHandler(options);
23
+ const app = new Hono();
24
+ app.all("*", (c) => handler.fetch(c.req.raw));
25
+ return Object.assign(app, {
26
+ core: handler.core,
27
+ dispatcher: handler.dispatcher,
28
+ openapi: handler.openapi
29
+ });
30
+ }
31
+ //#endregion
32
+ export { webhooksPanel };
33
+
34
+ //# sourceMappingURL=entry-hono.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-hono.mjs","names":[],"sources":["../src/adapters/hono.ts"],"sourcesContent":["/**\n * Hono adapter. Returns a `Hono` instance whose catch-all delegates to the\n * web-standard panel handler, so it composes via `app.route(path, panel)`.\n * The panel starts the delivery dispatcher by default; pass `dispatcher: false`\n * for split-worker deployments.\n *\n * ```ts\n * import { webhooksPanel } from \"@xtandard/webhooks/hono\";\n * app.route(\"/webhooks\", webhooksPanel({ basePath: \"/webhooks\", storage }));\n * ```\n *\n * @module\n */\n\nimport { Hono } from \"hono\";\nimport { createFetchHandler, type WebhooksPanelOptions } from \"../server/create-fetch-handler.ts\";\n\n/**\n * Create a Hono sub-app serving the panel. The admin `core`, the started\n * `dispatcher` (or `null`), and the `openapi()` document builder are attached.\n */\nexport function webhooksPanel(options: WebhooksPanelOptions): Hono & {\n core: ReturnType<typeof createFetchHandler>[\"core\"];\n dispatcher: ReturnType<typeof createFetchHandler>[\"dispatcher\"];\n openapi: ReturnType<typeof createFetchHandler>[\"openapi\"];\n} {\n const handler = createFetchHandler(options);\n const app = new Hono();\n app.all(\"*\", (c) => handler.fetch(c.req.raw));\n return Object.assign(app, {\n core: handler.core,\n dispatcher: handler.dispatcher,\n openapi: handler.openapi,\n });\n}\n\nexport type { WebhooksPanelOptions };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cAAc,SAI5B;CACA,MAAM,UAAU,mBAAmB,OAAO;CAC1C,MAAM,MAAM,IAAI,KAAK;CACrB,IAAI,IAAI,MAAM,MAAM,QAAQ,MAAM,EAAE,IAAI,GAAG,CAAC;CAC5C,OAAO,OAAO,OAAO,KAAK;EACxB,MAAM,QAAQ;EACd,YAAY,QAAQ;EACpB,SAAS,QAAQ;CACnB,CAAC;AACH"}
@@ -0,0 +1,22 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/hooks/log.ts
3
+ const defaultFormat = (phase, event) => `[@xtandard/webhooks] ${phase} ${event.type} ${JSON.stringify(event)}`;
4
+ /**
5
+ * Build a hook that logs each mutation event. Never throws from `before`, so it
6
+ * never denies a mutation — it is a pure observer.
7
+ */
8
+ function createLogHook(options = {}) {
9
+ const log = options.log ?? ((line) => console.log(line));
10
+ const format = options.format ?? defaultFormat;
11
+ const hook = { after(event) {
12
+ log(format("after", event));
13
+ } };
14
+ if (options.includeBefore) hook.before = (event) => {
15
+ log(format("before", event));
16
+ };
17
+ return hook;
18
+ }
19
+ //#endregion
20
+ exports.createLogHook = createLogHook;
21
+
22
+ //# sourceMappingURL=entry-hooks-log.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-hooks-log.cjs","names":[],"sources":["../src/hooks/log.ts"],"sourcesContent":["/**\n * `@xtandard/webhooks/hooks/log` — a reference hook that logs mutation events.\n *\n * The simplest possible consumer of the hooks seam: useful as a starting point\n * for your own `after` side effects, and handy for local debugging or piping\n * admin activity to a log aggregator. Zero dependencies.\n *\n * @example\n * ```ts\n * import { createWebhooksCore } from \"@xtandard/webhooks\";\n * import { createLogHook } from \"@xtandard/webhooks/hooks/log\";\n *\n * createWebhooksCore({ storage, hooks: createLogHook() });\n * ```\n *\n * @module\n */\n\nimport type { AfterEvent, BeforeEvent, WebhooksHooks } from \"./contract.ts\";\n\n/** Options for {@link createLogHook}. */\nexport interface LogHookOptions {\n /** Sink for each formatted line. Default: `console.log`. */\n log?: (line: string) => void;\n /** Also log `before` events (default `false` — `after` only). */\n includeBefore?: boolean;\n /**\n * Format a line for an event. Default: a compact\n * `[@xtandard/webhooks] <phase> <type>` prefix + JSON payload.\n */\n format?: (phase: \"before\" | \"after\", event: BeforeEvent | AfterEvent) => string;\n}\n\nconst defaultFormat = (phase: \"before\" | \"after\", event: BeforeEvent | AfterEvent): string =>\n `[@xtandard/webhooks] ${phase} ${event.type} ${JSON.stringify(event)}`;\n\n/**\n * Build a hook that logs each mutation event. Never throws from `before`, so it\n * never denies a mutation — it is a pure observer.\n */\nexport function createLogHook(options: LogHookOptions = {}): WebhooksHooks {\n const log = options.log ?? ((line: string) => console.log(line));\n const format = options.format ?? defaultFormat;\n const hook: WebhooksHooks = {\n after(event) {\n log(format(\"after\", event));\n },\n };\n if (options.includeBefore) {\n hook.before = (event) => {\n log(format(\"before\", event));\n };\n }\n return hook;\n}\n"],"mappings":";;AAiCA,MAAM,iBAAiB,OAA2B,UAChD,wBAAwB,MAAM,GAAG,MAAM,KAAK,GAAG,KAAK,UAAU,KAAK;;;;;AAMrE,SAAgB,cAAc,UAA0B,CAAC,GAAkB;CACzE,MAAM,MAAM,QAAQ,SAAS,SAAiB,QAAQ,IAAI,IAAI;CAC9D,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,OAAsB,EAC1B,MAAM,OAAO;EACX,IAAI,OAAO,SAAS,KAAK,CAAC;CAC5B,EACF;CACA,IAAI,QAAQ,eACV,KAAK,UAAU,UAAU;EACvB,IAAI,OAAO,UAAU,KAAK,CAAC;CAC7B;CAEF,OAAO;AACT"}
@@ -0,0 +1,23 @@
1
+ import { r as BeforeEvent, s as WebhooksHooks, t as AfterEvent } from "./contract-Bnb3fgRJ.cjs";
2
+
3
+ //#region src/hooks/log.d.ts
4
+ /** Options for {@link createLogHook}. */
5
+ interface LogHookOptions {
6
+ /** Sink for each formatted line. Default: `console.log`. */
7
+ log?: (line: string) => void;
8
+ /** Also log `before` events (default `false` — `after` only). */
9
+ includeBefore?: boolean;
10
+ /**
11
+ * Format a line for an event. Default: a compact
12
+ * `[@xtandard/webhooks] <phase> <type>` prefix + JSON payload.
13
+ */
14
+ format?: (phase: "before" | "after", event: BeforeEvent | AfterEvent) => string;
15
+ }
16
+ /**
17
+ * Build a hook that logs each mutation event. Never throws from `before`, so it
18
+ * never denies a mutation — it is a pure observer.
19
+ */
20
+ declare function createLogHook(options?: LogHookOptions): WebhooksHooks;
21
+ //#endregion
22
+ export { LogHookOptions, createLogHook };
23
+ //# sourceMappingURL=entry-hooks-log.d.cts.map
@@ -0,0 +1,23 @@
1
+ import { r as BeforeEvent, s as WebhooksHooks, t as AfterEvent } from "./contract-T1kcZNdG.mjs";
2
+
3
+ //#region src/hooks/log.d.ts
4
+ /** Options for {@link createLogHook}. */
5
+ interface LogHookOptions {
6
+ /** Sink for each formatted line. Default: `console.log`. */
7
+ log?: (line: string) => void;
8
+ /** Also log `before` events (default `false` — `after` only). */
9
+ includeBefore?: boolean;
10
+ /**
11
+ * Format a line for an event. Default: a compact
12
+ * `[@xtandard/webhooks] <phase> <type>` prefix + JSON payload.
13
+ */
14
+ format?: (phase: "before" | "after", event: BeforeEvent | AfterEvent) => string;
15
+ }
16
+ /**
17
+ * Build a hook that logs each mutation event. Never throws from `before`, so it
18
+ * never denies a mutation — it is a pure observer.
19
+ */
20
+ declare function createLogHook(options?: LogHookOptions): WebhooksHooks;
21
+ //#endregion
22
+ export { LogHookOptions, createLogHook };
23
+ //# sourceMappingURL=entry-hooks-log.d.mts.map
@@ -0,0 +1,21 @@
1
+ //#region src/hooks/log.ts
2
+ const defaultFormat = (phase, event) => `[@xtandard/webhooks] ${phase} ${event.type} ${JSON.stringify(event)}`;
3
+ /**
4
+ * Build a hook that logs each mutation event. Never throws from `before`, so it
5
+ * never denies a mutation — it is a pure observer.
6
+ */
7
+ function createLogHook(options = {}) {
8
+ const log = options.log ?? ((line) => console.log(line));
9
+ const format = options.format ?? defaultFormat;
10
+ const hook = { after(event) {
11
+ log(format("after", event));
12
+ } };
13
+ if (options.includeBefore) hook.before = (event) => {
14
+ log(format("before", event));
15
+ };
16
+ return hook;
17
+ }
18
+ //#endregion
19
+ export { createLogHook };
20
+
21
+ //# sourceMappingURL=entry-hooks-log.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-hooks-log.mjs","names":[],"sources":["../src/hooks/log.ts"],"sourcesContent":["/**\n * `@xtandard/webhooks/hooks/log` — a reference hook that logs mutation events.\n *\n * The simplest possible consumer of the hooks seam: useful as a starting point\n * for your own `after` side effects, and handy for local debugging or piping\n * admin activity to a log aggregator. Zero dependencies.\n *\n * @example\n * ```ts\n * import { createWebhooksCore } from \"@xtandard/webhooks\";\n * import { createLogHook } from \"@xtandard/webhooks/hooks/log\";\n *\n * createWebhooksCore({ storage, hooks: createLogHook() });\n * ```\n *\n * @module\n */\n\nimport type { AfterEvent, BeforeEvent, WebhooksHooks } from \"./contract.ts\";\n\n/** Options for {@link createLogHook}. */\nexport interface LogHookOptions {\n /** Sink for each formatted line. Default: `console.log`. */\n log?: (line: string) => void;\n /** Also log `before` events (default `false` — `after` only). */\n includeBefore?: boolean;\n /**\n * Format a line for an event. Default: a compact\n * `[@xtandard/webhooks] <phase> <type>` prefix + JSON payload.\n */\n format?: (phase: \"before\" | \"after\", event: BeforeEvent | AfterEvent) => string;\n}\n\nconst defaultFormat = (phase: \"before\" | \"after\", event: BeforeEvent | AfterEvent): string =>\n `[@xtandard/webhooks] ${phase} ${event.type} ${JSON.stringify(event)}`;\n\n/**\n * Build a hook that logs each mutation event. Never throws from `before`, so it\n * never denies a mutation — it is a pure observer.\n */\nexport function createLogHook(options: LogHookOptions = {}): WebhooksHooks {\n const log = options.log ?? ((line: string) => console.log(line));\n const format = options.format ?? defaultFormat;\n const hook: WebhooksHooks = {\n after(event) {\n log(format(\"after\", event));\n },\n };\n if (options.includeBefore) {\n hook.before = (event) => {\n log(format(\"before\", event));\n };\n }\n return hook;\n}\n"],"mappings":";AAiCA,MAAM,iBAAiB,OAA2B,UAChD,wBAAwB,MAAM,GAAG,MAAM,KAAK,GAAG,KAAK,UAAU,KAAK;;;;;AAMrE,SAAgB,cAAc,UAA0B,CAAC,GAAkB;CACzE,MAAM,MAAM,QAAQ,SAAS,SAAiB,QAAQ,IAAI,IAAI;CAC9D,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,OAAsB,EAC1B,MAAM,OAAO;EACX,IAAI,OAAO,SAAS,KAAK,CAAC;CAC5B,EACF;CACA,IAAI,QAAQ,eACV,KAAK,UAAU,UAAU;EACvB,IAAI,OAAO,UAAU,KAAK,CAAC;CAC7B;CAEF,OAAO;AACT"}
@@ -0,0 +1,47 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/storage/cloudflare-kv.ts
3
+ /**
4
+ * Create a Cloudflare KV–backed {@link WebhooksStorage} from a `KVNamespace` binding.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { createCloudflareKvStorage } from "@xtandard/webhooks/storage/cloudflare-kv";
9
+ * const storage = createCloudflareKvStorage({ namespace: env.WEBHOOKS });
10
+ * ```
11
+ */
12
+ function createCloudflareKvStorage(options) {
13
+ const { namespace } = options;
14
+ const fullPrefix = options.prefix ? `${options.prefix}:` : "";
15
+ const toKey = (key) => `${fullPrefix}${key}`;
16
+ const fromKey = (key) => fullPrefix && key.startsWith(fullPrefix) ? key.slice(fullPrefix.length) : key;
17
+ return {
18
+ async getItem(key) {
19
+ const raw = await namespace.get(toKey(key), "text");
20
+ return raw === null ? null : JSON.parse(raw);
21
+ },
22
+ async setItem(key, value) {
23
+ await namespace.put(toKey(key), JSON.stringify(value));
24
+ },
25
+ async removeItem(key) {
26
+ await namespace.delete(toKey(key));
27
+ },
28
+ async getKeys(prefix) {
29
+ const match = toKey(prefix);
30
+ const out = [];
31
+ let cursor;
32
+ do {
33
+ const page = await namespace.list({
34
+ prefix: match,
35
+ ...cursor ? { cursor } : {}
36
+ });
37
+ for (const k of page.keys) out.push(fromKey(k.name));
38
+ cursor = page.list_complete ? void 0 : page.cursor;
39
+ } while (cursor);
40
+ return out;
41
+ }
42
+ };
43
+ }
44
+ //#endregion
45
+ exports.createCloudflareKvStorage = createCloudflareKvStorage;
46
+
47
+ //# sourceMappingURL=entry-storage-cloudflare-kv.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-storage-cloudflare-kv.cjs","names":[],"sources":["../src/storage/cloudflare-kv.ts"],"sourcesContent":["/**\n * Cloudflare Workers KV storage adapter. It wraps a `KVNamespace` **binding** —\n * the object Workers exposes on `env.MY_KV` — so it works in production Workers,\n * in local dev via `wrangler dev` / [Miniflare](https://miniflare.dev), and in\n * tests against any object that satisfies the small {@link KVNamespaceLike}\n * surface. There is **no npm peer dependency**: the binding is provided by the\n * runtime, so this adapter only needs the structural type.\n *\n * KV is eventually consistent and has a ~25 MB per-value limit and list\n * pagination — acceptable for a webhooks control plane at library scale. An\n * optional `prefix` namespaces every key (joined with `:`) and is stripped from\n * {@link CloudflareKvWebhooksStorage.getKeys} results, so several deployments\n * can share one namespace.\n *\n * **Dispatcher note:** Workers have no long-lived process, so the delivery\n * dispatcher cannot run its own interval loop. Configure a\n * [cron trigger](https://developers.cloudflare.com/workers/configuration/cron-triggers/)\n * whose `scheduled` handler calls the dispatcher's `tick()` to drive due\n * deliveries.\n *\n * ```ts\n * import { createCloudflareKvStorage } from \"@xtandard/webhooks/storage/cloudflare-kv\";\n *\n * export default {\n * async fetch(req: Request, env: { WEBHOOKS: KVNamespace }) {\n * const storage = createCloudflareKvStorage({ namespace: env.WEBHOOKS, prefix: \"prod\" });\n * // …build the webhooks core over `storage`…\n * },\n * };\n * ```\n *\n * @module\n */\n\nimport type { WebhooksStorage } from \"./contract.ts\";\n\n/** The subset of the Workers `KVNamespace` binding this adapter uses. */\nexport interface KVNamespaceLike {\n get(key: string, type?: \"text\"): Promise<string | null>;\n put(key: string, value: string): Promise<void>;\n delete(key: string): Promise<void>;\n list(options?: {\n prefix?: string;\n cursor?: string;\n limit?: number;\n }): Promise<{ keys: Array<{ name: string }>; list_complete: boolean; cursor?: string }>;\n}\n\n/** Options for {@link createCloudflareKvStorage}. */\nexport interface CloudflareKvStorageOptions {\n /** The KV namespace binding (e.g. `env.WEBHOOKS`). */\n namespace: KVNamespaceLike;\n /** Optional key namespace prepended to every key, joined with `:`. */\n prefix?: string;\n}\n\n/** A {@link WebhooksStorage} backed by a Cloudflare KV namespace binding. */\nexport type CloudflareKvWebhooksStorage = WebhooksStorage;\n\n/**\n * Create a Cloudflare KV–backed {@link WebhooksStorage} from a `KVNamespace` binding.\n *\n * @example\n * ```ts\n * import { createCloudflareKvStorage } from \"@xtandard/webhooks/storage/cloudflare-kv\";\n * const storage = createCloudflareKvStorage({ namespace: env.WEBHOOKS });\n * ```\n */\nexport function createCloudflareKvStorage(\n options: CloudflareKvStorageOptions,\n): CloudflareKvWebhooksStorage {\n const { namespace } = options;\n const fullPrefix = options.prefix ? `${options.prefix}:` : \"\";\n const toKey = (key: string): string => `${fullPrefix}${key}`;\n const fromKey = (key: string): string =>\n fullPrefix && key.startsWith(fullPrefix) ? key.slice(fullPrefix.length) : key;\n\n return {\n async getItem<T>(key: string): Promise<T | null> {\n const raw = await namespace.get(toKey(key), \"text\");\n return raw === null ? null : (JSON.parse(raw) as T);\n },\n\n async setItem<T>(key: string, value: T): Promise<void> {\n await namespace.put(toKey(key), JSON.stringify(value));\n },\n\n async removeItem(key: string): Promise<void> {\n await namespace.delete(toKey(key));\n },\n\n async getKeys(prefix: string): Promise<string[]> {\n const match = toKey(prefix);\n const out: string[] = [];\n let cursor: string | undefined;\n // KV list is paginated; page through until complete.\n do {\n const page = await namespace.list({ prefix: match, ...(cursor ? { cursor } : {}) });\n for (const k of page.keys) out.push(fromKey(k.name));\n cursor = page.list_complete ? undefined : page.cursor;\n } while (cursor);\n return out;\n },\n } satisfies CloudflareKvWebhooksStorage;\n}\n"],"mappings":";;;;;;;;;;;AAoEA,SAAgB,0BACd,SAC6B;CAC7B,MAAM,EAAE,cAAc;CACtB,MAAM,aAAa,QAAQ,SAAS,GAAG,QAAQ,OAAO,KAAK;CAC3D,MAAM,SAAS,QAAwB,GAAG,aAAa;CACvD,MAAM,WAAW,QACf,cAAc,IAAI,WAAW,UAAU,IAAI,IAAI,MAAM,WAAW,MAAM,IAAI;CAE5E,OAAO;EACL,MAAM,QAAW,KAAgC;GAC/C,MAAM,MAAM,MAAM,UAAU,IAAI,MAAM,GAAG,GAAG,MAAM;GAClD,OAAO,QAAQ,OAAO,OAAQ,KAAK,MAAM,GAAG;EAC9C;EAEA,MAAM,QAAW,KAAa,OAAyB;GACrD,MAAM,UAAU,IAAI,MAAM,GAAG,GAAG,KAAK,UAAU,KAAK,CAAC;EACvD;EAEA,MAAM,WAAW,KAA4B;GAC3C,MAAM,UAAU,OAAO,MAAM,GAAG,CAAC;EACnC;EAEA,MAAM,QAAQ,QAAmC;GAC/C,MAAM,QAAQ,MAAM,MAAM;GAC1B,MAAM,MAAgB,CAAC;GACvB,IAAI;GAEJ,GAAG;IACD,MAAM,OAAO,MAAM,UAAU,KAAK;KAAE,QAAQ;KAAO,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;IAAG,CAAC;IAClF,KAAK,MAAM,KAAK,KAAK,MAAM,IAAI,KAAK,QAAQ,EAAE,IAAI,CAAC;IACnD,SAAS,KAAK,gBAAgB,KAAA,IAAY,KAAK;GACjD,SAAS;GACT,OAAO;EACT;CACF;AACF"}