@beignet/core 0.0.49 → 0.0.50

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 (109) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +160 -6
  3. package/dist/events/index.d.ts +54 -5
  4. package/dist/events/index.d.ts.map +1 -1
  5. package/dist/events/index.js +183 -32
  6. package/dist/events/index.js.map +1 -1
  7. package/dist/idempotency/index.d.ts +7 -3
  8. package/dist/idempotency/index.d.ts.map +1 -1
  9. package/dist/idempotency/index.js +45 -12
  10. package/dist/idempotency/index.js.map +1 -1
  11. package/dist/mail/index.d.ts.map +1 -1
  12. package/dist/mail/index.js +6 -3
  13. package/dist/mail/index.js.map +1 -1
  14. package/dist/ports/best-effort-work.d.ts +21 -0
  15. package/dist/ports/best-effort-work.d.ts.map +1 -0
  16. package/dist/ports/best-effort-work.js +2 -0
  17. package/dist/ports/best-effort-work.js.map +1 -0
  18. package/dist/ports/events.d.ts +7 -5
  19. package/dist/ports/events.d.ts.map +1 -1
  20. package/dist/ports/index.d.ts +6 -1
  21. package/dist/ports/index.d.ts.map +1 -1
  22. package/dist/ports/index.js +1 -0
  23. package/dist/ports/index.js.map +1 -1
  24. package/dist/ports/testing.d.ts +15 -0
  25. package/dist/ports/testing.d.ts.map +1 -1
  26. package/dist/ports/testing.js +38 -0
  27. package/dist/ports/testing.js.map +1 -1
  28. package/dist/providers/provider.d.ts +8 -5
  29. package/dist/providers/provider.d.ts.map +1 -1
  30. package/dist/providers/provider.js.map +1 -1
  31. package/dist/server/hooks/cors.d.ts +2 -2
  32. package/dist/server/hooks/cors.d.ts.map +1 -1
  33. package/dist/server/hooks/cors.js +2 -1
  34. package/dist/server/hooks/cors.js.map +1 -1
  35. package/dist/server/hooks/logging.d.ts +2 -2
  36. package/dist/server/hooks/logging.d.ts.map +1 -1
  37. package/dist/server/hooks/logging.js.map +1 -1
  38. package/dist/server/hooks/security.d.ts +2 -2
  39. package/dist/server/hooks/security.d.ts.map +1 -1
  40. package/dist/server/hooks/security.js.map +1 -1
  41. package/dist/server/http.d.ts +21 -2
  42. package/dist/server/http.d.ts.map +1 -1
  43. package/dist/server/index.d.ts +4 -0
  44. package/dist/server/index.d.ts.map +1 -1
  45. package/dist/server/index.js +4 -0
  46. package/dist/server/index.js.map +1 -1
  47. package/dist/server/instrumentation.d.ts.map +1 -1
  48. package/dist/server/instrumentation.js +5 -3
  49. package/dist/server/instrumentation.js.map +1 -1
  50. package/dist/server/request-executor.d.ts.map +1 -1
  51. package/dist/server/request-executor.js +9 -0
  52. package/dist/server/request-executor.js.map +1 -1
  53. package/dist/server/request-preparation.d.ts.map +1 -1
  54. package/dist/server/request-preparation.js +20 -2
  55. package/dist/server/request-preparation.js.map +1 -1
  56. package/dist/server/response-finalization.d.ts +2 -2
  57. package/dist/server/response-finalization.d.ts.map +1 -1
  58. package/dist/server/response-finalization.js +25 -8
  59. package/dist/server/response-finalization.js.map +1 -1
  60. package/dist/server/route-matching.d.ts.map +1 -1
  61. package/dist/server/route-matching.js +12 -1
  62. package/dist/server/route-matching.js.map +1 -1
  63. package/dist/server/server-sent-events.d.ts +94 -0
  64. package/dist/server/server-sent-events.d.ts.map +1 -0
  65. package/dist/server/server-sent-events.js +275 -0
  66. package/dist/server/server-sent-events.js.map +1 -0
  67. package/dist/server/server.d.ts.map +1 -1
  68. package/dist/server/server.js +41 -22
  69. package/dist/server/server.js.map +1 -1
  70. package/dist/server/trusted-proxy-internal.d.ts +4 -0
  71. package/dist/server/trusted-proxy-internal.d.ts.map +1 -1
  72. package/dist/server/trusted-proxy-internal.js +20 -0
  73. package/dist/server/trusted-proxy-internal.js.map +1 -1
  74. package/dist/server/trusted-proxy.d.ts.map +1 -1
  75. package/dist/server/trusted-proxy.js +3 -8
  76. package/dist/server/trusted-proxy.js.map +1 -1
  77. package/dist/testing/index.d.ts +17 -0
  78. package/dist/testing/index.d.ts.map +1 -1
  79. package/dist/testing/index.js +6 -1
  80. package/dist/testing/index.js.map +1 -1
  81. package/package.json +1 -1
  82. package/skills/app-architecture/SKILL.md +23 -3
  83. package/src/events/index.ts +263 -38
  84. package/src/idempotency/index.ts +65 -17
  85. package/src/mail/index.ts +7 -3
  86. package/src/ports/best-effort-work.ts +21 -0
  87. package/src/ports/events.ts +9 -4
  88. package/src/ports/index.ts +9 -0
  89. package/src/ports/testing.ts +45 -0
  90. package/src/providers/provider.ts +8 -5
  91. package/src/server/hooks/cors.ts +11 -5
  92. package/src/server/hooks/logging.ts +6 -2
  93. package/src/server/hooks/security.ts +8 -4
  94. package/src/server/http.ts +23 -2
  95. package/src/server/index.ts +4 -0
  96. package/src/server/instrumentation.ts +12 -4
  97. package/src/server/request-executor.ts +14 -0
  98. package/src/server/request-preparation.ts +23 -3
  99. package/src/server/response-finalization.ts +51 -15
  100. package/src/server/route-matching.ts +24 -1
  101. package/src/server/server-sent-events.ts +415 -0
  102. package/src/server/server.ts +46 -22
  103. package/src/server/trusted-proxy-internal.ts +20 -0
  104. package/src/server/trusted-proxy.ts +6 -7
  105. package/src/testing/index.ts +30 -0
  106. package/dist/query-codec.d.ts +0 -27
  107. package/dist/query-codec.d.ts.map +0 -1
  108. package/dist/query-codec.js +0 -245
  109. package/dist/query-codec.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @beignet/core
2
2
 
3
+ ## 0.0.50
4
+
5
+ ### Patch Changes
6
+
7
+ - 6fe026a: Expose event-subscription readiness and asynchronous cleanup, await listener
8
+ registries during provider startup with bounded rollback, diagnose unsafe app
9
+ wiring, and make Redis subscription lifecycle failures observable with bounded
10
+ provider shutdown and recoverable channel state.
11
+ - 4be4573: Keep mail content out of provider instrumentation, document the Redis
12
+ deployment policy required for monotonic fencing, and align generated agent
13
+ guidance with optional seed, worker, and migration paths.
14
+ - ee402a9: Map invalid adapter URLs to framework responses, cancel oversized request
15
+ streams, distinguish typed idempotency inputs, preserve repeated response
16
+ headers, and match Unicode static routes against encoded URL pathnames.
17
+ - d1db53e: Add a portable Server-Sent Events response helper with JSON framing,
18
+ heartbeats, bounded unread buffering, optional maximum lifetime,
19
+ cancellation-aware asynchronous setup, eventual late cleanup, and safe
20
+ response headers, expose native request cancellation through
21
+ `HttpRequestLike.signal`, and use recoverable bounded snapshots for the
22
+ Devtools live stream with visible partial-data reporting.
23
+ - 7b0961b: Add a non-durable best-effort work port, a recording test adapter, and a Next.js `after()` adapter that isolates scheduler and callback failures.
24
+
3
25
  ## 0.0.49
4
26
 
5
27
  ### Patch Changes
package/README.md CHANGED
@@ -72,11 +72,11 @@ name the framework area they depend on.
72
72
  | `@beignet/core/outbox` | Durable event and job outbox |
73
73
  | `@beignet/core/payments` | Payments port, memory payments adapter, and memory payments provider |
74
74
  | `@beignet/core/pagination` | Offset/cursor page types, normalizers, and result helpers |
75
- | `@beignet/core/ports` | App-facing ports, auth, audit, policies, cache, storage, logging, and redaction |
75
+ | `@beignet/core/ports` | App-facing ports, auth, audit, policies, cache, storage, best-effort work, logging, and redaction |
76
76
  | `@beignet/core/providers` | Provider lifecycle and instrumentation primitives |
77
77
  | `@beignet/core/search` | Search index definitions, SearchPort, memory adapter, memory provider, and helpers |
78
78
  | `@beignet/core/schedules` | Schedule primitives |
79
- | `@beignet/core/server` | Framework-agnostic server runtime, security headers, CSRF, and hook helpers |
79
+ | `@beignet/core/server` | Framework-agnostic server runtime, SSE responses, security headers, CSRF, and hook helpers |
80
80
  | `@beignet/core/server-only` | Static lint marker for modules that must stay out of client bundles |
81
81
  | `@beignet/core/tasks` | Operational task definitions and inline task execution |
82
82
  | `@beignet/core/tenancy` | Branded tenant scope helpers for repository boundaries |
@@ -313,6 +313,55 @@ and dead-lettered messages when you pass a devtools or instrumentation port to
313
313
  `drainOutbox(...)`. Pass `instrumentationContext` when the worker has request or
314
314
  trace IDs that should connect the drain to devtools rows.
315
315
 
316
+ ## Best-effort work
317
+
318
+ `BestEffortWorkPort` lets application code request non-durable follow-up work
319
+ without waiting for it in the originating operation:
320
+
321
+ ```ts
322
+ import type { BestEffortWorkPort } from "@beignet/core/ports";
323
+
324
+ export type AppPorts = {
325
+ bestEffortWork: BestEffortWorkPort;
326
+ };
327
+
328
+ ctx.ports.bestEffortWork.defer(() =>
329
+ ctx.ports.workspaceBroadcast.publish(workspaceId, message),
330
+ );
331
+ ```
332
+
333
+ Use it only when losing the callback does not change the operation's result,
334
+ such as publishing a cache-invalidation hint after the authoritative write has
335
+ committed. The adapter owns scheduler and callback error isolation. Use a job
336
+ or transaction-scoped outbox when work must be retried or survive process
337
+ termination.
338
+
339
+ Tests can use `createRecordingBestEffortWork()` directly or the default
340
+ `bestEffortWork` returned by `createTestPorts(...)`. Call
341
+ `fixture.flushBestEffortWork()` to run the current queued batch deterministically;
342
+ callbacks deferred by that batch remain pending until the next flush. A flush
343
+ attempts the complete batch before rejecting with any callback failures.
344
+
345
+ ## Event subscriptions
346
+
347
+ `EventBusPort.subscribe(...)` returns an `EventSubscription` with a `ready`
348
+ promise and asynchronous, idempotent `unsubscribe()` method. Await `ready`
349
+ before advertising that a process can receive events, and await
350
+ `unsubscribe()` during shutdown. The memory adapter is ready immediately;
351
+ transport adapters resolve readiness only after their initial subscription is
352
+ active.
353
+
354
+ `registerListeners(...)` combines a listener registry into one subscription.
355
+ It waits for every child subscription and applies one 10-second registration
356
+ deadline by default. When setup fails or times out, Beignet starts every child
357
+ cleanup within the remaining deadline. If cleanup does not settle in time,
358
+ `ready` rejects with both the startup failure and a
359
+ `ListenerRegistrationCleanupTimeoutError` instead of hanging startup. Set
360
+ `readyTimeoutMs` when the process needs a different bounded startup policy.
361
+ Normal teardown after successful readiness still awaits transport cleanup;
362
+ apply a host-level shutdown deadline when required. Readiness is an initial
363
+ lifecycle signal, not an ongoing health check or durability guarantee.
364
+
316
365
  ## Provider-contributed ports
317
366
 
318
367
  Apps bind app-owned ports directly and defer the rest to providers with the
@@ -381,7 +430,9 @@ defer those ports before choosing production infrastructure.
381
430
  `createMemoryMailerProvider(options?)` contributes `{ mailer: MailerPort }`
382
431
  backed by `createMemoryMailer(...)`. Deliveries are captured in memory and
383
432
  recorded as `mail.sent` devtools events through the `mail` watcher when an
384
- instrumentation port is installed. Options extend
433
+ instrumentation port is installed. Instrumentation records only the provider,
434
+ recipient count, delivery ID, and duration; it does not record addresses,
435
+ subjects, or message bodies. Options extend
385
436
  `CreateMemoryMailerOptions` (`defaultFrom`, `now`, `id`, `onSend`) plus a
386
437
  provider `name` that defaults to `"memory-mailer"`.
387
438
 
@@ -1080,6 +1131,78 @@ feeds metadata-driven hooks such as rate limiting exactly like contract
1080
1131
  metadata, and the route is not added to the registry — the adapter mounts
1081
1132
  the returned handler at the route's own path.
1082
1133
 
1134
+ ### Server-sent events
1135
+
1136
+ `createServerSentEventResponse(...)` creates a portable Fetch `Response` for
1137
+ an SSE endpoint. Use it from a contract handler or raw route after
1138
+ application-owned authentication and authorization:
1139
+
1140
+ ```ts
1141
+ import { createServerSentEventResponse } from "@beignet/core/server";
1142
+
1143
+ return createServerSentEventResponse({
1144
+ signal: req.signal,
1145
+ maxLifetimeMs: 240_000,
1146
+ start({ send }) {
1147
+ send({ event: "reconcile", data: { workspaceId } });
1148
+ const subscription = ctx.ports.workspaceBroadcast.subscribe(
1149
+ workspaceId,
1150
+ (change) => {
1151
+ send({ event: "changed", data: change });
1152
+ },
1153
+ );
1154
+ return { close: () => subscription.unsubscribe() };
1155
+ },
1156
+ onError: (error) => ctx.ports.logger.error("SSE stream failed", { error }),
1157
+ });
1158
+ ```
1159
+
1160
+ Event `data` is JSON-encoded. Optional `event`, `id`, and `retry` fields use
1161
+ standard SSE framing; `retry` sets the browser reconnection delay in
1162
+ milliseconds. `comment(...)` sends an explicit comment, and `close()` ends the
1163
+ response. `send(...)` and `comment(...)` return `true` when they enqueue a
1164
+ frame and `false` after closure, when framing or encoding fails, or when the
1165
+ unread byte limit would be exceeded. Event names and IDs must fit on one line,
1166
+ and IDs cannot contain null characters. A producer, framing, encoding, stream,
1167
+ or buffer-overflow failure reports through `onError` and closes the connection.
1168
+
1169
+ Heartbeat comments default to 25 seconds; `heartbeatMs: false` disables them.
1170
+ `maxLifetimeMs` is opt-in. Both options accept `false` or an integer from `1`
1171
+ through `2_147_483_647`; `retry` accepts an integer from `0` through the same
1172
+ maximum. `start(...)` receives a stream-scoped `signal` that aborts whenever
1173
+ the response closes. Pass it to subscription APIs that perform asynchronous
1174
+ setup. `start(...)` may return a cleanup callback, a closeable subscription, a
1175
+ promise of either, or nothing. If it returns cleanup, request abort, response
1176
+ cancellation, explicit close, and maximum lifetime invoke that cleanup exactly
1177
+ once. `onError` also observes cleanup failures without creating an unhandled
1178
+ rejection. When stream closure aborts asynchronous setup, an expected
1179
+ `AbortError` rejection is treated as cancellation rather than a producer
1180
+ failure; other setup rejections still reach `onError`.
1181
+
1182
+ Unread encoded frames are bounded to `1_048_576` bytes by default. Set
1183
+ `maxBufferedBytes` to an integer from `1` through `2_147_483_647` when the
1184
+ endpoint has a verified frame-size requirement. If one frame or the
1185
+ accumulated unread queue would exceed the limit, the helper reports a
1186
+ `RangeError` and closes the connection; the limit remains active even when
1187
+ `maxLifetimeMs` is disabled. Response-body cancellation waits for cleanup that
1188
+ has already been registered, but it does not wait indefinitely for pending
1189
+ asynchronous setup. The stream signal lets setup stop cooperatively, and any
1190
+ cleanup returned after closure still runs exactly once.
1191
+
1192
+ The response always sets `Content-Type: text/event-stream`,
1193
+ `Cache-Control: no-store, no-transform`, and `X-Accel-Buffering: no`, removes
1194
+ `Content-Length` and hop-by-hop streaming headers, and preserves other custom
1195
+ headers supplied through `headers`. The helper does not own authorization,
1196
+ replay, durability, distributed connection limits, or client reconciliation.
1197
+ Keep authoritative state elsewhere and reconcile on initial connection and
1198
+ reconnect when messages are best-effort hints.
1199
+
1200
+ Use a contract handler when the stream belongs in the route registry and
1201
+ OpenAPI document. Use a raw route when the endpoint is transport-only and the
1202
+ app owns its request and response shape. Document a contract stream with a
1203
+ `.responses({ 200: null })` success schema and an OpenAPI `text/event-stream`
1204
+ media override.
1205
+
1083
1206
  Use `.headers(...)` for request headers that are part of the endpoint contract. Declare header keys in lowercase; server and client runtime matching is case-insensitive.
1084
1207
 
1085
1208
  Request bodies are supported for `POST`, `PUT`, and `PATCH` contracts only.
@@ -1177,7 +1300,8 @@ const tester = createUseCaseTester<AppContext>(createContext);
1177
1300
  The returned fixture exposes captured side effects such as `events`,
1178
1301
  `dispatchedJobs`, `audit.entries`, `mailer.deliveries`,
1179
1302
  `notifications.deliveries`, `outbox.messages`, and memory storage for
1180
- assertions.
1303
+ assertions. Its default `bestEffortWork` port queues callbacks in
1304
+ `pendingBestEffortWork`; call `flushBestEffortWork()` to run the current batch.
1181
1305
 
1182
1306
  `overrides` is typed as `TestPortsOverrides<Ports>`, which accepts typed
1183
1307
  partial ports without casts. The partial rule is one level deep: an
@@ -1821,6 +1945,14 @@ import { createMemoryIdempotencyStore } from "@beignet/core/idempotency";
1821
1945
  const idempotency = createMemoryIdempotencyStore();
1822
1946
  ```
1823
1947
 
1948
+ `createIdempotencyFingerprint(...)` sorts object keys and tags non-JSON values
1949
+ before hashing while retaining the stable representation of ordinary JSON
1950
+ payloads. BigInts and Dates therefore remain distinct from same-looking
1951
+ strings; invalid dates, non-finite numbers, circular values, and the reserved
1952
+ tag key fail instead of producing ambiguous fingerprints. Non-plain objects
1953
+ other than `Date` fail as unsupported; project them to plain command data
1954
+ before hashing.
1955
+
1824
1956
  Reservation tokens use Web Crypto `randomUUID()` or `getRandomValues()` when
1825
1957
  available and securely fall back to `node:crypto` on supported Node runtimes.
1826
1958
  The memory adapter accepts `createReservationToken` when a deterministic test
@@ -2053,6 +2185,24 @@ Use `{ contract, handle }` as the escape hatch for response headers,
2053
2185
  streaming, and multi-status responses. `defineRoute` remains
2054
2186
  available for full handlers that read hook-added `ctx` fields.
2055
2187
 
2188
+ Framework-neutral response header values may be strings or string arrays.
2189
+ Use an array for repeated fields such as `Set-Cookie`; Web-compatible adapters
2190
+ append every item separately, and hooks receive the same string-or-array
2191
+ header record:
2192
+
2193
+ ```ts
2194
+ return {
2195
+ status: 200,
2196
+ headers: {
2197
+ "set-cookie": [
2198
+ "session=abc; Path=/; HttpOnly; Secure; SameSite=Lax",
2199
+ "theme=dark; Path=/; Secure; SameSite=Lax",
2200
+ ],
2201
+ },
2202
+ body: { ok: true },
2203
+ };
2204
+ ```
2205
+
2056
2206
  When credentials live in request headers, declare a `headers` schema on the
2057
2207
  auth hooks. The hook validates the raw lowercase request header record before
2058
2208
  `resolve` runs, so `resolve` receives typed header values; on `required()`
@@ -2154,13 +2304,17 @@ status, including when reading the response stream itself fails.
2154
2304
  request validation, response validation, error mapping, and provider lifecycle.
2155
2305
  Adapters own the platform edge only:
2156
2306
 
2157
- - Convert the native request into `HttpRequestLike`
2307
+ - Convert the native request into `HttpRequestLike`, including its abort
2308
+ signal when the platform exposes one
2158
2309
  - Call `server.api(...)` or a single route handler
2159
2310
  - Convert `HttpResponse` back into the native response type
2160
2311
 
2161
2312
  The public adapter contract is `HttpAdapter<NativeRequest, NativeResponse>`.
2162
2313
  Use it when building a runtime package beyond the first-party `@beignet/web`
2163
- and `@beignet/next` adapters.
2314
+ and `@beignet/next` adapters. Custom adapters must supply an absolute HTTP or
2315
+ HTTPS `HttpRequestLike.url`; invalid values are converted to a framework-owned
2316
+ `400 INVALID_REQUEST_URL` response instead of escaping as a rejected handler
2317
+ promise.
2164
2318
 
2165
2319
  ### Health and readiness
2166
2320
 
@@ -47,6 +47,45 @@ export interface EventPublishOptions {
47
47
  /** Versioned trace context captured by the event producer. */
48
48
  trace?: TraceCarrier;
49
49
  }
50
+ /**
51
+ * Lifecycle handle for one event subscription or a composed listener
52
+ * registration.
53
+ *
54
+ * `ready` proves initial transport readiness. It does not represent ongoing
55
+ * connectivity, durability, replay, or handler success after startup.
56
+ */
57
+ export interface EventSubscription {
58
+ /** Resolves when the subscription can receive events. */
59
+ readonly ready: Promise<void>;
60
+ /** Stop local delivery and await transport cleanup. Idempotent. */
61
+ unsubscribe(): Promise<void>;
62
+ }
63
+ /** Error used when a subscription closes before initial readiness. */
64
+ export declare class EventSubscriptionClosedError extends Error {
65
+ constructor(message?: string);
66
+ }
67
+ /** Error thrown when a listener registry misses its readiness deadline. */
68
+ export declare class ListenerRegistrationTimeoutError extends Error {
69
+ /** Configured readiness deadline in milliseconds. */
70
+ readonly timeoutMs: number;
71
+ /** Listener names that were part of the registration. */
72
+ readonly listenerNames: readonly string[];
73
+ constructor(args: {
74
+ timeoutMs: number;
75
+ listenerNames: readonly string[];
76
+ });
77
+ }
78
+ /** Error thrown when listener rollback misses the registration deadline. */
79
+ export declare class ListenerRegistrationCleanupTimeoutError extends Error {
80
+ /** Configured registration deadline in milliseconds. */
81
+ readonly timeoutMs: number;
82
+ /** Listener names that were part of the registration. */
83
+ readonly listenerNames: readonly string[];
84
+ constructor(args: {
85
+ timeoutMs: number;
86
+ listenerNames: readonly string[];
87
+ });
88
+ }
50
89
  /**
51
90
  * Options for `defineEvent(...)`.
52
91
  */
@@ -120,9 +159,9 @@ export interface EventBusLike {
120
159
  */
121
160
  publish<E extends EventPayloadDef>(event: E, payload: InferEventPayload<E>, options?: EventPublishOptions): MaybePromise<void>;
122
161
  /**
123
- * Subscribe to an event and return an unsubscribe function.
162
+ * Subscribe to an event and return its readiness and cleanup handle.
124
163
  */
125
- subscribe<E extends EventPayloadDef>(event: E, handler: (payload: InferEventPayload<E>, options?: EventPublishOptions) => MaybePromise<void>): () => void;
164
+ subscribe<E extends EventPayloadDef>(event: E, handler: (payload: InferEventPayload<E>, options?: EventPublishOptions) => MaybePromise<void>): EventSubscription;
126
165
  }
127
166
  /**
128
167
  * Options for `registerListeners(...)`.
@@ -142,6 +181,12 @@ export interface RegisterListenersOptions<Ctx> {
142
181
  * the event bus subscription callback.
143
182
  */
144
183
  onError?: (error: unknown, listener: ListenerDef<EventDef, Ctx>) => void;
184
+ /**
185
+ * Maximum time for the complete listener registry to become ready. The same
186
+ * registration deadline bounds automatic rollback after startup failure.
187
+ * Defaults to 10 seconds.
188
+ */
189
+ readyTimeoutMs?: number;
145
190
  }
146
191
  /**
147
192
  * Context-bound listener helper factory.
@@ -181,12 +226,16 @@ export declare function parseEventPayload<E extends EventPayloadDef>(event: E, p
181
226
  */
182
227
  export declare function publishEvent<E extends EventPayloadDef>(eventBus: EventBusLike, event: E, payload: InferEventPayload<E>, options?: EventPublishOptions): Promise<void>;
183
228
  /**
184
- * Register listeners against an event bus and return an unsubscribe function.
229
+ * Register listeners against an event bus and return a composite lifecycle
230
+ * handle.
185
231
  *
186
232
  * Payloads are validated before listener handlers run. Listener context is
187
- * resolved per delivery when `options.ctx` is a factory.
233
+ * resolved per delivery when `options.ctx` is a factory. Initial registration
234
+ * starts every child cleanup after a synchronous subscribe failure, rejected
235
+ * readiness promise, or readiness timeout. Cleanup that cannot finish inside
236
+ * the registration deadline is reported without extending startup forever.
188
237
  */
189
- export declare function registerListeners<Ctx>(eventBus: EventBusLike, listeners: readonly ListenerDef<EventDef, Ctx>[], options?: RegisterListenersOptions<Ctx>): () => void;
238
+ export declare function registerListeners<Ctx>(eventBus: EventBusLike, listeners: readonly ListenerDef<EventDef, Ctx>[], options?: RegisterListenersOptions<Ctx>): EventSubscription;
190
239
  /**
191
240
  * Create listener helper methods bound to an application context type.
192
241
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,gBAAgB,IACtD,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,eAAe,CAC9B,IAAI,SAAS,MAAM,GAAG,MAAM,EAC5B,OAAO,SAAS,cAAc,GAAG,cAAc;IAE/C;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ,CACvB,IAAI,SAAS,MAAM,GAAG,MAAM,EAC5B,OAAO,SAAS,cAAc,GAAG,cAAc,CAC/C,SAAQ,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC;IACtC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,eAAe,IACrD,CAAC,CAAC,SAAS,CAAC,SAAS,gBAAgB,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC;AAEhF,kDAAkD;AAClD,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,OAAO,SAAS,cAAc;IAChE;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,QAAQ,EAAE,GAAG;IACzD;;OAEG;IACH,KAAK,EAAE,CAAC,CAAC;IACT;;OAEG;IACH,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC9B;;OAEG;IACH,GAAG,EAAE,GAAG,CAAC;CACV;AAED;;GAEG;AACH,MAAM,WAAW,WAAW,CAC1B,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAC7B,GAAG,GAAG,OAAO,EACb,IAAI,SAAS,MAAM,GAAG,MAAM;IAE5B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,QAAQ,EAAE,GAAG;IAC5D;;OAEG;IACH,KAAK,EAAE,CAAC,CAAC;IACT;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,OAAO,CAAC,CAAC,SAAS,eAAe,EAC/B,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC7B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,YAAY,CAAC,IAAI,CAAC,CAAC;IACtB;;OAEG;IACH,SAAS,CAAC,CAAC,SAAS,eAAe,EACjC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CACP,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC7B,OAAO,CAAC,EAAE,mBAAmB,KAC1B,YAAY,CAAC,IAAI,CAAC,GACtB,MAAM,IAAI,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB,CAAC,GAAG;IAC3C;;OAEG;IACH,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,GAAG;IAC5B;;OAEG;IACH,cAAc,CAAC,IAAI,SAAS,MAAM,EAAE,CAAC,SAAS,QAAQ,EACpD,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,GACrC,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,CAAC,KAAK,EAAE,CAAC;gBAEvC,IAAI,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,SAAS,gBAAgB,CAAC,KAAK,EAAE,CAAC;KAC3C;CAOF;AA4CD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,IAAI,SAAS,MAAM,EACnB,OAAO,SAAS,cAAc,EAC9B,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,kBAAkB,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAO3E;AAkBD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,SAAS,eAAe,EAC/D,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAI/B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,SAAS,eAAe,EAC1D,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC7B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EACnC,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,SAAS,WAAW,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,EAChD,OAAO,GAAE,wBAAwB,CAAC,GAAG,CAAM,GAC1C,MAAM,IAAI,CAuCZ;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,KAAK,SAAS,CAAC,GAAG,CAAC,CASrD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,46 @@
1
1
  import { runWithResolvedTracingContext } from "../tracing/execution.js";
2
2
  import { parseTraceCarrier, } from "../tracing/index.js";
3
+ const DEFAULT_LISTENER_READY_TIMEOUT_MS = 10_000;
4
+ const MAX_TIMER_MS = 2_147_483_647;
5
+ /** Error used when a subscription closes before initial readiness. */
6
+ export class EventSubscriptionClosedError extends Error {
7
+ constructor(message = "Event subscription closed before it became ready.") {
8
+ super(message);
9
+ this.name = "EventSubscriptionClosedError";
10
+ }
11
+ }
12
+ /** Error thrown when a listener registry misses its readiness deadline. */
13
+ export class ListenerRegistrationTimeoutError extends Error {
14
+ /** Configured readiness deadline in milliseconds. */
15
+ timeoutMs;
16
+ /** Listener names that were part of the registration. */
17
+ listenerNames;
18
+ constructor(args) {
19
+ const suffix = args.listenerNames.length
20
+ ? `: ${args.listenerNames.join(", ")}`
21
+ : "";
22
+ super(`Listeners did not become ready within ${args.timeoutMs}ms${suffix}.`);
23
+ this.name = "ListenerRegistrationTimeoutError";
24
+ this.timeoutMs = args.timeoutMs;
25
+ this.listenerNames = [...args.listenerNames];
26
+ }
27
+ }
28
+ /** Error thrown when listener rollback misses the registration deadline. */
29
+ export class ListenerRegistrationCleanupTimeoutError extends Error {
30
+ /** Configured registration deadline in milliseconds. */
31
+ timeoutMs;
32
+ /** Listener names that were part of the registration. */
33
+ listenerNames;
34
+ constructor(args) {
35
+ const suffix = args.listenerNames.length
36
+ ? `: ${args.listenerNames.join(", ")}`
37
+ : "";
38
+ super(`Listener cleanup did not finish before the ${args.timeoutMs}ms registration deadline${suffix}.`);
39
+ this.name = "ListenerRegistrationCleanupTimeoutError";
40
+ this.timeoutMs = args.timeoutMs;
41
+ this.listenerNames = [...args.listenerNames];
42
+ }
43
+ }
3
44
  /**
4
45
  * Error thrown when event payload validation fails.
5
46
  */
@@ -81,48 +122,158 @@ export async function publishEvent(eventBus, event, payload, options) {
81
122
  await parseEventPayload(event, payload);
82
123
  await eventBus.publish(event, payload, options);
83
124
  }
125
+ function assertReadyTimeoutMs(value) {
126
+ if (Number.isInteger(value) && value >= 1 && value <= MAX_TIMER_MS)
127
+ return;
128
+ throw new RangeError(`readyTimeoutMs must be an integer between 1 and ${MAX_TIMER_MS} milliseconds.`);
129
+ }
130
+ function errorsFromCleanup(error) {
131
+ return error instanceof AggregateError ? [...error.errors] : [error];
132
+ }
133
+ function unsubscribeAllSettled(subscriptions) {
134
+ const attempts = [];
135
+ for (const subscription of [...subscriptions].reverse()) {
136
+ try {
137
+ attempts.push(Promise.resolve(subscription.unsubscribe()));
138
+ }
139
+ catch (error) {
140
+ attempts.push(Promise.reject(error));
141
+ }
142
+ }
143
+ return Promise.allSettled(attempts);
144
+ }
145
+ function throwSubscriptionCleanupErrors(results) {
146
+ const errors = results.flatMap((result) => result.status === "rejected" ? errorsFromCleanup(result.reason) : []);
147
+ if (errors.length > 0) {
148
+ throw new AggregateError(errors, "Event subscription cleanup failed");
149
+ }
150
+ }
151
+ function withListenerDeadline(operation, args) {
152
+ let timeout;
153
+ const timedOut = new Promise((_, reject) => {
154
+ timeout = setTimeout(() => {
155
+ reject(args.timeoutError);
156
+ }, Math.max(0, args.deadlineAt - performance.now()));
157
+ });
158
+ return Promise.race([operation, timedOut]).finally(() => {
159
+ if (timeout !== undefined)
160
+ clearTimeout(timeout);
161
+ });
162
+ }
84
163
  /**
85
- * Register listeners against an event bus and return an unsubscribe function.
164
+ * Register listeners against an event bus and return a composite lifecycle
165
+ * handle.
86
166
  *
87
167
  * Payloads are validated before listener handlers run. Listener context is
88
- * resolved per delivery when `options.ctx` is a factory.
168
+ * resolved per delivery when `options.ctx` is a factory. Initial registration
169
+ * starts every child cleanup after a synchronous subscribe failure, rejected
170
+ * readiness promise, or readiness timeout. Cleanup that cannot finish inside
171
+ * the registration deadline is reported without extending startup forever.
89
172
  */
90
173
  export function registerListeners(eventBus, listeners, options = {}) {
91
- const unsubscribes = listeners.map((listener) => eventBus.subscribe(listener.event, async (rawPayload, publishOptions) => {
174
+ const readyTimeoutMs = options.readyTimeoutMs ?? DEFAULT_LISTENER_READY_TIMEOUT_MS;
175
+ assertReadyTimeoutMs(readyTimeoutMs);
176
+ const registrationDeadlineAt = performance.now() + readyTimeoutMs;
177
+ const listenerNames = listeners.map(({ name }) => name);
178
+ const subscriptions = [];
179
+ let registrationError;
180
+ for (const listener of listeners) {
92
181
  try {
93
- const payload = await parseEventPayload(listener.event, rawPayload);
94
- const traceAttributes = {
95
- "beignet.listener.name": listener.name,
96
- "beignet.event.name": listener.event.name,
97
- };
98
- await runWithResolvedTracingContext({
99
- tracing: options.tracing,
100
- ctx: options.ctx,
101
- operation: {
102
- name: `beignet.listener ${listener.name}`,
103
- type: "listener",
104
- kind: "consumer",
105
- parent: parseTraceCarrier(publishOptions?.trace),
106
- attributes: traceAttributes,
107
- metricAttributes: traceAttributes,
108
- },
109
- run: (ctx) => listener.handle({
110
- event: listener.event,
111
- payload,
112
- ctx,
113
- }),
114
- });
182
+ subscriptions.push(eventBus.subscribe(listener.event, async (rawPayload, publishOptions) => {
183
+ try {
184
+ const payload = await parseEventPayload(listener.event, rawPayload);
185
+ const traceAttributes = {
186
+ "beignet.listener.name": listener.name,
187
+ "beignet.event.name": listener.event.name,
188
+ };
189
+ await runWithResolvedTracingContext({
190
+ tracing: options.tracing,
191
+ ctx: options.ctx,
192
+ operation: {
193
+ name: `beignet.listener ${listener.name}`,
194
+ type: "listener",
195
+ kind: "consumer",
196
+ parent: parseTraceCarrier(publishOptions?.trace),
197
+ attributes: traceAttributes,
198
+ metricAttributes: traceAttributes,
199
+ },
200
+ run: (ctx) => listener.handle({
201
+ event: listener.event,
202
+ payload,
203
+ ctx,
204
+ }),
205
+ });
206
+ }
207
+ catch (error) {
208
+ options.onError?.(error, listener);
209
+ if (!options.onError)
210
+ throw error;
211
+ }
212
+ }));
115
213
  }
116
214
  catch (error) {
117
- options.onError?.(error, listener);
118
- if (!options.onError)
119
- throw error;
215
+ registrationError = error;
216
+ break;
120
217
  }
121
- }));
122
- return () => {
123
- for (const unsubscribe of [...unsubscribes].reverse()) {
124
- unsubscribe();
218
+ }
219
+ let rejectClosed;
220
+ const closedBeforeReady = new Promise((_, reject) => {
221
+ rejectClosed = reject;
222
+ });
223
+ // A consumer may only await cleanup. Keep an explicit observer on the
224
+ // cancellation signal so that use does not create an unhandled rejection.
225
+ void closedBeforeReady.catch(() => undefined);
226
+ let cleanupPromise;
227
+ const cleanup = (deadlineAt) => {
228
+ if (cleanupPromise)
229
+ return cleanupPromise;
230
+ const operation = unsubscribeAllSettled(subscriptions);
231
+ cleanupPromise =
232
+ deadlineAt === undefined
233
+ ? operation.then(throwSubscriptionCleanupErrors)
234
+ : withListenerDeadline(operation, {
235
+ deadlineAt,
236
+ timeoutError: new ListenerRegistrationCleanupTimeoutError({
237
+ timeoutMs: readyTimeoutMs,
238
+ listenerNames,
239
+ }),
240
+ }).then(throwSubscriptionCleanupErrors);
241
+ return cleanupPromise;
242
+ };
243
+ const initialReadiness = registrationError
244
+ ? Promise.reject(registrationError)
245
+ : Promise.all(subscriptions.map(({ ready }) => ready)).then(() => undefined);
246
+ let readySettled = false;
247
+ const ready = withListenerDeadline(Promise.race([initialReadiness, closedBeforeReady]), {
248
+ deadlineAt: registrationDeadlineAt,
249
+ timeoutError: new ListenerRegistrationTimeoutError({
250
+ timeoutMs: readyTimeoutMs,
251
+ listenerNames,
252
+ }),
253
+ })
254
+ .catch(async (primaryError) => {
255
+ try {
256
+ await cleanup(registrationDeadlineAt);
257
+ }
258
+ catch (cleanupError) {
259
+ throw new AggregateError([primaryError, ...errorsFromCleanup(cleanupError)], "Listener registration failed and cleanup failed");
125
260
  }
261
+ throw primaryError;
262
+ })
263
+ .finally(() => {
264
+ readySettled = true;
265
+ });
266
+ // EventSubscription allows callers that only own cleanup. Preserve the
267
+ // rejection for awaiters while preventing process-level unhandled noise.
268
+ void ready.catch(() => undefined);
269
+ return {
270
+ ready,
271
+ unsubscribe() {
272
+ if (!readySettled) {
273
+ rejectClosed(new EventSubscriptionClosedError());
274
+ }
275
+ return cleanup(readySettled ? undefined : registrationDeadlineAt);
276
+ },
126
277
  };
127
278
  }
128
279
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,iBAAiB,GAGlB,MAAM,qBAAqB,CAAC;AAiM7B;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C;;OAEG;IACM,MAAM,CAAoC;IAEnD,YAAY,IAGX;QACC,KAAK,CACH,UAAU,IAAI,CAAC,IAAI,gCAAgC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAC/E,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5B,CAAC;CACF;AAED,SAAS,UAAU,CAAC,IAAoC;IACtD,IAAI,CAAC,IAAI,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC;IAE7B,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACf,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,IAAI,OAAO;QACjE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;QACrB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CACpB;SACA,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,MAAyC;IAC7D,OAAO,MAAM;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAC5D,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,MAAc,EACd,KAAc,EACd,IAAsB;IAEtB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEzD,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,oBAAoB,CAAC;YAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC,KAAkC,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAGzB,IAAU,EAAE,OAAoC;IAChD,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI;QACJ,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAKzB,IAAU,EACV,OAAsC;IAEtC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,IAAI;QACJ,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAQ,EACR,OAAgB;IAEhB,OAAO,CAAC,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE;QACjD,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC,CAAyB,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAsB,EACtB,KAAQ,EACR,OAA6B,EAC7B,OAA6B;IAE7B,MAAM,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAsB,EACtB,SAAgD,EAChD,UAAyC,EAAE;IAE3C,MAAM,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC9C,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,EAAE;QACtE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YACpE,MAAM,eAAe,GAAG;gBACtB,uBAAuB,EAAE,QAAQ,CAAC,IAAI;gBACtC,oBAAoB,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI;aACjC,CAAC;YACX,MAAM,6BAA6B,CAAC;gBAClC,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,GAAG,EAAE,OAAO,CAAC,GAAsC;gBACnD,SAAS,EAAE;oBACT,IAAI,EAAE,oBAAoB,QAAQ,CAAC,IAAI,EAAE;oBACzC,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,iBAAiB,CAAC,cAAc,EAAE,KAAK,CAAC;oBAChD,UAAU,EAAE,eAAe;oBAC3B,gBAAgB,EAAE,eAAe;iBAClC;gBACD,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CACX,QAAQ,CAAC,MAAM,CAAC;oBACd,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,OAAO;oBACP,GAAG;iBACJ,CAAC;aACL,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACnC,IAAI,CAAC,OAAO,CAAC,OAAO;gBAAE,MAAM,KAAK,CAAC;QACpC,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,GAAG,EAAE;QACV,KAAK,MAAM,WAAW,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YACtD,WAAW,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,cAAc,CACZ,IAAU,EACV,OAAsC;YAEtC,OAAO,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"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"}
@@ -410,9 +410,13 @@ export declare function runIdempotently<Result>(idempotency: IdempotencyPort, op
410
410
  /**
411
411
  * Create a SHA-256 fingerprint from a canonicalized value.
412
412
  *
413
- * Object keys are sorted, `undefined` and functions are omitted, `Date` values
414
- * become ISO strings, BigInts become strings, and circular or non-finite values
415
- * throw. Exact omit paths may be supplied as dotted strings or string arrays.
413
+ * Object keys are sorted, while non-JSON values carry reserved type tags so
414
+ * BigInts and Dates cannot collide with same-looking strings. Ordinary JSON
415
+ * inputs retain their existing canonical representation. `undefined` values
416
+ * and functions are omitted from objects and represented as omitted array
417
+ * positions. Circular or unsupported object values, reserved tag keys,
418
+ * invalid dates, and non-finite numbers throw. Exact omit paths may be supplied
419
+ * as dotted strings or string arrays.
416
420
  */
417
421
  export declare function createIdempotencyFingerprint(value: unknown, options?: CreateIdempotencyFingerprintOptions): Promise<string>;
418
422
  //# sourceMappingURL=index.d.ts.map