@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,502 @@
1
+ import { a as AuditEntry, f as EventType, g as WebhookDuration, l as Endpoint, m as Message, n as Application, o as Delivery, p as JsonValue, r as AttemptTrigger, s as DeliveryAttempt, t as Actor } from "./schema-mo__wv4P.mjs";
2
+ import { o as WebhooksStorage } from "./contract-DhQ4JjGG.mjs";
3
+ import { c as WebhooksHooksInput, o as HookErrorReporter, s as WebhooksHooks } from "./contract-T1kcZNdG.mjs";
4
+
5
+ //#region src/deliver.d.ts
6
+ /** Default cap on how many response-body characters are kept per attempt. */
7
+ declare const DEFAULT_RESPONSE_BODY_LIMIT = 4096;
8
+ /** Default per-attempt timeout. */
9
+ declare const DEFAULT_ATTEMPT_TIMEOUT_MS = 20000;
10
+ /** Input to {@link attemptDelivery}. */
11
+ interface AttemptDeliveryInput {
12
+ endpoint: Endpoint;
13
+ /** The `webhook-id` header — the **message** id (stable across retries). */
14
+ messageId: string;
15
+ /** The serialized envelope body, exactly as stored at publish time. */
16
+ body: string;
17
+ /** Per-attempt timeout (AbortController). Default 20s. */
18
+ timeoutMs?: number;
19
+ /** Cap on stored response-body characters. Default 4096. */
20
+ responseBodyLimit?: number;
21
+ /** `user-agent` header value. */
22
+ userAgent?: string;
23
+ /** Injectable fetch (tests, instrumentation). Default: global fetch. */
24
+ fetch?: typeof fetch;
25
+ /** Unix millis of the attempt; defaults to `Date.now()`. */
26
+ nowMs?: number;
27
+ }
28
+ /** The observed outcome of one HTTP delivery attempt. */
29
+ interface AttemptOutcome {
30
+ ok: boolean;
31
+ httpStatus?: number;
32
+ /** Truncated error message on network error/timeout. */
33
+ error?: string;
34
+ /** Truncated response body. */
35
+ responseBody?: string;
36
+ durationMs: number;
37
+ /** ISO-8601 timestamp of the attempt. */
38
+ at: string;
39
+ }
40
+ /** The exact HTTP request a delivery attempt sends — the inspector's view. */
41
+ interface SignedRequest {
42
+ method: "POST";
43
+ url: string;
44
+ headers: Record<string, string>;
45
+ body: string;
46
+ }
47
+ /** Input to {@link buildSignedRequest}. */
48
+ interface BuildSignedRequestInput {
49
+ endpoint: Endpoint;
50
+ /** `webhook-id` — the message id (stable across retries). */
51
+ messageId: string;
52
+ /** The serialized envelope body. */
53
+ body: string;
54
+ /** `user-agent` header value. */
55
+ userAgent?: string;
56
+ /** Unix millis; defaults to `Date.now()`. Determines `webhook-timestamp`. */
57
+ nowMs?: number;
58
+ }
59
+ /**
60
+ * Build the exact signed request an attempt would POST — Standard Webhooks
61
+ * headers, all unexpired secrets signing — **without sending it**. Shared by
62
+ * {@link attemptDelivery} and the panel's request inspector so what you preview
63
+ * is byte-for-byte what a receiver gets.
64
+ */
65
+ declare function buildSignedRequest(input: BuildSignedRequestInput): Promise<SignedRequest>;
66
+ /** The endpoint's currently-signing secrets: the active one + unexpired rotation grace. */
67
+ declare function activeSecrets(endpoint: Endpoint, nowMs: number): string[];
68
+ /**
69
+ * Perform one signed POST to `endpoint.url`. Never throws for remote-party
70
+ * failures — network errors, timeouts, and non-2xx responses all come back as
71
+ * a failed {@link AttemptOutcome}. (It does throw on programmer error, e.g. an
72
+ * endpoint with no unexpired secret.)
73
+ */
74
+ declare function attemptDelivery(input: AttemptDeliveryInput): Promise<AttemptOutcome>;
75
+ //#endregion
76
+ //#region src/delivery-sink.d.ts
77
+ /** One recorded delivery attempt, delivered to a {@link DeliveryListener}. */
78
+ interface DeliveryEvent {
79
+ applicationKey: string;
80
+ endpointId: string;
81
+ messageId: string;
82
+ deliveryId: string;
83
+ /** The message's event type name. */
84
+ eventType: string;
85
+ /** 1-based attempt ordinal within the delivery. */
86
+ attemptNumber: number;
87
+ /** True when the receiver answered 2xx. */
88
+ ok: boolean;
89
+ /** True when this attempt drove the delivery to a terminal state. */
90
+ terminal: boolean;
91
+ /** HTTP status code; absent on network error/timeout. */
92
+ httpStatus?: number;
93
+ /** Wall-clock duration of the HTTP round trip. */
94
+ durationMs: number;
95
+ /** What initiated the attempt. */
96
+ trigger: AttemptTrigger;
97
+ /** ISO-8601 timestamp of the attempt. */
98
+ at: string;
99
+ }
100
+ /**
101
+ * A fire-and-forget observer of delivery attempts. Return value (including a
102
+ * Promise) is ignored by the caller; throwing / rejecting never affects the
103
+ * delivery — failures are routed to the configured error reporter.
104
+ */
105
+ type DeliveryListener = (event: DeliveryEvent) => void | Promise<void>;
106
+ /** Reports an error thrown/rejected by a {@link DeliveryListener}. */
107
+ type DeliveryErrorReporter = (error: unknown, event: DeliveryEvent) => void;
108
+ /**
109
+ * Invoke `listener` safely off the delivery path: synchronous throws are caught
110
+ * and a returned Promise's rejection is handled, so a broken sink can never
111
+ * fail (or slow, since it is not awaited) a delivery.
112
+ */
113
+ declare function emitDelivery(listener: DeliveryListener, event: DeliveryEvent, onError?: DeliveryErrorReporter): void;
114
+ //#endregion
115
+ //#region src/dispatcher.d.ts
116
+ /** Options for {@link createDispatcher} (also accepted on panels and the core). */
117
+ interface DispatcherOptions {
118
+ /** How often to poll for due deliveries. Default `1000`. */
119
+ pollIntervalMs?: number;
120
+ /** Max deliveries claimed per tick. Default `20`. */
121
+ batchSize?: number;
122
+ /** Max in-flight HTTP attempts. Default `8`. */
123
+ concurrency?: number;
124
+ /** Per-attempt timeout (AbortController). Default `20_000`. */
125
+ timeoutMs?: number;
126
+ /** Claim lease duration; an expired lease makes a claim reclaimable. Default `60_000`. */
127
+ leaseMs?: number;
128
+ /**
129
+ * Delay before attempt N+1 after attempt N fails (index 0 = the initial
130
+ * attempt's delay). Exhausting the schedule dead-letters the delivery.
131
+ * Default `["0s", "5s", "5m", "30m", "2h", "5h", "10h"]` (Svix-compatible).
132
+ */
133
+ retrySchedule?: WebhookDuration[];
134
+ /**
135
+ * Auto-disable endpoints whose every attempt has failed for this many
136
+ * consecutive days. `false` disables the policy. Default `{ failingForDays: 5 }`.
137
+ */
138
+ autoDisable?: {
139
+ failingForDays?: number;
140
+ } | false;
141
+ /** Cap on stored response-body characters per attempt. Default `4096`. */
142
+ responseBodyLimit?: number;
143
+ /** Injectable fetch (tests, instrumentation). Default: global fetch. */
144
+ fetch?: typeof fetch;
145
+ /** `user-agent` header. Default `"xtandard-webhooks/<version>"`. */
146
+ userAgent?: string;
147
+ }
148
+ /** The delivery engine handle. */
149
+ interface Dispatcher {
150
+ /** Begin polling. Idempotent. */
151
+ start(): void;
152
+ /** Stop polling and wait for in-flight attempts to finish. */
153
+ stop(): Promise<void>;
154
+ /**
155
+ * Run one manual pass: claim due deliveries, attempt them, record outcomes.
156
+ * Returns the number of attempts made — the unit-test surface (tests never
157
+ * assert on timers).
158
+ */
159
+ tick(): Promise<number>;
160
+ readonly running: boolean;
161
+ }
162
+ /** The default retry schedule (Svix-compatible). */
163
+ declare const DEFAULT_RETRY_SCHEDULE: WebhookDuration[];
164
+ /**
165
+ * Create a dispatcher over a core. Not started — call
166
+ * {@link Dispatcher.start}, or drive {@link Dispatcher.tick} manually.
167
+ *
168
+ * @example
169
+ * ```ts
170
+ * import { createWebhooksCore, createDispatcher } from "@xtandard/webhooks";
171
+ * import { createMemoryStorage } from "@xtandard/webhooks/storage/memory";
172
+ *
173
+ * const core = createWebhooksCore({ storage: createMemoryStorage() });
174
+ * const dispatcher = createDispatcher(core);
175
+ * dispatcher.start();
176
+ * ```
177
+ */
178
+ declare function createDispatcher(core: WebhooksCore, options?: DispatcherOptions): Dispatcher;
179
+ //#endregion
180
+ //#region src/core.d.ts
181
+ /** Thrown by mutating operations when the core is in readonly mode. */
182
+ declare class ReadonlyError extends Error {
183
+ constructor(operation: string);
184
+ }
185
+ /** Thrown when a referenced application/event type/endpoint/delivery does not exist. */
186
+ declare class NotFoundError extends Error {
187
+ constructor(message: string);
188
+ }
189
+ /** Thrown when creating an entity whose key already exists. Maps to HTTP 409. */
190
+ declare class ConflictError extends Error {
191
+ constructor(message: string);
192
+ }
193
+ /** Thrown by {@link WebhooksCore.publish} when the payload exceeds the limit. Maps to 413. */
194
+ declare class PayloadTooLargeError extends Error {
195
+ constructor(size: number, limit: number);
196
+ }
197
+ /**
198
+ * Thrown by {@link WebhooksCore.publish} when an idempotency key is reused with
199
+ * a **different** payload (same key + same payload returns the original
200
+ * message instead). Maps to HTTP 409.
201
+ */
202
+ declare class IdempotencyConflictError extends Error {
203
+ constructor(key: string);
204
+ }
205
+ /**
206
+ * One retention rule set. When both fields are set, an item is **kept if either
207
+ * rule keeps it** (union of keeps — the same semantics as backup tools): pruned
208
+ * only when it is outside the `keepLast` most recent AND older than `maxAge`.
209
+ */
210
+ interface RetentionRule {
211
+ /** Keep at most the N most recent items. */
212
+ keepLast?: number;
213
+ /** Keep items newer than this age (relative to prune time). */
214
+ maxAge?: WebhookDuration;
215
+ }
216
+ /** Retention policy for {@link WebhooksCoreOptions.retention}. */
217
+ interface RetentionOptions {
218
+ /**
219
+ * Prune old messages, cascading their deliveries and attempts. Messages with
220
+ * a non-terminal delivery are never pruned (the dispatcher still needs them).
221
+ */
222
+ messages?: RetentionRule;
223
+ /** Prune old audit entries. */
224
+ audit?: RetentionRule;
225
+ }
226
+ /** Options for {@link createWebhooksCore}. */
227
+ interface WebhooksCoreOptions {
228
+ /** Control-plane store: applications, event types, endpoints, messages, audit. */
229
+ storage: WebhooksStorage;
230
+ /**
231
+ * Store for deliveries, attempts, and the due index. Defaults to `storage`.
232
+ * Splitting lets control data live in Postgres while the queue lives in Redis.
233
+ */
234
+ queueStorage?: WebhooksStorage;
235
+ /** When true, all mutating operations throw {@link ReadonlyError}. */
236
+ readonly?: boolean;
237
+ /**
238
+ * Control-plane hooks fired around admin mutations. Pass one hook or an array.
239
+ * `before` hooks run sequentially and may **throw to deny**; `after` hooks run
240
+ * post-commit for side effects and never fail the operation.
241
+ */
242
+ hooks?: WebhooksHooksInput;
243
+ /** Reporter invoked when an `after` hook throws. Defaults to `console.warn`. */
244
+ onHookError?: HookErrorReporter;
245
+ /** Fire-and-forget sink invoked for **every** delivery attempt (metrics tap). */
246
+ onDelivery?: DeliveryListener;
247
+ /** Reporter invoked when the `onDelivery` sink throws/rejects. */
248
+ onDeliveryError?: DeliveryErrorReporter;
249
+ /**
250
+ * Retention policy. Message pruning cascades deliveries/attempts and is
251
+ * non-vetoable; removed payloads are surfaced to `after` hooks
252
+ * (`message.pruned`, `audit.pruned`) so they can be offloaded first. Pruning
253
+ * runs opportunistically after publishes (off the hot path, fire-and-forget)
254
+ * and on demand via {@link WebhooksCore.prune}.
255
+ */
256
+ retention?: RetentionOptions;
257
+ /**
258
+ * Dispatcher configuration, carried here so panels/CLI construct dispatchers
259
+ * consistently. The core itself never starts one — creation is the
260
+ * panel/CLI's job (or yours, via `createDispatcher(core, core.options.dispatcher)`).
261
+ */
262
+ dispatcher?: DispatcherOptions;
263
+ /** Grace window during which a rotated-out secret keeps signing. Default `"24h"`. */
264
+ secretRotationGrace?: WebhookDuration;
265
+ /** Allow `http:` endpoint URLs beyond localhost (dev only; default `false`). */
266
+ allowInsecureUrls?: boolean;
267
+ /** Extra endpoint-URL gate; return `false` to reject (SSRF denylist etc.). */
268
+ urlPolicy?: (url: string) => boolean;
269
+ /** Max serialized payload size accepted by publish. Default `262_144` bytes. */
270
+ payloadLimitBytes?: number;
271
+ /**
272
+ * Whether {@link WebhooksCore.publish} requires the event type to exist in
273
+ * the catalog. Default `true` — a typo'd event type name would otherwise
274
+ * silently deliver to nobody (endpoints subscribe by exact name).
275
+ */
276
+ requireKnownEventTypes?: boolean;
277
+ /** Injectable clock (unix millis) for tests. Default `Date.now`. */
278
+ now?: () => number;
279
+ }
280
+ /** Per-call actor attribution for audited mutations. */
281
+ interface ActorOptions {
282
+ actor?: Actor | null;
283
+ }
284
+ /** Input to {@link WebhooksCore.publish}. */
285
+ interface PublishInput {
286
+ eventType: string;
287
+ payload: JsonValue;
288
+ /** ISO-8601 event-occurred time. Defaults to publish time. */
289
+ timestamp?: string;
290
+ /** Dedupe key: same key + same payload within retention returns the existing message. */
291
+ idempotencyKey?: string;
292
+ }
293
+ /** Result of {@link WebhooksCore.publish}. */
294
+ interface PublishResult {
295
+ message: Message;
296
+ deliveries: Delivery[];
297
+ /** True when an idempotency key matched and the existing message was returned. */
298
+ deduplicated: boolean;
299
+ }
300
+ /** Pagination + filters for {@link WebhooksCore.listMessages}. */
301
+ interface ListMessagesOptions {
302
+ /** Page size. Default 50, max 200. */
303
+ limit?: number;
304
+ /** Cursor: return items strictly older than the message with this id. */
305
+ before?: string;
306
+ eventType?: string;
307
+ }
308
+ /** Pagination + filters for {@link WebhooksCore.listDeliveries}. */
309
+ interface ListDeliveriesOptions {
310
+ status?: Delivery["status"];
311
+ endpointId?: string;
312
+ messageId?: string;
313
+ /** Page size. Default 50, max 200. */
314
+ limit?: number;
315
+ /** Cursor: return items strictly older than the delivery with this id. */
316
+ before?: string;
317
+ }
318
+ /** Input to the dispatcher-facing {@link WebhooksCore.claimDueDeliveries}. */
319
+ interface ClaimInput {
320
+ limit: number;
321
+ leaseMs: number;
322
+ }
323
+ /** Input to the dispatcher-facing {@link WebhooksCore.recordAttempt}. */
324
+ interface RecordAttemptInput {
325
+ delivery: Delivery;
326
+ outcome: AttemptOutcome;
327
+ trigger: DeliveryAttempt["trigger"];
328
+ /**
329
+ * When the outcome failed: the next attempt time (dispatcher computes the
330
+ * schedule + jitter), or `null` when the schedule is exhausted (dead-letter).
331
+ * Ignored for successful outcomes.
332
+ */
333
+ nextAttemptAt?: string | null;
334
+ /** The message's event type (for the sink event); loaded by the dispatcher anyway. */
335
+ eventType: string;
336
+ }
337
+ /** Result of {@link WebhooksCore.sendExample}. */
338
+ interface SendExampleResult {
339
+ outcome: AttemptOutcome;
340
+ /** The envelope body that was sent. */
341
+ body: string;
342
+ /** The synthetic message id used as `webhook-id` (not retained). */
343
+ messageId: string;
344
+ }
345
+ /** Result of {@link WebhooksCore.recoverEndpoint}. */
346
+ interface RecoverResult {
347
+ /** Ids of the failed deliveries that were re-queued. */
348
+ deliveryIds: string[];
349
+ }
350
+ /** The admin + publish core surface. */
351
+ interface WebhooksCore {
352
+ readonly options: {
353
+ storage: WebhooksStorage;
354
+ queueStorage: WebhooksStorage;
355
+ readonly: boolean; /** Normalized hooks (always an array). */
356
+ hooks: WebhooksHooks[];
357
+ retention?: RetentionOptions;
358
+ dispatcher?: DispatcherOptions;
359
+ secretRotationGrace: WebhookDuration;
360
+ allowInsecureUrls: boolean;
361
+ urlPolicy?: (url: string) => boolean;
362
+ payloadLimitBytes: number;
363
+ requireKnownEventTypes: boolean;
364
+ onDelivery?: DeliveryListener;
365
+ onDeliveryError?: DeliveryErrorReporter;
366
+ now: () => number;
367
+ };
368
+ listApplications(): Promise<Application[]>;
369
+ createApplication(input: {
370
+ key: string;
371
+ name?: string;
372
+ metadata?: JsonValue;
373
+ }, options?: ActorOptions): Promise<Application>;
374
+ getApplication(applicationKey: string): Promise<Application | null>;
375
+ updateApplication(applicationKey: string, patch: {
376
+ name?: string;
377
+ metadata?: JsonValue;
378
+ }, options?: ActorOptions): Promise<Application>;
379
+ /** Deletes the application and **everything** under it (endpoints, messages, deliveries). */
380
+ deleteApplication(applicationKey: string, options?: ActorOptions): Promise<void>;
381
+ listEventTypes(): Promise<EventType[]>;
382
+ getEventType(name: string): Promise<EventType | null>;
383
+ upsertEventType(input: EventType, options?: ActorOptions): Promise<EventType>;
384
+ /**
385
+ * Delete an event type. Endpoints referencing it keep their subscription
386
+ * entry and simply stop matching new publishes of that name.
387
+ */
388
+ deleteEventType(name: string, options?: ActorOptions): Promise<void>;
389
+ listEndpoints(applicationKey: string): Promise<Endpoint[]>;
390
+ getEndpoint(applicationKey: string, endpointId: string): Promise<Endpoint | null>;
391
+ /** Creates the endpoint and generates its first signing secret. */
392
+ createEndpoint(applicationKey: string, input: {
393
+ url: string;
394
+ description?: string;
395
+ eventTypes?: string[];
396
+ headers?: Record<string, string>;
397
+ metadata?: JsonValue;
398
+ disabled?: boolean;
399
+ }, options?: ActorOptions): Promise<Endpoint>;
400
+ updateEndpoint(applicationKey: string, endpointId: string, patch: {
401
+ url?: string;
402
+ description?: string;
403
+ eventTypes?: string[];
404
+ headers?: Record<string, string>;
405
+ metadata?: JsonValue;
406
+ }, options?: ActorOptions): Promise<Endpoint>;
407
+ deleteEndpoint(applicationKey: string, endpointId: string, options?: ActorOptions): Promise<void>;
408
+ /**
409
+ * Mint a new current secret; the previous one keeps verifying until
410
+ * `secretRotationGrace` elapses. Expired grace secrets are pruned lazily.
411
+ */
412
+ rotateSecret(applicationKey: string, endpointId: string, options?: ActorOptions): Promise<Endpoint>;
413
+ /** The endpoint's secrets (current first). Gate behind `endpoint:read-secret`. */
414
+ getSecrets(applicationKey: string, endpointId: string): Promise<Endpoint["secrets"]>;
415
+ enableEndpoint(applicationKey: string, endpointId: string, options?: ActorOptions): Promise<Endpoint>;
416
+ disableEndpoint(applicationKey: string, endpointId: string, options?: ActorOptions): Promise<Endpoint>;
417
+ /**
418
+ * Persist a message and fan out one pending delivery per matching enabled
419
+ * endpoint. Never performs HTTP; never throws because an endpoint is down.
420
+ */
421
+ publish(applicationKey: string, input: PublishInput, options?: ActorOptions): Promise<PublishResult>;
422
+ listMessages(applicationKey: string, options?: ListMessagesOptions): Promise<Message[]>;
423
+ getMessage(applicationKey: string, messageId: string): Promise<Message | null>;
424
+ listDeliveries(applicationKey: string, options?: ListDeliveriesOptions): Promise<Delivery[]>;
425
+ getDelivery(applicationKey: string, deliveryId: string): Promise<{
426
+ delivery: Delivery;
427
+ attempts: DeliveryAttempt[];
428
+ } | null>;
429
+ /**
430
+ * The exact signed HTTP request this delivery would send **right now** —
431
+ * method, URL, all headers (including the computed `webhook-signature`), and
432
+ * body. The inspector view: shows what a receiver gets, without sending.
433
+ * Returns `null` if the delivery or its endpoint no longer exists. The
434
+ * `webhook-timestamp`/signature reflect the current time (they change per
435
+ * attempt by design); the id and body are stable.
436
+ */
437
+ previewDeliveryRequest(applicationKey: string, deliveryId: string): Promise<SignedRequest | null>;
438
+ /** Re-queue a dead-lettered delivery (`failed` → `pending`, due immediately). */
439
+ retryDelivery(applicationKey: string, deliveryId: string, options?: ActorOptions): Promise<Delivery>;
440
+ /** Re-queue every failed delivery for an endpoint created at/after `since`. */
441
+ recoverEndpoint(applicationKey: string, endpointId: string, input: {
442
+ since: string;
443
+ }, options?: ActorOptions): Promise<RecoverResult>;
444
+ /**
445
+ * Fire a one-off signed test delivery at an endpoint, synchronously, through
446
+ * the same wire path as real deliveries (`trigger: "test"`). The synthetic
447
+ * message is not retained.
448
+ */
449
+ sendExample(applicationKey: string, endpointId: string, input: {
450
+ eventType: string;
451
+ payload?: JsonValue;
452
+ }, options?: ActorOptions): Promise<SendExampleResult>;
453
+ /** Newest-first. With `applicationKey`: that app's log; without: global + all apps. */
454
+ listAudit(applicationKey?: string): Promise<AuditEntry[]>;
455
+ /** Run retention now (also runs opportunistically after publishes). */
456
+ prune(): Promise<void>;
457
+ /**
458
+ * Claim up to `limit` due deliveries for exclusive processing. Uses the
459
+ * storage's native `claimDue` when available; otherwise scans the due index
460
+ * with compare-and-swap claiming (plain read-modify-write when the storage
461
+ * has no CAS — single-dispatcher assumption, see docs/DELIVERY.md).
462
+ */
463
+ claimDueDeliveries(input: ClaimInput): Promise<Delivery[]>;
464
+ /** Record one attempt's outcome and advance the delivery's state machine. */
465
+ recordAttempt(input: RecordAttemptInput): Promise<Delivery>;
466
+ /**
467
+ * Update the endpoint's failure streak after an attempt (any success clears
468
+ * it) and auto-disable once the streak exceeds `failingForDays`. Returns the
469
+ * endpoint when it was auto-disabled by this call.
470
+ */
471
+ noteEndpointOutcome(applicationKey: string, endpointId: string, ok: boolean, policy?: {
472
+ failingForDays?: number;
473
+ } | false): Promise<Endpoint | null>;
474
+ }
475
+ /**
476
+ * Construct the core over the configured storage.
477
+ *
478
+ * @example
479
+ * ```ts
480
+ * import { createWebhooksCore } from "@xtandard/webhooks";
481
+ * import { createMemoryStorage } from "@xtandard/webhooks/storage/memory";
482
+ *
483
+ * const core = createWebhooksCore({ storage: createMemoryStorage() });
484
+ *
485
+ * await core.createApplication({ key: "acme" });
486
+ * await core.upsertEventType({ name: "invoice.paid" });
487
+ * const endpoint = await core.createEndpoint("acme", {
488
+ * url: "https://api.acme-customer.com/webhooks",
489
+ * eventTypes: ["invoice.paid"],
490
+ * });
491
+ *
492
+ * // The hot path — call this from your app code:
493
+ * await core.publish("acme", {
494
+ * eventType: "invoice.paid",
495
+ * payload: { invoiceId: "inv_1", amount: 4200 },
496
+ * });
497
+ * ```
498
+ */
499
+ declare function createWebhooksCore(options: WebhooksCoreOptions): WebhooksCore;
500
+ //#endregion
501
+ export { BuildSignedRequestInput as A, createDispatcher as C, emitDelivery as D, DeliveryListener as E, attemptDelivery as F, buildSignedRequest as I, DEFAULT_RESPONSE_BODY_LIMIT as M, SignedRequest as N, AttemptDeliveryInput as O, activeSecrets as P, DispatcherOptions as S, DeliveryEvent as T, WebhooksCore as _, ListDeliveriesOptions as a, DEFAULT_RETRY_SCHEDULE as b, PayloadTooLargeError as c, ReadonlyError as d, RecordAttemptInput as f, SendExampleResult as g, RetentionRule as h, IdempotencyConflictError as i, DEFAULT_ATTEMPT_TIMEOUT_MS as j, AttemptOutcome as k, PublishInput as l, RetentionOptions as m, ClaimInput as n, ListMessagesOptions as o, RecoverResult as p, ConflictError as r, NotFoundError as s, ActorOptions as t, PublishResult as u, WebhooksCoreOptions as v, DeliveryErrorReporter as w, Dispatcher as x, createWebhooksCore as y };
502
+ //# sourceMappingURL=core-DT4ppWh8.d.mts.map