opinionated-machine 10.5.0 → 11.2.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 (63) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +513 -52
  3. package/dist/lib/DIContext.d.ts +13 -1
  4. package/dist/lib/DIContext.js +28 -8
  5. package/dist/lib/DIContext.js.map +1 -1
  6. package/dist/lib/api-contracts/apiRouteBuilder.d.ts +47 -5
  7. package/dist/lib/api-contracts/apiRouteBuilder.js +57 -8
  8. package/dist/lib/api-contracts/apiRouteBuilder.js.map +1 -1
  9. package/dist/lib/api-contracts/apiSseConnectionRegistry.d.ts +182 -0
  10. package/dist/lib/api-contracts/apiSseConnectionRegistry.js +332 -0
  11. package/dist/lib/api-contracts/apiSseConnectionRegistry.js.map +1 -0
  12. package/dist/lib/api-contracts/index.d.ts +1 -0
  13. package/dist/lib/api-contracts/index.js +1 -0
  14. package/dist/lib/api-contracts/index.js.map +1 -1
  15. package/dist/lib/gateway/gatewayMetadata.d.ts +1 -0
  16. package/dist/lib/gateway/gatewayMetadata.js +11 -0
  17. package/dist/lib/gateway/gatewayMetadata.js.map +1 -1
  18. package/dist/lib/gateway/index.d.ts +1 -0
  19. package/dist/lib/gateway/index.js +1 -0
  20. package/dist/lib/gateway/index.js.map +1 -1
  21. package/dist/lib/gateway/manifest/buildManifest.d.ts +18 -0
  22. package/dist/lib/gateway/manifest/buildManifest.js +31 -0
  23. package/dist/lib/gateway/manifest/buildManifest.js.map +1 -1
  24. package/dist/lib/gateway/manifest/manifestSchema.d.ts +18 -0
  25. package/dist/lib/gateway/manifest/manifestSchema.js +27 -0
  26. package/dist/lib/gateway/manifest/manifestSchema.js.map +1 -1
  27. package/dist/lib/gateway/routeStreaming.d.ts +79 -0
  28. package/dist/lib/gateway/routeStreaming.js +70 -0
  29. package/dist/lib/gateway/routeStreaming.js.map +1 -0
  30. package/dist/lib/resolverFunctions.d.ts +7 -0
  31. package/dist/lib/resolverFunctions.js +13 -0
  32. package/dist/lib/resolverFunctions.js.map +1 -1
  33. package/dist/lib/routes/fastifyRouteBuilder.js +9 -2
  34. package/dist/lib/routes/fastifyRouteBuilder.js.map +1 -1
  35. package/dist/lib/sse/AbstractSSEController.d.ts +10 -0
  36. package/dist/lib/sse/AbstractSSEController.js +9 -0
  37. package/dist/lib/sse/AbstractSSEController.js.map +1 -1
  38. package/dist/lib/sse/eventIds.d.ts +138 -0
  39. package/dist/lib/sse/eventIds.js +155 -0
  40. package/dist/lib/sse/eventIds.js.map +1 -0
  41. package/dist/lib/sse/index.d.ts +3 -2
  42. package/dist/lib/sse/index.js +6 -2
  43. package/dist/lib/sse/index.js.map +1 -1
  44. package/dist/lib/sse/rooms/SSERoomEventPublisher.d.ts +121 -0
  45. package/dist/lib/sse/rooms/SSERoomEventPublisher.js +119 -0
  46. package/dist/lib/sse/rooms/SSERoomEventPublisher.js.map +1 -0
  47. package/dist/lib/sse/rooms/index.d.ts +1 -0
  48. package/dist/lib/sse/rooms/index.js +1 -0
  49. package/dist/lib/sse/rooms/index.js.map +1 -1
  50. package/dist/lib/testing/apiSseEventValidation.d.ts +1 -1
  51. package/dist/lib/testing/apiSseInjectHelpers.js +9 -10
  52. package/dist/lib/testing/apiSseInjectHelpers.js.map +1 -1
  53. package/dist/lib/testing/sseHttpClient.d.ts +10 -2
  54. package/dist/lib/testing/sseHttpClient.js +13 -6
  55. package/dist/lib/testing/sseHttpClient.js.map +1 -1
  56. package/dist/lib/testing/sseInjectClient.d.ts +1 -1
  57. package/dist/lib/testing/sseInjectClient.js +1 -1
  58. package/dist/lib/testing/sseInjectClient.js.map +1 -1
  59. package/dist/lib/testing/sseTestTypes.d.ts +1 -1
  60. package/package.json +13 -13
  61. package/dist/lib/sse/sseParser.d.ts +0 -167
  62. package/dist/lib/sse/sseParser.js +0 -225
  63. package/dist/lib/sse/sseParser.js.map +0 -1
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Monotonic event-id helpers for SSE streams.
3
+ *
4
+ * The polling-fallback pattern (and `Last-Event-ID` reconnection/replay in
5
+ * general) needs event ids a client can ORDER, not just deduplicate: the
6
+ * client keeps a high-watermark and drops anything at or below it. Random
7
+ * UUIDs (the `broadcastToRoom` default) are unique but unordered; use a
8
+ * sequence from {@link createEventIdSequence} instead and pass its ids
9
+ * explicitly:
10
+ *
11
+ * ```ts
12
+ * const seq = createEventIdSequence()
13
+ * await broadcaster.broadcastToRoom(room, statusEvent, data, { id: seq.next() })
14
+ * ```
15
+ *
16
+ * Keep one sequence per ordering scope (per room, per resource, per stream) —
17
+ * ids from different scopes are not comparable. Stamp the same underlying
18
+ * version into the sync (poll) response body so the client can order
19
+ * snapshots against events.
20
+ *
21
+ * ## Choosing an id source
22
+ *
23
+ * Prefer a **domain version** (`job.version`, a revision column, an updated-at
24
+ * revision counter) over a generated sequence whenever the resource has one.
25
+ * A domain version is per-scope and writer-independent: any pod that writes the
26
+ * resource reads the same version, and the same number is already what the
27
+ * snapshot body has to carry for the client's version gate. Use
28
+ * {@link createEventIdSequence} when the resource has no version of its own.
29
+ *
30
+ * ## Hazard: per-process sequences are single-writer only
31
+ *
32
+ * {@link createEventIdSequence} is in-memory and per-process. Its epoch
33
+ * defaults to the process start time, and the client's default extractor
34
+ * orders by epoch first. That is safe only when a single writer owns the
35
+ * ordering scope.
36
+ *
37
+ * If two pods of the same service broadcast into the same room, each with its
38
+ * own per-process sequence, their epochs differ. The events interleave, the
39
+ * client's high-watermark lands on the newer epoch, and every subsequent event
40
+ * from the older-epoch pod compares as stale and is **silently dropped**. The
41
+ * failure only appears under horizontal scale, so it reaches production.
42
+ *
43
+ * For a multi-writer scope use one of:
44
+ *
45
+ * - a domain version (see above), or
46
+ * - a shared counter, e.g. `createRedisEventIdSequence()` from
47
+ * `@opinionated-machine/sse-rooms-redis`, which backs the counter with
48
+ * Redis `INCR` and shares one epoch across pods, or
49
+ * - a fixed `epoch` plus a `start` handed out from shared storage, so every
50
+ * writer contributes to a single ordered run.
51
+ */
52
+ /**
53
+ * Epochs are digits only, and so are counters.
54
+ *
55
+ * The client's default version extractor (`@opinionated-machine/sse-fallback`)
56
+ * has to tell a generated id apart from any other id shape a stream might
57
+ * carry, and a UUID matches `<anything>-<digits>` too — ordering events by a
58
+ * chunk of a UUID drops them at random. Restricting the epoch to digits is what
59
+ * makes `<digits>-<digits>` an unambiguous marker, so every id these helpers
60
+ * produce is one that extractor can order. Any other id scheme needs
61
+ * `version.ofEvent` declared on the client.
62
+ */
63
+ const NUMERIC_EPOCH_PATTERN = /^\d+$/;
64
+ const COUNTER_PAD = 12;
65
+ /**
66
+ * Largest counter value that still fits in {@link COUNTER_PAD} digits. Beyond
67
+ * this the id grows a digit and stops sorting after its predecessor, so
68
+ * {@link createEventIdSequence} refuses to produce it.
69
+ */
70
+ export const MAX_EVENT_ID_COUNTER = 999_999_999_999;
71
+ /**
72
+ * Create a monotonic event-id sequence.
73
+ *
74
+ * Ids look like `"1754838000000-000000000042"`. Within one epoch they order
75
+ * lexicographically (fixed-width zero-padded counter).
76
+ *
77
+ * Sequences are in-memory and per-process, which makes them safe only for a
78
+ * single-writer ordering scope. See the module docs for the multi-writer
79
+ * hazard and the alternatives (domain versions, or a Redis-backed sequence).
80
+ *
81
+ * @throws TypeError if `epoch` is not a string of digits, or if `start` is not
82
+ * an integer in `[0, MAX_EVENT_ID_COUNTER - 1]`.
83
+ */
84
+ export function createEventIdSequence(options) {
85
+ const epoch = options?.epoch ?? String(Date.now());
86
+ if (!NUMERIC_EPOCH_PATTERN.test(epoch)) {
87
+ throw new TypeError(`createEventIdSequence: \`epoch\` must be a non-empty string of digits, got "${epoch}"`);
88
+ }
89
+ const start = options?.start ?? 0;
90
+ if (!Number.isInteger(start) || start < 0 || start >= MAX_EVENT_ID_COUNTER) {
91
+ throw new TypeError(`createEventIdSequence: \`start\` must be an integer in [0, ${MAX_EVENT_ID_COUNTER - 1}], got ${String(start)}`);
92
+ }
93
+ let counter = start;
94
+ let current;
95
+ return {
96
+ next() {
97
+ if (counter >= MAX_EVENT_ID_COUNTER) {
98
+ throw new RangeError(`createEventIdSequence: counter exhausted at ${MAX_EVENT_ID_COUNTER}; start a new epoch`);
99
+ }
100
+ counter += 1;
101
+ current = `${epoch}-${String(counter).padStart(COUNTER_PAD, '0')}`;
102
+ return current;
103
+ },
104
+ get current() {
105
+ return current;
106
+ },
107
+ };
108
+ }
109
+ const EVENT_ID_PATTERN = /^(\d+)-(\d+)$/;
110
+ /**
111
+ * Compare two event ids produced by {@link createEventIdSequence}.
112
+ *
113
+ * Returns `-1` / `0` / `1` when both ids belong to the same epoch, and
114
+ * `undefined` when they don't (or when either id doesn't match the expected
115
+ * format). An `undefined` result means the ids are not ordered relative to
116
+ * each other — clients should treat that as "resynchronize via a snapshot
117
+ * poll" rather than guess.
118
+ */
119
+ export function compareEventIds(a, b) {
120
+ const parsedA = EVENT_ID_PATTERN.exec(a);
121
+ const parsedB = EVENT_ID_PATTERN.exec(b);
122
+ if (!parsedA || !parsedB)
123
+ return undefined;
124
+ if (parsedA[1] !== parsedB[1])
125
+ return undefined;
126
+ const counterA = BigInt(parsedA[2]);
127
+ const counterB = BigInt(parsedB[2]);
128
+ if (counterA < counterB)
129
+ return -1;
130
+ if (counterA > counterB)
131
+ return 1;
132
+ return 0;
133
+ }
134
+ /**
135
+ * Format a counter value as an event id in the shape
136
+ * {@link createEventIdSequence} produces, so ids from a shared counter compare
137
+ * against ids from an in-process sequence with the same epoch.
138
+ *
139
+ * @throws TypeError if `epoch` is not a string of digits.
140
+ * `createEventIdSequence()` refuses the same input: an id whose epoch is
141
+ * empty (`"-000000000001"`) or free-form is one {@link compareEventIds}
142
+ * cannot parse, so nothing downstream can order it.
143
+ * @throws RangeError if the counter does not fit the fixed id width.
144
+ */
145
+ export function formatEventId(epoch, counter) {
146
+ if (!NUMERIC_EPOCH_PATTERN.test(epoch)) {
147
+ throw new TypeError(`formatEventId: \`epoch\` must be a non-empty string of digits, got "${epoch}"`);
148
+ }
149
+ const asBigInt = typeof counter === 'bigint' ? counter : BigInt(counter);
150
+ if (asBigInt < 1n || asBigInt > BigInt(MAX_EVENT_ID_COUNTER)) {
151
+ throw new RangeError(`formatEventId: counter must be in [1, ${MAX_EVENT_ID_COUNTER}], got ${String(counter)}`);
152
+ }
153
+ return `${epoch}-${asBigInt.toString().padStart(COUNTER_PAD, '0')}`;
154
+ }
155
+ //# sourceMappingURL=eventIds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventIds.js","sourceRoot":"","sources":["../../../lib/sse/eventIds.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  export type { AllContractEventNames, AllContractEvents, AnySSEContractDefinition, ExtractEventSchema, SSEContractDefinition, SSEEventSchemas, SSEMethod, } from '@lokalise/api-contracts';
2
+ export { createSSEStreamParser, type ParsedSSEEvent, type ParseSSEBufferResult, type ParseSSEStreamOptions, parseSSEBuffer, parseSSEEvents, parseSSEResponse, parseSSEStream, type SSEResponseLike, type SSEStreamParser, type SSEStreamParserOptions, } from '@opinionated-machine/sse-parser';
2
3
  export { type BuildFastifySSERoutesReturnType, buildFastifyRoute, buildHandler, type FastifySSEHandlerConfig, type FastifySSEPreHandler, type FastifySSERouteOptions, type InferSSERequest, type RegisterSSERoutesOptions, type SSEContext, type SSEOnlyHandlers, type SSERouteHandler, type SSESession, } from '../routes/index.js';
3
4
  export { AbstractSSEController, type SSEControllerConfig, type SSEEventSender, type SSELogger, type SSEMessage, } from './AbstractSSEController.js';
4
5
  export { defineEvent, type SSEEventDefinition } from './defineEvent.js';
5
- export { defineRoom, InMemoryAdapter, type PreDeliveryFilter, type RoomBroadcastOptions, type RoomNameResolver, type SSERoomAdapter, SSERoomBroadcaster, SSERoomManager, type SSERoomManagerConfig, type SSERoomMessageHandler, type SSERoomOperations, } from './rooms/index.js';
6
+ export { type AsyncEventIdSequence, type CreateEventIdSequenceOptions, compareEventIds, createEventIdSequence, type EventIdSequence, formatEventId, MAX_EVENT_ID_COUNTER, } from './eventIds.js';
7
+ export { defineRoom, InMemoryAdapter, type PreDeliveryFilter, type RoomBroadcastOptions, type RoomNameResolver, type SSELogContext, type SSERoomAdapter, SSERoomBroadcaster, SSERoomEventPublisher, type SSERoomEventPublisherDependencies, type SSERoomEventPublishOptions, SSERoomManager, type SSERoomManagerConfig, type SSERoomMessageHandler, type SSERoomOperations, } from './rooms/index.js';
6
8
  export { type SpiedSSESession, type SSESessionEvent, SSESessionSpy } from './SSESessionSpy.js';
7
- export { type ParsedSSEEvent, type ParseSSEBufferResult, parseSSEBuffer, parseSSEEvents, } from './sseParser.js';
8
9
  export { SSE_DIAGNOSTICS_HEADER, type SSEDiagnosticsScope, type SSESendFailure, } from './sseSendDiagnostics.js';
9
10
  export { defineEventMetadata, type ExtractMetadata, type FilterVerdict, type IncomingEvent, type MetadataGuard, type MetadataGuards, type PublishResult, type ResolverResult, SSESubscriptionManager, type SSESubscriptionManagerConfig, type SubscriptionContext, type SubscriptionPolicy, type SubscriptionResolver, } from './subscriptions/index.js';
@@ -1,11 +1,15 @@
1
+ // The wire-format parser lives in its own package so that the browser client
2
+ // (@opinionated-machine/sse-fallback) frames the stream with the same code the
3
+ // server's test helpers do.
4
+ export { createSSEStreamParser, parseSSEBuffer, parseSSEEvents, parseSSEResponse, parseSSEStream, } from '@opinionated-machine/sse-parser';
1
5
  // Re-export route types from routes module
2
6
  export { buildFastifyRoute, buildHandler, } from '../routes/index.js';
3
7
  export { AbstractSSEController, } from './AbstractSSEController.js';
4
8
  export { defineEvent } from './defineEvent.js';
9
+ export { compareEventIds, createEventIdSequence, formatEventId, MAX_EVENT_ID_COUNTER, } from './eventIds.js';
5
10
  // Re-export room types and classes
6
- export { defineRoom, InMemoryAdapter, SSERoomBroadcaster, SSERoomManager, } from './rooms/index.js';
11
+ export { defineRoom, InMemoryAdapter, SSERoomBroadcaster, SSERoomEventPublisher, SSERoomManager, } from './rooms/index.js';
7
12
  export { SSESessionSpy } from './SSESessionSpy.js';
8
- export { parseSSEBuffer, parseSSEEvents, } from './sseParser.js';
9
13
  export { SSE_DIAGNOSTICS_HEADER, } from './sseSendDiagnostics.js';
10
14
  // SSE Subscriptions
11
15
  export { defineEventMetadata, SSESubscriptionManager, } from './subscriptions/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/sse/index.ts"],"names":[],"mappings":"AAUA,2CAA2C;AAC3C,OAAO,EAEL,iBAAiB,EACjB,YAAY,GAUb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,qBAAqB,GAKtB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,WAAW,EAA2B,MAAM,kBAAkB,CAAA;AACvE,mCAAmC;AACnC,OAAO,EACL,UAAU,EACV,eAAe,EAKf,kBAAkB,EAClB,cAAc,GAIf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAA8C,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAC9F,OAAO,EAGL,cAAc,EACd,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,sBAAsB,GAGvB,MAAM,yBAAyB,CAAA;AAChC,oBAAoB;AACpB,OAAO,EACL,mBAAmB,EAQnB,sBAAsB,GAKvB,MAAM,0BAA0B,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/sse/index.ts"],"names":[],"mappings":"AAUA,6EAA6E;AAC7E,+EAA+E;AAC/E,4BAA4B;AAC5B,OAAO,EACL,qBAAqB,EAIrB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,cAAc,GAIf,MAAM,iCAAiC,CAAA;AACxC,2CAA2C;AAC3C,OAAO,EAEL,iBAAiB,EACjB,YAAY,GAUb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,qBAAqB,GAKtB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,WAAW,EAA2B,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAGL,eAAe,EACf,qBAAqB,EAErB,aAAa,EACb,oBAAoB,GACrB,MAAM,eAAe,CAAA;AACtB,mCAAmC;AACnC,OAAO,EACL,UAAU,EACV,eAAe,EAMf,kBAAkB,EAClB,qBAAqB,EAGrB,cAAc,GAIf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAA8C,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAC9F,OAAO,EACL,sBAAsB,GAGvB,MAAM,yBAAyB,CAAA;AAChC,oBAAoB;AACpB,OAAO,EACL,mBAAmB,EAQnB,sBAAsB,GAKvB,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,121 @@
1
+ import { type Either, InternalError } from '@lokalise/node-core';
2
+ import type { z } from 'zod';
3
+ import type { SSEEventDefinition } from '../defineEvent.js';
4
+ import type { SSELogger } from '../sseTypes.js';
5
+ import type { SSERoomBroadcaster } from './SSERoomBroadcaster.js';
6
+ import type { RoomBroadcastOptions } from './types.js';
7
+ export type SSERoomEventPublisherDependencies = {
8
+ sseRoomBroadcaster: SSERoomBroadcaster;
9
+ logger: SSELogger;
10
+ };
11
+ /**
12
+ * Whatever the caller is working on behalf of, narrowed to the one thing the publisher needs
13
+ * from it. `@lokalise/fastify-extras`' `RequestContext` satisfies this structurally, as does a
14
+ * job or consumer context of your own, so neither this package nor its callers need an adapter.
15
+ */
16
+ export type SSELogContext = {
17
+ logger: SSELogger;
18
+ };
19
+ /**
20
+ * Everything {@link SSERoomBroadcaster.broadcastToRoom} accepts, so the publisher is not a lossy
21
+ * wrapper over it.
22
+ */
23
+ export type SSERoomEventPublishOptions = RoomBroadcastOptions & {
24
+ /**
25
+ * The SSE `id:` put on the wire. Defaults to a random UUID. Set it to a value a client can
26
+ * order, such as the sequence from `createEventIdSequence()`, when consumers deduplicate or
27
+ * resume by event id.
28
+ */
29
+ id?: string;
30
+ /** The SSE `retry:` hint, in milliseconds: how long a client waits before reconnecting. */
31
+ retry?: number;
32
+ /**
33
+ * Per-broadcast context handed to the pre-delivery filter, and to other nodes alongside the
34
+ * message. Only a filter reads it (`SSESubscriptionManager` installs one to evaluate its
35
+ * resolver pipeline), so it is redundant unless one is installed.
36
+ */
37
+ metadata?: Record<string, unknown>;
38
+ };
39
+ /**
40
+ * Fire-and-forget broadcasting for domain code: a room event goes out and the caller does not
41
+ * await the fan-out.
42
+ *
43
+ * The typical producer is an event listener or a message handler whose primary work has already
44
+ * committed. It cannot retry a dropped hint, and awaiting the fan-out would tie its latency to
45
+ * the number of open connections. Code that needs the delivered count, or that can act on a
46
+ * delivery failure, should use {@link SSERoomBroadcaster} directly.
47
+ *
48
+ * The two ways publishing fails are treated differently, because they are different kinds of
49
+ * problem:
50
+ *
51
+ * - **A payload that violates its own event schema is a bug in the producer.** Nobody receives
52
+ * the event, so swallowing it means believing you published something you did not.
53
+ * {@link publish} throws. {@link safePublish} returns the error instead, for a caller that
54
+ * cannot absorb a throw.
55
+ * - **A failed broadcast is the world's problem**, and no caller here can retry it, so both
56
+ * methods log it. It also happens after the call has returned, which is why neither method can
57
+ * report it in a return value.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * // In your DI module
62
+ * sseRoomEventPublisher: asSingletonClass(SSERoomEventPublisher),
63
+ *
64
+ * // In a listener. `requestContext` is passed straight through: the publisher reads its
65
+ * // logger, so a dropped event carries the correlation id of whatever produced it.
66
+ * this.publisher.publish(
67
+ * ProjectSse.roomResolver(projectId),
68
+ * ProjectSse.events.updated,
69
+ * payload,
70
+ * requestContext,
71
+ * )
72
+ * ```
73
+ */
74
+ export declare class SSERoomEventPublisher {
75
+ private readonly sseRoomBroadcaster;
76
+ private readonly logger;
77
+ constructor({ sseRoomBroadcaster, logger }: SSERoomEventPublisherDependencies);
78
+ /**
79
+ * Validate `data` against the event's own schema and broadcast it to `room`, throwing if it
80
+ * fails.
81
+ *
82
+ * Validating here rather than leaving it to delivery is what makes the throw possible at all.
83
+ * Delivery-time validation runs once per connection, so it reports a mismatch once per open
84
+ * connection on every node, names the event but not the code that produced it, and does not
85
+ * run at all when nobody has joined the room. By then the call has long returned and there is
86
+ * nothing left to throw to.
87
+ *
88
+ * What goes on the wire is the parsed value, so a schema default is filled in once here
89
+ * instead of being left to every client. Delivery-time validation discards its own result and
90
+ * serializes what it was handed, so calling {@link SSERoomBroadcaster.broadcastToRoom}
91
+ * directly sends the unparsed input.
92
+ *
93
+ * `context` is whatever the caller is acting on behalf of; only its logger is read, so a
94
+ * request context goes in as-is. Omit it in a caller that has none and the injected logger is
95
+ * used, which costs a logged failure its correlation id and nothing else.
96
+ *
97
+ * @throws {InternalError} if `data` does not satisfy the event's schema.
98
+ */
99
+ publish<T extends z.ZodType>(room: string | string[], event: SSEEventDefinition<string, T>, data: z.input<T>, context?: SSELogContext, options?: SSERoomEventPublishOptions): void;
100
+ /**
101
+ * {@link publish}, but a payload that fails its schema comes back as an error instead of being
102
+ * thrown.
103
+ *
104
+ * For a producer that cannot absorb a throw: a message handler whose primary work has already
105
+ * committed would be retried in full and redo it, and the retry cannot succeed anyway, since a
106
+ * malformed payload fails the same way every time. Prefer {@link publish} everywhere else.
107
+ *
108
+ * The failure is logged as well as returned, so a caller that ignores the result still leaves
109
+ * a trace rather than silence.
110
+ *
111
+ * @returns `{ result: true }` once the payload has been validated and handed to the
112
+ * broadcaster. That is acceptance, not delivery: the fan-out has not happened yet, and its
113
+ * own failure is logged rather than returned.
114
+ */
115
+ safePublish<T extends z.ZodType>(room: string | string[], event: SSEEventDefinition<string, T>, data: z.input<T>, context?: SSELogContext, options?: SSERoomEventPublishOptions): Either<InternalError, true>;
116
+ /**
117
+ * The shared tail of both methods. A failed broadcast is logged rather than surfaced: it
118
+ * happens after the caller has returned, and none of these callers could retry it anyway.
119
+ */
120
+ private broadcast;
121
+ }
@@ -0,0 +1,119 @@
1
+ import { InternalError } from '@lokalise/node-core';
2
+ /** The same error either way, so a caller switching between the two methods sees one shape. */
3
+ const validationError = (room, event, error) => new InternalError({
4
+ message: `SSE event validation failed for event "${event}": ${error.message}`,
5
+ errorCode: 'SSE_EVENT_VALIDATION_FAILED',
6
+ details: { room: Array.isArray(room) ? room.join(',') : room, event },
7
+ });
8
+ /**
9
+ * Fire-and-forget broadcasting for domain code: a room event goes out and the caller does not
10
+ * await the fan-out.
11
+ *
12
+ * The typical producer is an event listener or a message handler whose primary work has already
13
+ * committed. It cannot retry a dropped hint, and awaiting the fan-out would tie its latency to
14
+ * the number of open connections. Code that needs the delivered count, or that can act on a
15
+ * delivery failure, should use {@link SSERoomBroadcaster} directly.
16
+ *
17
+ * The two ways publishing fails are treated differently, because they are different kinds of
18
+ * problem:
19
+ *
20
+ * - **A payload that violates its own event schema is a bug in the producer.** Nobody receives
21
+ * the event, so swallowing it means believing you published something you did not.
22
+ * {@link publish} throws. {@link safePublish} returns the error instead, for a caller that
23
+ * cannot absorb a throw.
24
+ * - **A failed broadcast is the world's problem**, and no caller here can retry it, so both
25
+ * methods log it. It also happens after the call has returned, which is why neither method can
26
+ * report it in a return value.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * // In your DI module
31
+ * sseRoomEventPublisher: asSingletonClass(SSERoomEventPublisher),
32
+ *
33
+ * // In a listener. `requestContext` is passed straight through: the publisher reads its
34
+ * // logger, so a dropped event carries the correlation id of whatever produced it.
35
+ * this.publisher.publish(
36
+ * ProjectSse.roomResolver(projectId),
37
+ * ProjectSse.events.updated,
38
+ * payload,
39
+ * requestContext,
40
+ * )
41
+ * ```
42
+ */
43
+ export class SSERoomEventPublisher {
44
+ sseRoomBroadcaster;
45
+ logger;
46
+ constructor({ sseRoomBroadcaster, logger }) {
47
+ this.sseRoomBroadcaster = sseRoomBroadcaster;
48
+ this.logger = logger;
49
+ }
50
+ /**
51
+ * Validate `data` against the event's own schema and broadcast it to `room`, throwing if it
52
+ * fails.
53
+ *
54
+ * Validating here rather than leaving it to delivery is what makes the throw possible at all.
55
+ * Delivery-time validation runs once per connection, so it reports a mismatch once per open
56
+ * connection on every node, names the event but not the code that produced it, and does not
57
+ * run at all when nobody has joined the room. By then the call has long returned and there is
58
+ * nothing left to throw to.
59
+ *
60
+ * What goes on the wire is the parsed value, so a schema default is filled in once here
61
+ * instead of being left to every client. Delivery-time validation discards its own result and
62
+ * serializes what it was handed, so calling {@link SSERoomBroadcaster.broadcastToRoom}
63
+ * directly sends the unparsed input.
64
+ *
65
+ * `context` is whatever the caller is acting on behalf of; only its logger is read, so a
66
+ * request context goes in as-is. Omit it in a caller that has none and the injected logger is
67
+ * used, which costs a logged failure its correlation id and nothing else.
68
+ *
69
+ * @throws {InternalError} if `data` does not satisfy the event's schema.
70
+ */
71
+ publish(room, event, data, context, options) {
72
+ const validation = event.schema.safeParse(data);
73
+ if (!validation.success) {
74
+ throw validationError(room, event.event, validation.error);
75
+ }
76
+ this.broadcast(room, event, validation.data, context, options);
77
+ }
78
+ /**
79
+ * {@link publish}, but a payload that fails its schema comes back as an error instead of being
80
+ * thrown.
81
+ *
82
+ * For a producer that cannot absorb a throw: a message handler whose primary work has already
83
+ * committed would be retried in full and redo it, and the retry cannot succeed anyway, since a
84
+ * malformed payload fails the same way every time. Prefer {@link publish} everywhere else.
85
+ *
86
+ * The failure is logged as well as returned, so a caller that ignores the result still leaves
87
+ * a trace rather than silence.
88
+ *
89
+ * @returns `{ result: true }` once the payload has been validated and handed to the
90
+ * broadcaster. That is acceptance, not delivery: the fan-out has not happened yet, and its
91
+ * own failure is logged rather than returned.
92
+ */
93
+ safePublish(room, event, data, context, options) {
94
+ const validation = event.schema.safeParse(data);
95
+ if (!validation.success) {
96
+ const logger = context?.logger ?? this.logger;
97
+ logger.error({ room, event: event.event, issues: validation.error.issues }, 'Refusing to broadcast an SSE event that fails its own schema');
98
+ return { error: validationError(room, event.event, validation.error) };
99
+ }
100
+ this.broadcast(room, event, validation.data, context, options);
101
+ return { result: true };
102
+ }
103
+ /**
104
+ * The shared tail of both methods. A failed broadcast is logged rather than surfaced: it
105
+ * happens after the caller has returned, and none of these callers could retry it anyway.
106
+ */
107
+ broadcast(room, event,
108
+ // Already schema-valid, so the re-parse at delivery accepts it. The cast below is only
109
+ // needed because `z.output` is not `z.input` for a schema that defaults or transforms.
110
+ parsed, context, options) {
111
+ const logger = context?.logger ?? this.logger;
112
+ this.sseRoomBroadcaster
113
+ .broadcastToRoom(room, event, parsed, options)
114
+ .catch((error) => {
115
+ logger.error({ error, room, event: event.event }, 'Failed to broadcast SSE event');
116
+ });
117
+ }
118
+ }
119
+ //# sourceMappingURL=SSERoomEventPublisher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SSERoomEventPublisher.js","sourceRoot":"","sources":["../../../../lib/sse/rooms/SSERoomEventPublisher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,aAAa,EAAE,MAAM,qBAAqB,CAAA;AA0ChE,+FAA+F;AAC/F,MAAM,eAAe,GAAG,CACtB,IAAuB,EACvB,KAAa,EACb,KAAiB,EACF,EAAE,CACjB,IAAI,aAAa,CAAC;IAChB,OAAO,EAAE,0CAA0C,KAAK,MAAM,KAAK,CAAC,OAAO,EAAE;IAC7E,SAAS,EAAE,6BAA6B;IACxC,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;CACtE,CAAC,CAAA;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,OAAO,qBAAqB;IACf,kBAAkB,CAAoB;IACtC,MAAM,CAAW;IAElC,YAAY,EAAE,kBAAkB,EAAE,MAAM,EAAqC;QAC3E,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,CAAA;QAC5C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CACL,IAAuB,EACvB,KAAoC,EACpC,IAAgB,EAChB,OAAuB,EACvB,OAAoC;QAEpC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAE/C,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;QAC5D,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IAChE,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,WAAW,CACT,IAAuB,EACvB,KAAoC,EACpC,IAAgB,EAChB,OAAuB,EACvB,OAAoC;QAEpC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAE/C,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,IAAI,CAAC,MAAM,CAAA;YAC7C,MAAM,CAAC,KAAK,CACV,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,EAC7D,8DAA8D,CAC/D,CAAA;YAED,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAA;QACxE,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;QAE9D,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;IACzB,CAAC;IAED;;;OAGG;IACK,SAAS,CACf,IAAuB,EACvB,KAAoC;IACpC,uFAAuF;IACvF,uFAAuF;IACvF,MAAmB,EACnB,OAAkC,EAClC,OAA+C;QAE/C,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,IAAI,CAAC,MAAM,CAAA;QAE7C,IAAI,CAAC,kBAAkB;aACpB,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,MAAoB,EAAE,OAAO,CAAC;aAC3D,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACxB,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,+BAA+B,CAAC,CAAA;QACpF,CAAC,CAAC,CAAA;IACN,CAAC;CACF"}
@@ -1,5 +1,6 @@
1
1
  export { InMemoryAdapter } from './adapters/InMemoryAdapter.js';
2
2
  export { defineRoom } from './defineRoom.js';
3
3
  export { SSERoomBroadcaster } from './SSERoomBroadcaster.js';
4
+ export { type SSELogContext, SSERoomEventPublisher, type SSERoomEventPublisherDependencies, type SSERoomEventPublishOptions, } from './SSERoomEventPublisher.js';
4
5
  export { SSERoomManager } from './SSERoomManager.js';
5
6
  export type { PreDeliveryFilter, RoomBroadcastOptions, RoomNameResolver, SSERoomAdapter, SSERoomManagerConfig, SSERoomMessageHandler, SSERoomOperations, } from './types.js';
@@ -3,5 +3,6 @@
3
3
  export { InMemoryAdapter } from './adapters/InMemoryAdapter.js';
4
4
  export { defineRoom } from './defineRoom.js';
5
5
  export { SSERoomBroadcaster } from './SSERoomBroadcaster.js';
6
+ export { SSERoomEventPublisher, } from './SSERoomEventPublisher.js';
6
7
  export { SSERoomManager } from './SSERoomManager.js';
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../lib/sse/rooms/index.ts"],"names":[],"mappings":"AAAA,oBAAoB;AAEpB,WAAW;AACX,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../lib/sse/rooms/index.ts"],"names":[],"mappings":"AAAA,oBAAoB;AAEpB,WAAW;AACX,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAEL,qBAAqB,GAGtB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { SSEEventSchemas } from '@lokalise/api-contracts';
9
9
  import { type ApiContract } from '@lokalise/api-contracts';
10
- import type { ParsedSSEEvent } from '../sse/sseParser.ts';
10
+ import type { ParsedSSEEvent } from '@opinionated-machine/sse-parser';
11
11
  import type { ApiSSEEvent } from './apiSseTestTypes.ts';
12
12
  /**
13
13
  * The contract's SSE schemas, merged across every declared status, or a thrown error naming
@@ -1,5 +1,5 @@
1
1
  import { buildRequestPath, resolveResponseEntry, } from '@lokalise/api-contracts';
2
- import { parseSSEBuffer, parseSSEEvents } from "../sse/sseParser.js";
2
+ import { createSSEStreamParser, parseSSEEvents, } from '@opinionated-machine/sse-parser';
3
3
  import { describeSendFailures, openSSEDiagnosticsScope, unhandledSendFailures, } from "../sse/sseSendDiagnostics.js";
4
4
  import { assertSSEResponse, mediaTypeOf, resolveApiSseSchemas, SSE_CONTENT_TYPE, validateApiSseEvent, } from "./apiSseEventValidation.js";
5
5
  import { truncateBody } from "./sseInjectShared.js";
@@ -156,15 +156,15 @@ class InjectedSSEStream {
156
156
  throw err;
157
157
  }
158
158
  let body = '';
159
- let buffer = '';
160
159
  const decoder = new TextDecoder();
160
+ // Owns the partial frame across chunks, so a frame split by a flush boundary
161
+ // is not read as two.
162
+ const parser = createSSEStreamParser();
161
163
  try {
162
164
  for await (const chunk of res.stream()) {
163
165
  const text = typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });
164
166
  body += text;
165
- buffer += text;
166
- const { events, remaining } = parseSSEBuffer(buffer);
167
- buffer = remaining;
167
+ const events = parser.push(text);
168
168
  if (events.length > 0) {
169
169
  this.received.push(...events);
170
170
  this.notify();
@@ -175,11 +175,10 @@ class InjectedSSEStream {
175
175
  this.fail(err);
176
176
  throw err;
177
177
  }
178
- // A stream that ended without a terminating blank line still carries one last event.
179
- const trailing = parseSSEEvents(buffer);
180
- if (trailing.length > 0) {
181
- this.received.push(...trailing);
182
- }
178
+ // Anything still buffered is a frame the response ended in the middle of. The spec
179
+ // discards pending data at the end of a stream, so it is not delivered as an event:
180
+ // a truncated payload reported as a real one hides the handler bug that produced it.
181
+ // The raw text is still on `body` for a test that wants to look.
183
182
  this.ended = true;
184
183
  this.notify();
185
184
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"apiSseInjectHelpers.js","sourceRoot":"","sources":["../../../lib/testing/apiSseInjectHelpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apiSseInjectHelpers.js","sourceRoot":"","sources":["../../../lib/testing/apiSseInjectHelpers.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { ApiContract } from '@lokalise/api-contracts';
2
+ import { type ParsedSSEEvent } from '@opinionated-machine/sse-parser';
2
3
  import type { SSESession } from '../routes/fastifyRouteTypes.ts';
3
4
  import type { SpiedSSESession, SSESessionSpy } from '../sse/SSESessionSpy.ts';
4
- import { type ParsedSSEEvent } from '../sse/sseParser.ts';
5
5
  import type { ApiSSEEvent } from './apiSseTestTypes.ts';
6
6
  /**
7
7
  * Interface for objects that have a sessionSpy (e.g., SSE controllers in test mode).
@@ -163,11 +163,19 @@ export declare class SSEHttpClient {
163
163
  * subsequent body read with an `AbortError`.
164
164
  */
165
165
  readonly response: Response;
166
+ /**
167
+ * Optional hook invoked with every decoded raw text chunk as it arrives —
168
+ * including comment frames (e.g. `: heartbeat`) that the SSE parser drops.
169
+ * Useful for asserting heartbeat delivery or tracking byte-level liveness.
170
+ * Only fires while the stream is being consumed via events()/collectEvents().
171
+ */
172
+ onRawChunk?: (chunk: string) => void;
166
173
  private readonly abortController;
167
174
  private readonly responseBody;
168
175
  private streamReader;
169
176
  private readonly decoder;
170
- private buffer;
177
+ /** Owns the partial-frame buffer and the Last-Event-ID cursor across chunks. */
178
+ private readonly parser;
171
179
  private closed;
172
180
  private constructor();
173
181
  /**