@xtandard/webhooks 0.1.1 → 0.1.3

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 (82) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.cjs +4 -4
  3. package/dist/cli.mjs +4 -4
  4. package/dist/{core-CF8U0hgi.cjs → core-DkIXozBY.cjs} +2 -2
  5. package/dist/{core-CF8U0hgi.cjs.map → core-DkIXozBY.cjs.map} +1 -1
  6. package/dist/{core-C9mPi4iw.mjs → core-tmmtadF1.mjs} +2 -2
  7. package/dist/{core-C9mPi4iw.mjs.map → core-tmmtadF1.mjs.map} +1 -1
  8. package/dist/core.cjs +1 -1
  9. package/dist/core.mjs +1 -1
  10. package/dist/{create-fetch-handler-BILaZ2Z7.cjs → create-fetch-handler-B5WBbf8x.cjs} +3 -3
  11. package/dist/{create-fetch-handler-BILaZ2Z7.cjs.map → create-fetch-handler-B5WBbf8x.cjs.map} +1 -1
  12. package/dist/{create-fetch-handler-D0F3cjoq.mjs → create-fetch-handler-DZohI08M.mjs} +3 -3
  13. package/dist/{create-fetch-handler-D0F3cjoq.mjs.map → create-fetch-handler-DZohI08M.mjs.map} +1 -1
  14. package/dist/{dispatcher-DOOCJJxM.cjs → dispatcher-Bn4O874S.cjs} +3 -3
  15. package/dist/{dispatcher-DOOCJJxM.cjs.map → dispatcher-Bn4O874S.cjs.map} +1 -1
  16. package/dist/{dispatcher-DuBrQL46.mjs → dispatcher-CQcoIsS9.mjs} +3 -3
  17. package/dist/{dispatcher-DuBrQL46.mjs.map → dispatcher-CQcoIsS9.mjs.map} +1 -1
  18. package/dist/elysia-shared-CgTU3yPa.mjs +47 -0
  19. package/dist/elysia-shared-CgTU3yPa.mjs.map +1 -0
  20. package/dist/elysia-shared-Cop1-ie0.cjs +58 -0
  21. package/dist/elysia-shared-Cop1-ie0.cjs.map +1 -0
  22. package/dist/elysia-shared-CvSsqMbR.d.mts +19 -0
  23. package/dist/elysia-shared-DSSrfuoF.d.cts +19 -0
  24. package/dist/entry-bun.cjs +1 -1
  25. package/dist/entry-bun.mjs +1 -1
  26. package/dist/entry-elysia.cjs +5 -25
  27. package/dist/entry-elysia.cjs.map +1 -1
  28. package/dist/entry-elysia.d.cts +5 -15
  29. package/dist/entry-elysia.d.mts +5 -15
  30. package/dist/entry-elysia.mjs +4 -24
  31. package/dist/entry-elysia.mjs.map +1 -1
  32. package/dist/entry-elysia2.cjs +95 -0
  33. package/dist/entry-elysia2.cjs.map +1 -0
  34. package/dist/entry-elysia2.d.cts +1273 -0
  35. package/dist/entry-elysia2.d.mts +1273 -0
  36. package/dist/entry-elysia2.mjs +93 -0
  37. package/dist/entry-elysia2.mjs.map +1 -0
  38. package/dist/entry-express.cjs +1 -1
  39. package/dist/entry-express.mjs +1 -1
  40. package/dist/entry-hono.cjs +1 -1
  41. package/dist/entry-hono.mjs +1 -1
  42. package/dist/index.cjs +3 -3
  43. package/dist/index.d.cts +1 -1
  44. package/dist/index.d.mts +1 -1
  45. package/dist/index.mjs +3 -3
  46. package/dist/react.css +1 -1
  47. package/dist/react.js +2522 -2506
  48. package/dist/testing.cjs +2 -2
  49. package/dist/testing.mjs +2 -2
  50. package/dist/types-elysia2/adapters/elysia-shared.d.ts +34 -0
  51. package/dist/types-elysia2/adapters/elysia2.d.ts +820 -0
  52. package/dist/types-elysia2/auth/contract.d.ts +26 -0
  53. package/dist/types-elysia2/authorization/contract.d.ts +50 -0
  54. package/dist/types-elysia2/canonical.d.ts +27 -0
  55. package/dist/types-elysia2/core.d.ts +344 -0
  56. package/dist/types-elysia2/deliver.d.ts +79 -0
  57. package/dist/types-elysia2/delivery-sink.d.ts +57 -0
  58. package/dist/types-elysia2/dispatcher.d.ts +80 -0
  59. package/dist/types-elysia2/duration.d.ts +26 -0
  60. package/dist/types-elysia2/entry-elysia2.d.ts +8 -0
  61. package/dist/types-elysia2/hooks/contract.d.ts +203 -0
  62. package/dist/types-elysia2/id.d.ts +24 -0
  63. package/dist/types-elysia2/keys.d.ts +98 -0
  64. package/dist/types-elysia2/portal.d.ts +69 -0
  65. package/dist/types-elysia2/schema.d.ts +229 -0
  66. package/dist/types-elysia2/server/base-path.d.ts +15 -0
  67. package/dist/types-elysia2/server/cors.d.ts +36 -0
  68. package/dist/types-elysia2/server/create-fetch-handler.d.ts +121 -0
  69. package/dist/types-elysia2/server/openapi.d.ts +25 -0
  70. package/dist/types-elysia2/server/render-index-html.d.ts +18 -0
  71. package/dist/types-elysia2/server/routes.d.ts +52 -0
  72. package/dist/types-elysia2/server/static-assets.d.ts +13 -0
  73. package/dist/types-elysia2/signing.d.ts +88 -0
  74. package/dist/types-elysia2/storage/contract.d.ts +75 -0
  75. package/dist/types-elysia2/validation.d.ts +82 -0
  76. package/dist/types-elysia2/version.d.ts +8 -0
  77. package/dist/types-react/ui/lib/portal-container.d.ts +24 -0
  78. package/dist/ui/assets/{index-S5t_CLOe.js → index-BgyX_njf.js} +44 -44
  79. package/dist/ui/assets/index-mJCJq_EB.css +1 -0
  80. package/dist/ui/index.html +2 -2
  81. package/package.json +23 -6
  82. package/dist/ui/assets/index-B0eoQX2U.css +0 -1
@@ -0,0 +1,95 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_elysia_shared = require("./elysia-shared-Cop1-ie0.cjs");
3
+ let elysia = require("elysia");
4
+ //#region src/adapters/elysia2.ts
5
+ /**
6
+ * Elysia **2.x** adapter — same surface as `@xtandard/webhooks/elysia`, built
7
+ * against Elysia 2's types and its `(path, hook, handler)` route order. Use
8
+ * `@xtandard/webhooks/elysia` for Elysia 1.x.
9
+ *
10
+ * ```ts
11
+ * new Elysia().mount("/webhooks", webhooksPanel({ basePath: "/webhooks", storage }));
12
+ * // or, typed for Eden treaty (`@elysia/eden`):
13
+ * const app = new Elysia().use(webhooksElysia({ prefix: "/webhooks", storage }));
14
+ * ```
15
+ *
16
+ * The panel starts the delivery dispatcher by default; pass `dispatcher: false`
17
+ * for split-worker deployments.
18
+ *
19
+ * @module
20
+ */
21
+ const appParams = elysia.t.Object({ app: elysia.t.String() });
22
+ const endpointParams = elysia.t.Object({
23
+ app: elysia.t.String(),
24
+ id: elysia.t.String()
25
+ });
26
+ const nameParams = elysia.t.Object({ name: elysia.t.String() });
27
+ /**
28
+ * Typed Elysia plugin exposing the admin API so the **Eden** client can call it
29
+ * with full path/method/param typing (`edenClient.webhooks.api.applications.get()`).
30
+ * Routes are declared for the typed surface; every handler delegates to the
31
+ * shared fetch pipeline (auth, authorization, portal scoping, error mapping
32
+ * reused). A catch-all also serves the bundled UI.
33
+ *
34
+ * Elysia 2.x only — for Elysia 1.x import from `@xtandard/webhooks/elysia`.
35
+ */
36
+ function webhooksElysia(options) {
37
+ const { prefix, pass } = require_elysia_shared.createPass(options);
38
+ const app = "/api/applications/:app";
39
+ const endpoint = `${app}/endpoints/:id`;
40
+ return new elysia.Elysia({
41
+ prefix,
42
+ name: "xtandard-webhooks"
43
+ }).get("/config", pass).get("/api/openapi.json", pass).get("/api/event-types.json", pass).get("/api/applications", pass).post("/api/applications", { body: elysia.t.Object({
44
+ key: elysia.t.String(),
45
+ name: elysia.t.Optional(elysia.t.String()),
46
+ metadata: elysia.t.Optional(elysia.t.Any())
47
+ }) }, pass).get(app, { params: appParams }, pass).put(app, {
48
+ params: appParams,
49
+ body: elysia.t.Any()
50
+ }, pass).delete(app, { params: appParams }, pass).get("/api/event-types", pass).post("/api/event-types", { body: elysia.t.Object({
51
+ name: elysia.t.String(),
52
+ description: elysia.t.Optional(elysia.t.String()),
53
+ groupName: elysia.t.Optional(elysia.t.String()),
54
+ schema: elysia.t.Optional(elysia.t.Any()),
55
+ deprecated: elysia.t.Optional(elysia.t.Boolean())
56
+ }) }, pass).get("/api/event-types/:name", { params: nameParams }, pass).put("/api/event-types/:name", {
57
+ params: nameParams,
58
+ body: elysia.t.Any()
59
+ }, pass).delete("/api/event-types/:name", { params: nameParams }, pass).get(`${app}/endpoints`, { params: appParams }, pass).post(`${app}/endpoints`, {
60
+ params: appParams,
61
+ body: elysia.t.Object({
62
+ url: elysia.t.String(),
63
+ description: elysia.t.Optional(elysia.t.String()),
64
+ eventTypes: elysia.t.Optional(elysia.t.Array(elysia.t.String())),
65
+ headers: elysia.t.Optional(elysia.t.Record(elysia.t.String(), elysia.t.String())),
66
+ metadata: elysia.t.Optional(elysia.t.Any()),
67
+ disabled: elysia.t.Optional(elysia.t.Boolean())
68
+ })
69
+ }, pass).get(endpoint, { params: endpointParams }, pass).put(endpoint, {
70
+ params: endpointParams,
71
+ body: elysia.t.Any()
72
+ }, pass).delete(endpoint, { params: endpointParams }, pass).get(`${endpoint}/secret`, { params: endpointParams }, pass).post(`${endpoint}/rotate-secret`, { params: endpointParams }, pass).post(`${endpoint}/enable`, { params: endpointParams }, pass).post(`${endpoint}/disable`, { params: endpointParams }, pass).post(`${endpoint}/test`, {
73
+ params: endpointParams,
74
+ body: elysia.t.Object({
75
+ eventType: elysia.t.String(),
76
+ payload: elysia.t.Optional(elysia.t.Any())
77
+ })
78
+ }, pass).post(`${endpoint}/recover`, {
79
+ params: endpointParams,
80
+ body: elysia.t.Object({ since: elysia.t.String() })
81
+ }, pass).get(`${app}/messages`, { params: appParams }, pass).post(`${app}/messages`, {
82
+ params: appParams,
83
+ body: elysia.t.Object({
84
+ eventType: elysia.t.String(),
85
+ payload: elysia.t.Any(),
86
+ timestamp: elysia.t.Optional(elysia.t.String()),
87
+ idempotencyKey: elysia.t.Optional(elysia.t.String())
88
+ })
89
+ }, pass).get(`${app}/messages/:id`, { params: endpointParams }, pass).get(`${app}/deliveries`, { params: appParams }, pass).get(`${app}/deliveries/:id`, { params: endpointParams }, pass).post(`${app}/deliveries/:id/retry`, { params: endpointParams }, pass).get(`${app}/audit`, { params: appParams }, pass).all("/*", pass);
90
+ }
91
+ //#endregion
92
+ exports.webhooksElysia = webhooksElysia;
93
+ exports.webhooksPanel = require_elysia_shared.webhooksPanel;
94
+
95
+ //# sourceMappingURL=entry-elysia2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-elysia2.cjs","names":["t","createPass","Elysia"],"sources":["../src/adapters/elysia2.ts"],"sourcesContent":["/**\n * Elysia **2.x** adapter — same surface as `@xtandard/webhooks/elysia`, built\n * against Elysia 2's types and its `(path, hook, handler)` route order. Use\n * `@xtandard/webhooks/elysia` for Elysia 1.x.\n *\n * ```ts\n * new Elysia().mount(\"/webhooks\", webhooksPanel({ basePath: \"/webhooks\", storage }));\n * // or, typed for Eden treaty (`@elysia/eden`):\n * const app = new Elysia().use(webhooksElysia({ prefix: \"/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 { Elysia, t } from \"elysia\";\nimport {\n createPass,\n webhooksPanel,\n type ElysiaWebhooksHandler,\n type WebhooksElysiaOptions,\n type WebhooksPanelOptions,\n} from \"./elysia-shared.ts\";\n\nexport { webhooksPanel };\nexport type { ElysiaWebhooksHandler, WebhooksElysiaOptions, WebhooksPanelOptions };\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 *\n * Elysia 2.x only — for Elysia 1.x import from `@xtandard/webhooks/elysia`.\n */\nexport function webhooksElysia(options: WebhooksElysiaOptions) {\n const { prefix, pass } = createPass(options);\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(\n \"/api/applications\",\n {\n body: t.Object({\n key: t.String(),\n name: t.Optional(t.String()),\n metadata: t.Optional(t.Any()),\n }),\n },\n pass,\n )\n .get(app, { params: appParams }, pass)\n .put(app, { params: appParams, body: t.Any() }, pass)\n .delete(app, { params: appParams }, pass)\n .get(\"/api/event-types\", pass)\n .post(\n \"/api/event-types\",\n {\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 pass,\n )\n .get(\"/api/event-types/:name\", { params: nameParams }, pass)\n .put(\"/api/event-types/:name\", { params: nameParams, body: t.Any() }, pass)\n .delete(\"/api/event-types/:name\", { params: nameParams }, pass)\n .get(`${app}/endpoints`, { params: appParams }, pass)\n .post(\n `${app}/endpoints`,\n {\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 pass,\n )\n .get(endpoint, { params: endpointParams }, pass)\n .put(endpoint, { params: endpointParams, body: t.Any() }, pass)\n .delete(endpoint, { params: endpointParams }, pass)\n .get(`${endpoint}/secret`, { params: endpointParams }, pass)\n .post(`${endpoint}/rotate-secret`, { params: endpointParams }, pass)\n .post(`${endpoint}/enable`, { params: endpointParams }, pass)\n .post(`${endpoint}/disable`, { params: endpointParams }, pass)\n .post(\n `${endpoint}/test`,\n {\n params: endpointParams,\n body: t.Object({ eventType: t.String(), payload: t.Optional(t.Any()) }),\n },\n pass,\n )\n .post(\n `${endpoint}/recover`,\n {\n params: endpointParams,\n body: t.Object({ since: t.String() }),\n },\n pass,\n )\n .get(`${app}/messages`, { params: appParams }, pass)\n .post(\n `${app}/messages`,\n {\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 pass,\n )\n .get(`${app}/messages/:id`, { params: endpointParams }, pass)\n .get(`${app}/deliveries`, { params: appParams }, pass)\n .get(`${app}/deliveries/:id`, { params: endpointParams }, pass)\n .post(`${app}/deliveries/:id/retry`, { params: endpointParams }, pass)\n .get(`${app}/audit`, { params: appParams }, pass)\n .all(\"/*\", pass); // bundled UI assets + SPA fallback\n}\n"],"mappings":"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"}