orpc-fn 0.1.0 → 0.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.
- package/README.md +48 -32
- package/dist/assemble-procedure.d.ts +13 -0
- package/dist/assemble-procedure.d.ts.map +1 -0
- package/dist/assemble-procedure.js +29 -0
- package/dist/assemble-procedure.js.map +1 -0
- package/dist/bound-call.d.ts +1 -1
- package/dist/bound-call.d.ts.map +1 -1
- package/dist/bound-call.js.map +1 -1
- package/dist/client.d.ts +4 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -2
- package/dist/client.js.map +1 -1
- package/dist/compatibility.d.ts +16 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +4 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/create-fn.d.ts +30 -34
- package/dist/create-fn.d.ts.map +1 -1
- package/dist/create-fn.js +177 -121
- package/dist/create-fn.js.map +1 -1
- package/dist/expo.d.ts +11 -25
- package/dist/expo.d.ts.map +1 -1
- package/dist/expo.js +25 -30
- package/dist/expo.js.map +1 -1
- package/dist/hono.d.ts +12 -4
- package/dist/hono.d.ts.map +1 -1
- package/dist/hono.js +29 -12
- package/dist/hono.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/json-schema.d.ts +2 -0
- package/dist/json-schema.d.ts.map +1 -1
- package/dist/json-schema.js +11 -0
- package/dist/json-schema.js.map +1 -1
- package/dist/live/codec.d.ts +6 -1
- package/dist/live/codec.d.ts.map +1 -1
- package/dist/live/codec.js +14 -3
- package/dist/live/codec.js.map +1 -1
- package/dist/live/fn-live.d.ts +63 -22
- package/dist/live/fn-live.d.ts.map +1 -1
- package/dist/live/fn-live.js +98 -16
- package/dist/live/fn-live.js.map +1 -1
- package/dist/live/index.d.ts +1 -1
- package/dist/live/index.d.ts.map +1 -1
- package/dist/live/index.js.map +1 -1
- package/dist/live/ioredis.d.ts +4 -1
- package/dist/live/ioredis.d.ts.map +1 -1
- package/dist/live/ioredis.js +21 -2
- package/dist/live/ioredis.js.map +1 -1
- package/dist/live/lifecycle.d.ts +7 -0
- package/dist/live/lifecycle.d.ts.map +1 -0
- package/dist/live/lifecycle.js +36 -0
- package/dist/live/lifecycle.js.map +1 -0
- package/dist/live/memory.d.ts.map +1 -1
- package/dist/live/memory.js +4 -0
- package/dist/live/memory.js.map +1 -1
- package/dist/live/pub-sub.d.ts +76 -12
- package/dist/live/pub-sub.d.ts.map +1 -1
- package/dist/live/pub-sub.js +429 -125
- package/dist/live/pub-sub.js.map +1 -1
- package/dist/live/redis-bun.d.ts +1 -1
- package/dist/live/redis-bun.d.ts.map +1 -1
- package/dist/live/redis-bun.js +3 -5
- package/dist/live/redis-bun.js.map +1 -1
- package/dist/live/redis.d.ts +2 -2
- package/dist/live/redis.d.ts.map +1 -1
- package/dist/live/redis.js +36 -9
- package/dist/live/redis.js.map +1 -1
- package/dist/live/transport.d.ts +5 -1
- package/dist/live/transport.d.ts.map +1 -1
- package/dist/live/transport.js.map +1 -1
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +21 -0
- package/dist/logger.js.map +1 -1
- package/dist/mastra.d.ts.map +1 -1
- package/dist/mastra.js +16 -7
- package/dist/mastra.js.map +1 -1
- package/dist/mcp/sdk.d.ts +20 -0
- package/dist/mcp/sdk.d.ts.map +1 -0
- package/dist/mcp/sdk.js +82 -0
- package/dist/mcp/sdk.js.map +1 -0
- package/dist/mcp.d.ts +3 -2
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +22 -7
- package/dist/mcp.js.map +1 -1
- package/dist/meta.d.ts +15 -7
- package/dist/meta.d.ts.map +1 -1
- package/dist/meta.js +9 -2
- package/dist/meta.js.map +1 -1
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +77 -6
- package/dist/otel.js.map +1 -1
- package/dist/route-options.d.ts +22 -0
- package/dist/route-options.d.ts.map +1 -0
- package/dist/route-options.js +67 -0
- package/dist/route-options.js.map +1 -0
- package/dist/router.d.ts +5 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +22 -0
- package/dist/router.js.map +1 -1
- package/dist/timing.d.ts +8 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +4 -0
- package/dist/timing.js.map +1 -0
- package/dist/types.d.ts +86 -41
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -2
- package/dist/types.js.map +1 -1
- package/package.json +15 -3
- package/src/assemble-procedure.ts +42 -0
- package/src/bound-call.ts +4 -3
- package/src/client.ts +9 -2
- package/src/compatibility.ts +39 -0
- package/src/create-fn.ts +297 -183
- package/src/expo.ts +49 -44
- package/src/hono.ts +36 -17
- package/src/index.ts +6 -2
- package/src/json-schema.ts +16 -0
- package/src/live/codec.ts +22 -3
- package/src/live/fn-live.ts +244 -69
- package/src/live/index.ts +2 -0
- package/src/live/ioredis.ts +22 -2
- package/src/live/lifecycle.ts +44 -0
- package/src/live/memory.ts +4 -0
- package/src/live/pub-sub.ts +608 -166
- package/src/live/redis-bun.ts +7 -5
- package/src/live/redis.ts +37 -11
- package/src/live/transport.ts +4 -1
- package/src/logger.ts +20 -0
- package/src/mastra.ts +15 -7
- package/src/mcp/sdk.ts +118 -0
- package/src/mcp.ts +48 -20
- package/src/meta.ts +40 -24
- package/src/otel.ts +77 -10
- package/src/route-options.ts +100 -0
- package/src/router.ts +39 -1
- package/src/timing.ts +5 -0
- package/src/types.ts +204 -62
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fn-live.d.ts","sourceRoot":"","sources":["../../src/live/fn-live.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"fn-live.d.ts","sourceRoot":"","sources":["../../src/live/fn-live.ts"],"names":[],"mappings":"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"}
|
package/dist/live/fn-live.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ORPCError } from '@orpc/server';
|
|
2
|
+
import { RAW_INPUT } from '../timing.js';
|
|
3
|
+
import { LIVE_GAP, positiveInteger } from './lifecycle.js';
|
|
2
4
|
import { errorMessageOf } from '../otel.js';
|
|
3
5
|
/** Marks a coalesce window that ended before the next event arrived. */
|
|
4
6
|
const TIMEOUT = Symbol('timeout');
|
|
@@ -54,6 +56,10 @@ function toSnapshotError(err, liveName) {
|
|
|
54
56
|
*/
|
|
55
57
|
export async function* streamLiveSnapshots(opts) {
|
|
56
58
|
const { source, initial, coalesceMs, apply } = opts;
|
|
59
|
+
const maxBatchSize = positiveInteger(opts.maxBatchSize ?? 1000, 'maxBatchSize');
|
|
60
|
+
if (coalesceMs !== undefined &&
|
|
61
|
+
(!Number.isFinite(coalesceMs) || coalesceMs < 0))
|
|
62
|
+
throw new RangeError('orpc-fn: coalesceMs must be finite and nonnegative');
|
|
57
63
|
let pending = null;
|
|
58
64
|
const readNext = () => {
|
|
59
65
|
const read = pending ?? source.next();
|
|
@@ -69,7 +75,7 @@ export async function* streamLiveSnapshots(opts) {
|
|
|
69
75
|
const batch = [current.value];
|
|
70
76
|
if (coalesceMs) {
|
|
71
77
|
const endAt = Date.now() + coalesceMs;
|
|
72
|
-
while (Date.now() < endAt) {
|
|
78
|
+
while (Date.now() < endAt && batch.length < maxBatchSize) {
|
|
73
79
|
const remainingMs = endAt - Date.now();
|
|
74
80
|
const read = readNext();
|
|
75
81
|
let timer;
|
|
@@ -93,18 +99,33 @@ export async function* streamLiveSnapshots(opts) {
|
|
|
93
99
|
batch.push(result.value);
|
|
94
100
|
}
|
|
95
101
|
}
|
|
102
|
+
if (opts.applyBatch) {
|
|
103
|
+
const next = await opts.applyBatch(batch, previous);
|
|
104
|
+
if (next !== undefined) {
|
|
105
|
+
previous = next;
|
|
106
|
+
yield previous;
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
let changed = false;
|
|
96
111
|
for (const event of batch) {
|
|
97
112
|
const next = await apply(event, previous);
|
|
98
113
|
if (next === undefined)
|
|
99
114
|
continue;
|
|
100
115
|
if (isFnLivePatch(next)) {
|
|
116
|
+
if (changed) {
|
|
117
|
+
yield previous;
|
|
118
|
+
changed = false;
|
|
119
|
+
}
|
|
101
120
|
previous = next.state;
|
|
102
121
|
yield next.emit;
|
|
103
122
|
continue;
|
|
104
123
|
}
|
|
105
124
|
previous = next;
|
|
106
|
-
|
|
125
|
+
changed = true;
|
|
107
126
|
}
|
|
127
|
+
if (changed)
|
|
128
|
+
yield previous;
|
|
108
129
|
}
|
|
109
130
|
}
|
|
110
131
|
/**
|
|
@@ -116,6 +137,13 @@ export function createFnLive(runtime) {
|
|
|
116
137
|
const liveLogger = runtime.createLogger('fn-live', undefined);
|
|
117
138
|
return (options) => {
|
|
118
139
|
const { live, handler, input, output, name, ...routeConfig } = options;
|
|
140
|
+
if (live.transformerFn && !live.stateSchema)
|
|
141
|
+
throw new TypeError('orpc-fn: live transformers require a stateSchema for parsed state');
|
|
142
|
+
if (live.coalesceMs !== undefined &&
|
|
143
|
+
(!Number.isFinite(live.coalesceMs) || live.coalesceMs < 0))
|
|
144
|
+
throw new RangeError('orpc-fn: coalesceMs must be finite and nonnegative');
|
|
145
|
+
if (live.maxBatchSize !== undefined)
|
|
146
|
+
positiveInteger(live.maxBatchSize, 'maxBatchSize');
|
|
119
147
|
const liveName = live.name ?? `${name}.live`;
|
|
120
148
|
const liveSummary = live.summary ?? `Live updates of ${routeConfig.summary ?? name}`;
|
|
121
149
|
const liveDescription = live.description ?? routeConfig.description;
|
|
@@ -137,11 +165,6 @@ export function createFnLive(runtime) {
|
|
|
137
165
|
}
|
|
138
166
|
};
|
|
139
167
|
const runHandler = (params) => handler({ ...params, publish });
|
|
140
|
-
// Snapshots go through the output schema like the route's own result.
|
|
141
|
-
const runSnapshot = async (params) => {
|
|
142
|
-
const result = await runHandler(params);
|
|
143
|
-
return output ? output.parseAsync(result) : result;
|
|
144
|
-
};
|
|
145
168
|
const procedure = fn({
|
|
146
169
|
...routeConfig,
|
|
147
170
|
name,
|
|
@@ -149,10 +172,24 @@ export function createFnLive(runtime) {
|
|
|
149
172
|
output,
|
|
150
173
|
handler: runHandler
|
|
151
174
|
});
|
|
152
|
-
|
|
175
|
+
const validate = async (schema, value) => {
|
|
176
|
+
const result = await schema['~standard'].validate(value);
|
|
177
|
+
if (result.issues)
|
|
178
|
+
throw new ORPCError('INTERNAL_SERVER_ERROR', {
|
|
179
|
+
message: 'Invalid live state or patch',
|
|
180
|
+
cause: result.issues
|
|
181
|
+
});
|
|
182
|
+
return result.value;
|
|
183
|
+
};
|
|
184
|
+
const runSnapshot = (params) => params.call(procedure, params[RAW_INPUT]);
|
|
185
|
+
// Generated streams inherit access policies and metadata; tool adapters reject streams.
|
|
153
186
|
const guardOptions = Object.fromEntries(Object.entries(routeConfig).filter(([option]) => isGuard(option)));
|
|
154
187
|
const subscribe = fn({
|
|
155
188
|
...guardOptions,
|
|
189
|
+
guardResolvers: routeConfig.guardResolvers,
|
|
190
|
+
errors: routeConfig.errors,
|
|
191
|
+
meta: routeConfig.meta,
|
|
192
|
+
stream: true,
|
|
156
193
|
procedure: routeConfig.procedure,
|
|
157
194
|
tags: routeConfig.tags,
|
|
158
195
|
name: liveName,
|
|
@@ -166,9 +203,12 @@ export function createFnLive(runtime) {
|
|
|
166
203
|
const subscription = await channel.open({
|
|
167
204
|
input: params.input,
|
|
168
205
|
context: params.context,
|
|
169
|
-
signal: params.signal
|
|
206
|
+
signal: params.signal,
|
|
207
|
+
recoverGaps: true
|
|
170
208
|
});
|
|
171
209
|
try {
|
|
210
|
+
if (subscription.isClosed())
|
|
211
|
+
return;
|
|
172
212
|
let initial;
|
|
173
213
|
try {
|
|
174
214
|
initial = await runSnapshot(params);
|
|
@@ -177,21 +217,61 @@ export function createFnLive(runtime) {
|
|
|
177
217
|
// `fn.completed` logs it, at the level `isExpectedError` picks.
|
|
178
218
|
throw toSnapshotError(err, liveName);
|
|
179
219
|
}
|
|
180
|
-
const rerun = (
|
|
220
|
+
const rerun = () => runSnapshot(params);
|
|
221
|
+
const authorize = async () => {
|
|
222
|
+
if (live.reauthorize &&
|
|
223
|
+
live.reauthorize !== true &&
|
|
224
|
+
!(await live.reauthorize({
|
|
225
|
+
input: params.input,
|
|
226
|
+
ctx: params.context
|
|
227
|
+
})))
|
|
228
|
+
throw new ORPCError('FORBIDDEN');
|
|
229
|
+
};
|
|
181
230
|
const apply = async (event, previous) => {
|
|
231
|
+
await authorize();
|
|
232
|
+
if (event === LIVE_GAP)
|
|
233
|
+
return rerun();
|
|
182
234
|
if (live.shouldUpdate &&
|
|
183
|
-
!(await live.shouldUpdate({ ...params, event, previous })))
|
|
235
|
+
!(await live.shouldUpdate({ ...params, event, previous })))
|
|
184
236
|
return undefined;
|
|
185
|
-
}
|
|
186
237
|
if (!live.transformerFn)
|
|
187
|
-
return
|
|
188
|
-
|
|
238
|
+
return rerun();
|
|
239
|
+
const next = await live.transformerFn({
|
|
240
|
+
...params,
|
|
241
|
+
event,
|
|
242
|
+
previous,
|
|
243
|
+
rerun
|
|
244
|
+
});
|
|
245
|
+
if (next === undefined)
|
|
246
|
+
return undefined;
|
|
247
|
+
if (isFnLivePatch(next)) {
|
|
248
|
+
if (!live.emitSchema)
|
|
249
|
+
throw new TypeError('orpc-fn: live patches require emitSchema');
|
|
250
|
+
return fnLivePatch(await validate(live.stateSchema, next.state), await validate(live.emitSchema, next.emit));
|
|
251
|
+
}
|
|
252
|
+
return validate(live.stateSchema, next);
|
|
189
253
|
};
|
|
254
|
+
const applyBatch = live.transformerFn
|
|
255
|
+
? undefined
|
|
256
|
+
: async (events, previous) => {
|
|
257
|
+
await authorize();
|
|
258
|
+
let invalidated = false;
|
|
259
|
+
for (const event of events)
|
|
260
|
+
if (event === LIVE_GAP ||
|
|
261
|
+
!live.shouldUpdate ||
|
|
262
|
+
(await live.shouldUpdate({ ...params, event, previous })))
|
|
263
|
+
invalidated = true;
|
|
264
|
+
return invalidated ? rerun() : undefined;
|
|
265
|
+
};
|
|
190
266
|
yield* streamLiveSnapshots({
|
|
191
267
|
source: subscription.events,
|
|
192
268
|
initial,
|
|
193
269
|
coalesceMs: live.coalesceMs,
|
|
194
|
-
|
|
270
|
+
...(live.maxBatchSize !== undefined
|
|
271
|
+
? { maxBatchSize: live.maxBatchSize }
|
|
272
|
+
: {}),
|
|
273
|
+
apply,
|
|
274
|
+
...(applyBatch ? { applyBatch } : {})
|
|
195
275
|
});
|
|
196
276
|
}
|
|
197
277
|
finally {
|
|
@@ -203,7 +283,9 @@ export function createFnLive(runtime) {
|
|
|
203
283
|
procedure,
|
|
204
284
|
subscribe,
|
|
205
285
|
publish,
|
|
206
|
-
getChannelName: channel.getChannelName
|
|
286
|
+
getChannelName: channel.getChannelName,
|
|
287
|
+
getSubscriptionChannelName: channel.getSubscriptionChannelName,
|
|
288
|
+
getPublishChannelName: channel.getPublishChannelName
|
|
207
289
|
};
|
|
208
290
|
};
|
|
209
291
|
}
|
package/dist/live/fn-live.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fn-live.js","sourceRoot":"","sources":["../../src/live/fn-live.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Schema } from '@orpc/contract'\nimport { type AnyProcedure, ORPCError } from '@orpc/server'\nimport type { ZodType, z } from 'zod'\nimport type { FnLogger } from '../logger.js'\nimport { errorMessageOf, type SpanLike } from '../otel.js'\nimport type {\n\tFnContext,\n\tFnDefinition,\n\tFnProcedure,\n\tFnRouteOptions,\n\tHandlerParams,\n\tMaybePromise,\n\tProcedureKey\n} from '../types.js'\nimport type {\n\tAuthFn,\n\tChannel,\n\tChannelDefinition,\n\tChannelOptions,\n\tObjectSchema,\n\tPublisherConfig\n} from './pub-sub.js'\n\n/** Marks a coalesce window that ended before the next event arrived. */\nconst TIMEOUT = Symbol('timeout')\n\nconst fnLivePatchMarker = Symbol('fnLive.patch')\n\n/**\n * Transformer result that splits the internal accumulator from the wire\n * payload: `state` becomes the `previous` snapshot for later events while only\n * `emit` is sent to the subscriber. Lets high-frequency streams avoid\n * re-serializing the full snapshot per event.\n */\nexport type FnLivePatch<TOutput, TEmit> = {\n\t[fnLivePatchMarker]: true\n\tstate: TOutput\n\temit: TEmit\n}\n\nexport function fnLivePatch<TOutput, TEmit>(\n\tstate: TOutput,\n\temit: TEmit\n): FnLivePatch<TOutput, TEmit> {\n\treturn { [fnLivePatchMarker]: true, state, emit }\n}\n\nfunction isFnLivePatch(value: unknown): value is FnLivePatch<unknown, unknown> {\n\treturn (\n\t\ttypeof value === 'object' && value !== null && fnLivePatchMarker in value\n\t)\n}\n\nexport type FnLiveConfig<\n\tTDef extends FnDefinition,\n\tTInput,\n\tTEventSchema extends ZodType,\n\tTOutput,\n\tTKey extends ProcedureKey<TDef>,\n\tTEmit = never\n> = Omit<PublisherConfig, 'name'> & {\n\t/** Subscribe route name; default `${name}.live`. */\n\tname?: string\n\teventSchema: TEventSchema\n\tchannel: ChannelDefinition<\n\t\tTInput,\n\t\tz.output<TEventSchema>,\n\t\tFnContext<TDef, TKey>\n\t>\n\t/** Fold an event into the snapshot; without it every event re-runs the handler. */\n\ttransformerFn?: (\n\t\tparams: HandlerParams<TDef, TInput, TKey> & {\n\t\t\tevent: z.output<TEventSchema>\n\t\t\tprevious: TOutput | undefined\n\t\t\trerun: (input?: TInput) => Promise<TOutput>\n\t\t}\n\t) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>\n\t/** Return false to skip an event. */\n\tshouldUpdate?: (\n\t\tparams: HandlerParams<TDef, TInput, TKey> & {\n\t\t\tevent: z.output<TEventSchema>\n\t\t\tprevious: TOutput | undefined\n\t\t}\n\t) => MaybePromise<boolean>\n\tauthFn?: AuthFn<TInput, FnContext<TDef, TKey>>\n\t/** Log publish failures instead of throwing them into the publishing route. */\n\tsafePublish?: boolean\n\t/** Batch events arriving within this window into one snapshot update. */\n\tcoalesceMs?: number\n\t/**\n\t * When a slow subscriber's queue overflows (drop-oldest), this marker is\n\t * enqueued INSTEAD of the dropped event so the client resyncs. Return\n\t * `null` to skip.\n\t */\n\toverflowMarker?: (input: TInput) => z.output<TEventSchema> | null\n\tsummary?: string\n\tdescription?: string\n}\n\nexport type FnLiveReturn<\n\tTDef extends FnDefinition,\n\tTKey extends ProcedureKey<TDef>,\n\tTInput extends ObjectSchema,\n\tTOutputSchema extends Schema<unknown, unknown>,\n\tTOutput,\n\tTEventSchema extends ZodType,\n\tTEmit = never\n> = {\n\tprocedure: FnProcedure<TDef, TKey, TInput, TOutputSchema>\n\tsubscribe: FnProcedure<\n\t\tTDef,\n\t\tTKey,\n\t\tTInput,\n\t\tSchema<AsyncGenerator<TOutput | TEmit>, AsyncGenerator<TOutput | TEmit>>\n\t>\n\tpublish: (event: z.input<TEventSchema>) => Promise<void>\n\tgetChannelName: (\n\t\tparams: Partial<z.output<TInput>> | Partial<z.output<TEventSchema>>,\n\t\tcontext?: FnContext<TDef, TKey>\n\t) => string\n}\n\n/**\n * A route plus a subscribe route that streams its result: the initial\n * snapshot, then an update for every event published on the channel.\n */\nexport interface FnLive<TDef extends FnDefinition> {\n\t<\n\t\tTInput extends ObjectSchema,\n\t\tTOutputSchema extends ZodType,\n\t\tTEventSchema extends ZodType,\n\t\tTKey extends ProcedureKey<TDef> = TDef['default'],\n\t\tTEmit = never\n\t>(\n\t\toptions: {\n\t\t\tinput: TInput\n\t\t\toutput: TOutputSchema\n\t\t\thandler: (\n\t\t\t\tparams: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>> & {\n\t\t\t\t\tpublish: (event: z.input<TEventSchema>) => Promise<void>\n\t\t\t\t}\n\t\t\t\t// The output schema parses what the handler returns: its input type.\n\t\t\t) => MaybePromise<z.input<TOutputSchema>>\n\t\t\tlive: FnLiveConfig<\n\t\t\t\tTDef,\n\t\t\t\tz.output<TInput>,\n\t\t\t\tTEventSchema,\n\t\t\t\tz.output<TOutputSchema>,\n\t\t\t\tNoInfer<TKey>,\n\t\t\t\tTEmit\n\t\t\t>\n\t\t} & FnRouteOptions<TDef, TKey>\n\t): FnLiveReturn<\n\t\tTDef,\n\t\tTKey,\n\t\tTInput,\n\t\tTOutputSchema,\n\t\tz.output<TOutputSchema>,\n\t\tTEventSchema,\n\t\tTEmit\n\t>\n\n\t<\n\t\tTInput extends ObjectSchema,\n\t\tTOutput,\n\t\tTEventSchema extends ZodType,\n\t\tTKey extends ProcedureKey<TDef> = TDef['default'],\n\t\tTEmit = never\n\t>(\n\t\toptions: {\n\t\t\tinput: TInput\n\t\t\toutput?: undefined\n\t\t\thandler: (\n\t\t\t\tparams: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>> & {\n\t\t\t\t\tpublish: (event: z.input<TEventSchema>) => Promise<void>\n\t\t\t\t}\n\t\t\t) => MaybePromise<TOutput>\n\t\t\tlive: FnLiveConfig<\n\t\t\t\tTDef,\n\t\t\t\tz.output<TInput>,\n\t\t\t\tTEventSchema,\n\t\t\t\tTOutput,\n\t\t\t\tNoInfer<TKey>,\n\t\t\t\tTEmit\n\t\t\t>\n\t\t} & FnRouteOptions<TDef, TKey>\n\t): FnLiveReturn<\n\t\tTDef,\n\t\tTKey,\n\t\tTInput,\n\t\tSchema<TOutput, TOutput>,\n\t\tTOutput,\n\t\tTEventSchema,\n\t\tTEmit\n\t>\n}\n\n/**\n * Fail a live subscription whose initial snapshot could not be built.\n *\n * An expected client failure - an `ORPCError` with a 4xx status, e.g. the\n * subscribed resource was not found or access was refused - reaches the\n * subscriber unchanged and is NOT logged as a server fault. Only 5xx and\n * unknown failures are logged. Unknown errors are wrapped as\n * `INTERNAL_SERVER_ERROR`.\n */\nexport function throwInitialSnapshotError(\n\terr: unknown,\n\tliveName: string,\n\tlogger: Pick<FnLogger, 'error'>,\n\t/** `createFn`'s `isExpectedError`; default: a 4xx `ORPCError`. */\n\tisExpected: (error: unknown) => boolean = (error) =>\n\t\terror instanceof ORPCError && error.status < 500\n): never {\n\tif (!isExpected(err)) {\n\t\tlogger.error('fnLive initial snapshot failed', {\n\t\t\tname: liveName,\n\t\t\terr: errorMessageOf(err)\n\t\t})\n\t}\n\tthrow toSnapshotError(err, liveName)\n}\n\n/** An `ORPCError` passes through; anything else becomes INTERNAL_SERVER_ERROR. */\nfunction toSnapshotError(\n\terr: unknown,\n\tliveName: string\n): ORPCError<string, unknown> {\n\tif (err instanceof ORPCError) return err\n\treturn new ORPCError('INTERNAL_SERVER_ERROR', {\n\t\tmessage: `Failed to load initial snapshot for ${liveName}`,\n\t\tcause: err\n\t})\n}\n\n/**\n * Drives a live subscription: yields the initial snapshot, then folds each\n * inbound event into the running snapshot via `apply`, yielding after every\n * change. With `coalesceMs`, events arriving within that window are batched so\n * bursty streams apply together.\n *\n * `apply` may return an {@link FnLivePatch} to keep the full snapshot as the\n * internal accumulator while yielding only the lighter `emit` payload.\n *\n * Invariant: there is never more than one outstanding `source.next()` read. On\n * a coalesce-window timeout the still-pending read is stashed in `pending` and\n * reused by the next `readNext()` - issuing a second concurrent read would\n * strand the in-flight event behind the next one (delivering it \"one behind\").\n */\nexport async function* streamLiveSnapshots<\n\tTEvent,\n\tTOutput,\n\tTEmit = never\n>(opts: {\n\tsource: AsyncIterator<TEvent>\n\tinitial: TOutput\n\tcoalesceMs?: number | undefined\n\tapply: (\n\t\tevent: TEvent,\n\t\tprevious: TOutput\n\t) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>\n}): AsyncGenerator<TOutput | TEmit> {\n\tconst { source, initial, coalesceMs, apply } = opts\n\n\tlet pending: Promise<IteratorResult<TEvent>> | null = null\n\tconst readNext = () => {\n\t\tconst read = pending ?? source.next()\n\t\tpending = null\n\t\treturn read\n\t}\n\n\tlet previous = initial\n\tyield previous\n\n\twhile (true) {\n\t\tconst current = await readNext()\n\t\tif (current.done) break\n\n\t\tconst batch: TEvent[] = [current.value]\n\n\t\tif (coalesceMs) {\n\t\t\tconst endAt = Date.now() + coalesceMs\n\t\t\twhile (Date.now() < endAt) {\n\t\t\t\tconst remainingMs = endAt - Date.now()\n\t\t\t\tconst read = readNext()\n\t\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined\n\t\t\t\tconst result = await Promise.race([\n\t\t\t\t\tread,\n\t\t\t\t\tnew Promise<typeof TIMEOUT>((resolve) => {\n\t\t\t\t\t\ttimer = setTimeout(resolve, remainingMs, TIMEOUT)\n\t\t\t\t\t})\n\t\t\t\t])\n\t\t\t\tclearTimeout(timer)\n\n\t\t\t\tif (result === TIMEOUT) {\n\t\t\t\t\t// Reuse the SAME in-flight read next iteration instead of starting\n\t\t\t\t\t// a new one - this is what prevents the \"one behind\" stranding.\n\t\t\t\t\tpending = read\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif (result.done) {\n\t\t\t\t\tpending = Promise.resolve(result)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tbatch.push(result.value)\n\t\t\t}\n\t\t}\n\n\t\tfor (const event of batch) {\n\t\t\tconst next = await apply(event, previous)\n\t\t\tif (next === undefined) continue\n\t\t\tif (isFnLivePatch(next)) {\n\t\t\t\tprevious = next.state as TOutput\n\t\t\t\tyield next.emit as TEmit\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tprevious = next\n\t\t\tyield previous\n\t\t}\n\t}\n}\n\ntype RuntimeParams = Record<string, unknown> & {\n\tinput: Record<string, unknown>\n\tcontext: unknown\n\tsignal: AbortSignal | undefined\n\tlogger: FnLogger\n}\n\n/** `FnLiveConfig` with the generics erased: what the implementation reads. */\ntype RuntimeLiveConfig = Omit<ChannelOptions, 'name'> & {\n\tname?: string\n\ttransformerFn?: (params: RuntimeParams & Record<string, unknown>) => unknown\n\tshouldUpdate?: (params: RuntimeParams & Record<string, unknown>) => unknown\n\tsafePublish?: boolean\n\tcoalesceMs?: number\n\tsummary?: string\n\tdescription?: string\n}\n\n/**\n * @internal Wires `fnLive` onto an `fn` and channel runtime of the same\n * instance. `createFn` returns it typed as {@link FnLive}.\n */\nexport function createFnLive(runtime: {\n\t// biome-ignore lint/suspicious/noExplicitAny: runtime half of the typed `Fn`\n\tfn: (options: any) => AnyProcedure\n\tcreateChannel: (options: ChannelOptions) => Channel\n\tcreateLogger: (scope: string, span: SpanLike | undefined) => FnLogger\n\tisGuard: (option: string) => boolean\n}) {\n\tconst { fn, createChannel, isGuard } = runtime\n\tconst liveLogger = runtime.createLogger('fn-live', undefined)\n\n\treturn (\n\t\toptions: {\n\t\t\tlive: RuntimeLiveConfig\n\t\t\thandler: (params: RuntimeParams) => unknown\n\t\t\tinput: ZodType\n\t\t\toutput?: ZodType\n\t\t\tname: string\n\t\t\tprocedure?: string\n\t\t\tsummary?: string\n\t\t\tdescription?: string\n\t\t\ttags?: string[]\n\t\t} & Record<string, unknown>\n\t) => {\n\t\tconst { live, handler, input, output, name, ...routeConfig } = options\n\t\tconst liveName = live.name ?? `${name}.live`\n\t\tconst liveSummary =\n\t\t\tlive.summary ?? `Live updates of ${routeConfig.summary ?? name}`\n\t\tconst liveDescription = live.description ?? routeConfig.description\n\n\t\t// `createChannel` reads only the channel keys of the live config.\n\t\tconst channel = createChannel({ ...live, name: liveName })\n\n\t\tconst publish = async (event: unknown) => {\n\t\t\tif (!live.safePublish) return channel.publish(event)\n\t\t\ttry {\n\t\t\t\tawait channel.publish(event)\n\t\t\t} catch (err) {\n\t\t\t\t// Live update failures must not roll back the route that emitted them,\n\t\t\t\t// but they should still be visible in logs.\n\t\t\t\tliveLogger.error('fnLive publish failed', {\n\t\t\t\t\tname: liveName,\n\t\t\t\t\terr: errorMessageOf(err)\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst runHandler = (params: RuntimeParams) =>\n\t\t\thandler({ ...params, publish })\n\t\t// Snapshots go through the output schema like the route's own result.\n\t\tconst runSnapshot = async (params: RuntimeParams) => {\n\t\t\tconst result = await runHandler(params)\n\t\t\treturn output ? output.parseAsync(result) : result\n\t\t}\n\n\t\tconst procedure = fn({\n\t\t\t...routeConfig,\n\t\t\tname,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\thandler: runHandler\n\t\t})\n\n\t\t// Guards run on the subscribe route too; route meta stays on `procedure`.\n\t\tconst guardOptions = Object.fromEntries(\n\t\t\tObject.entries(routeConfig).filter(([option]) => isGuard(option))\n\t\t)\n\t\tconst subscribe = fn({\n\t\t\t...guardOptions,\n\t\t\tprocedure: routeConfig.procedure,\n\t\t\ttags: routeConfig.tags,\n\t\t\tname: liveName,\n\t\t\tmethod: 'GET',\n\t\t\tinput,\n\t\t\tsummary: liveSummary,\n\t\t\tdescription: liveDescription,\n\t\t\thandler: async function* (params: RuntimeParams) {\n\t\t\t\t// Authorize and subscribe before the snapshot: a refused subscriber\n\t\t\t\t// gets nothing, and events published while it loads are queued.\n\t\t\t\tconst subscription = await channel.open({\n\t\t\t\t\tinput: params.input,\n\t\t\t\t\tcontext: params.context,\n\t\t\t\t\tsignal: params.signal\n\t\t\t\t})\n\t\t\t\ttry {\n\t\t\t\t\tlet initial: unknown\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinitial = await runSnapshot(params)\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t// `fn.completed` logs it, at the level `isExpectedError` picks.\n\t\t\t\t\t\tthrow toSnapshotError(err, liveName)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst rerun = (nextInput?: Record<string, unknown>) =>\n\t\t\t\t\t\trunSnapshot({ ...params, input: nextInput ?? params.input })\n\t\t\t\t\tconst apply = async (event: unknown, previous: unknown) => {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tlive.shouldUpdate &&\n\t\t\t\t\t\t\t!(await live.shouldUpdate({ ...params, event, previous }))\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!live.transformerFn) return runSnapshot(params)\n\t\t\t\t\t\treturn live.transformerFn({ ...params, event, previous, rerun })\n\t\t\t\t\t}\n\n\t\t\t\t\tyield* streamLiveSnapshots({\n\t\t\t\t\t\tsource: subscription.events,\n\t\t\t\t\t\tinitial,\n\t\t\t\t\t\tcoalesceMs: live.coalesceMs,\n\t\t\t\t\t\tapply\n\t\t\t\t\t})\n\t\t\t\t} finally {\n\t\t\t\t\tsubscription.close()\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\treturn {\n\t\t\tprocedure,\n\t\t\tsubscribe,\n\t\t\tpublish,\n\t\t\tgetChannelName: channel.getChannelName\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fn-live.js","sourceRoot":"","sources":["../../src/live/fn-live.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AnySchema, ErrorMap, Schema } from '@orpc/contract'\nimport { type AnyProcedure, ORPCError } from '@orpc/server'\nimport type { ZodType, z } from 'zod'\nimport { RAW_INPUT } from '../timing.js'\nimport { LIVE_GAP, positiveInteger } from './lifecycle.js'\nimport type { FnLogger } from '../logger.js'\nimport { errorMessageOf, type SpanLike } from '../otel.js'\nimport type {\n\tFnContext,\n\tFnDefinition,\n\tFnProcedure,\n\tFnRouteOptions,\n\tHandlerParams,\n\tMaybePromise,\n\tProcedureKey\n} from '../types.js'\nimport type {\n\tAuthFn,\n\tChannel,\n\tChannelDefinition,\n\tChannelOptions,\n\tChannelQueueOptions,\n\tObjectSchema,\n\tPublisherConfig\n} from './pub-sub.js'\n\n/** Marks a coalesce window that ended before the next event arrived. */\nconst TIMEOUT = Symbol('timeout')\n\nconst fnLivePatchMarker = Symbol('fnLive.patch')\n\n/**\n * Transformer result that splits the internal accumulator from the wire\n * payload: `state` becomes the `previous` snapshot for later events while only\n * `emit` is sent to the subscriber. Lets high-frequency streams avoid\n * re-serializing the full snapshot per event.\n */\nexport type FnLivePatch<TOutput, TEmit> = {\n\t[fnLivePatchMarker]: true\n\tstate: TOutput\n\temit: TEmit\n}\n\nexport function fnLivePatch<TOutput, TEmit>(\n\tstate: TOutput,\n\temit: TEmit\n): FnLivePatch<TOutput, TEmit> {\n\treturn { [fnLivePatchMarker]: true, state, emit }\n}\n\nfunction isFnLivePatch(value: unknown): value is FnLivePatch<unknown, unknown> {\n\treturn (\n\t\ttypeof value === 'object' && value !== null && fnLivePatchMarker in value\n\t)\n}\n\nexport type FnLiveConfig<\n\tTDef extends FnDefinition,\n\tTInput,\n\tTEventSchema extends ZodType,\n\tTOutput,\n\tTKey extends ProcedureKey<TDef>,\n\tTEmit = never,\n\tTErrors extends ErrorMap = Record<never, never>\n> = Omit<PublisherConfig, 'name'> &\n\tChannelQueueOptions & {\n\t\t/** Subscribe route name; default `${name}.live`. */\n\t\tname?: string\n\t\t/** Validates parsed reducer state without reapplying an output transform. Required with a transformer. */\n\t\tstateSchema?: Schema<TOutput, TOutput>\n\t\t/** Validates patch payloads. Required when a transformer returns fnLivePatch. */\n\t\temitSchema?: Schema<TEmit, TEmit>\n\t\t/** Optional access check before each update; idle streams keep their initial authorization. */\n\t\treauthorize?: AuthFn<TInput, FnContext<TDef, TKey>>\n\t\teventSchema: TEventSchema\n\t\tchannel: ChannelDefinition<\n\t\t\tTInput,\n\t\t\tz.output<TEventSchema>,\n\t\t\tFnContext<TDef, TKey>\n\t\t>\n\t\t/** Fold an event into the snapshot; without it every event re-runs the handler. */\n\t\ttransformerFn?: FnLiveConfigTransformer<\n\t\t\tTDef,\n\t\t\tTInput,\n\t\t\tTEventSchema,\n\t\t\tTOutput,\n\t\t\tTKey,\n\t\t\tTEmit,\n\t\t\tTErrors\n\t\t>\n\t\t/** Return false to skip an event. */\n\t\tshouldUpdate?: (\n\t\t\tparams: HandlerParams<TDef, TInput, TKey, TErrors> & {\n\t\t\t\tevent: z.output<TEventSchema>\n\t\t\t\tprevious: TOutput\n\t\t\t}\n\t\t) => MaybePromise<boolean>\n\t\tauthFn?: AuthFn<TInput, FnContext<TDef, TKey>>\n\t\t/** Log publish failures instead of throwing them into the publishing route. */\n\t\tsafePublish?: boolean\n\t\t/** Batch events arriving within this window into one snapshot update. */\n\t\tcoalesceMs?: number\n\t\t/** Maximum events collected in one coalescing batch (default 1000). */\n\t\tmaxBatchSize?: number\n\t\t/**\n\t\t * When a slow subscriber's queue overflows (drop-oldest), this marker is\n\t\t * enqueued INSTEAD of the dropped event so the client resyncs. Return\n\t\t * `null` to skip.\n\t\t */\n\t\toverflowMarker?: (input: TInput) => z.output<TEventSchema> | null\n\t\tsummary?: string\n\t\tdescription?: string\n\t} & (\n\t\t| { transformerFn?: undefined }\n\t\t| {\n\t\t\t\ttransformerFn: FnLiveConfigTransformer<\n\t\t\t\t\tTDef,\n\t\t\t\t\tTInput,\n\t\t\t\t\tTEventSchema,\n\t\t\t\t\tTOutput,\n\t\t\t\t\tTKey,\n\t\t\t\t\tTEmit,\n\t\t\t\t\tTErrors\n\t\t\t\t>\n\t\t\t\tstateSchema: Schema<TOutput, TOutput>\n\t\t }\n\t) &\n\t([TEmit] extends [never] ? object : { emitSchema: Schema<TEmit, TEmit> })\n\ntype FnLiveConfigTransformer<\n\tTDef extends FnDefinition,\n\tTInput,\n\tTEventSchema extends ZodType,\n\tTOutput,\n\tTKey extends ProcedureKey<TDef>,\n\tTEmit,\n\tTErrors extends ErrorMap\n> = (\n\tparams: HandlerParams<TDef, TInput, TKey, TErrors> & {\n\t\tevent: z.output<TEventSchema>\n\t\tprevious: TOutput\n\t\trerun: () => Promise<TOutput>\n\t}\n) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>\n\nexport type FnLiveReturn<\n\tTDef extends FnDefinition,\n\tTKey extends ProcedureKey<TDef>,\n\tTInput extends ObjectSchema,\n\tTOutputSchema extends Schema<unknown, unknown>,\n\tTOutput,\n\tTEventSchema extends ZodType,\n\tTEmit = never,\n\tTErrors extends ErrorMap = Record<never, never>\n> = {\n\tprocedure: FnProcedure<TDef, TKey, TInput, TOutputSchema, TErrors>\n\tsubscribe: FnProcedure<\n\t\tTDef,\n\t\tTKey,\n\t\tTInput,\n\t\tSchema<AsyncGenerator<TOutput | TEmit>, AsyncGenerator<TOutput | TEmit>>,\n\t\tTErrors\n\t>\n\tpublish: (event: z.input<TEventSchema>) => Promise<void>\n\tgetSubscriptionChannelName: (params: {\n\t\tinput: z.output<TInput>\n\t\tcontext: FnContext<TDef, TKey>\n\t}) => string\n\tgetPublishChannelName: (event: z.output<TEventSchema>) => string\n\t/** @deprecated Prefer the separate required-input resolver methods. */\n\tgetChannelName: (\n\t\tparams: Partial<z.output<TInput>> | Partial<z.output<TEventSchema>>,\n\t\tcontext?: FnContext<TDef, TKey>\n\t) => string\n}\n\n/**\n * A route plus a subscribe route that streams its result: the initial\n * snapshot, then an update for every event published on the channel.\n */\nexport interface FnLive<TDef extends FnDefinition> {\n\t<\n\t\tTInput extends ObjectSchema,\n\t\tTOutputSchema extends ZodType,\n\t\tTEventSchema extends ZodType,\n\t\tTKey extends ProcedureKey<TDef> = TDef['default'],\n\t\tTEmit = never,\n\t\tTErrors extends ErrorMap = Record<never, never>\n\t>(\n\t\toptions: {\n\t\t\tinput: TInput\n\t\t\toutput: TOutputSchema\n\t\t\thandler: (\n\t\t\t\tparams: HandlerParams<\n\t\t\t\t\tTDef,\n\t\t\t\t\tz.output<TInput>,\n\t\t\t\t\tNoInfer<TKey>,\n\t\t\t\t\tTErrors\n\t\t\t\t> & {\n\t\t\t\t\tpublish: (event: z.input<TEventSchema>) => Promise<void>\n\t\t\t\t}\n\t\t\t\t// The output schema parses what the handler returns: its input type.\n\t\t\t) => MaybePromise<z.input<TOutputSchema>>\n\t\t\tlive: FnLiveConfig<\n\t\t\t\tTDef,\n\t\t\t\tz.output<TInput>,\n\t\t\t\tTEventSchema,\n\t\t\t\tz.output<TOutputSchema>,\n\t\t\t\tNoInfer<TKey>,\n\t\t\t\tTEmit,\n\t\t\t\tTErrors\n\t\t\t>\n\t\t} & FnRouteOptions<TDef, TKey, z.output<TInput>, TErrors>\n\t): FnLiveReturn<\n\t\tTDef,\n\t\tTKey,\n\t\tTInput,\n\t\tTOutputSchema,\n\t\tz.output<TOutputSchema>,\n\t\tTEventSchema,\n\t\tTEmit,\n\t\tTErrors\n\t>\n\n\t<\n\t\tTInput extends ObjectSchema,\n\t\tTOutput,\n\t\tTEventSchema extends ZodType,\n\t\tTKey extends ProcedureKey<TDef> = TDef['default'],\n\t\tTEmit = never,\n\t\tTErrors extends ErrorMap = Record<never, never>\n\t>(\n\t\toptions: {\n\t\t\tinput: TInput\n\t\t\toutput?: undefined\n\t\t\thandler: (\n\t\t\t\tparams: HandlerParams<\n\t\t\t\t\tTDef,\n\t\t\t\t\tz.output<TInput>,\n\t\t\t\t\tNoInfer<TKey>,\n\t\t\t\t\tTErrors\n\t\t\t\t> & {\n\t\t\t\t\tpublish: (event: z.input<TEventSchema>) => Promise<void>\n\t\t\t\t}\n\t\t\t) => MaybePromise<TOutput>\n\t\t\tlive: FnLiveConfig<\n\t\t\t\tTDef,\n\t\t\t\tz.output<TInput>,\n\t\t\t\tTEventSchema,\n\t\t\t\tTOutput,\n\t\t\t\tNoInfer<TKey>,\n\t\t\t\tTEmit,\n\t\t\t\tTErrors\n\t\t\t>\n\t\t} & FnRouteOptions<TDef, TKey, z.output<TInput>, TErrors>\n\t): FnLiveReturn<\n\t\tTDef,\n\t\tTKey,\n\t\tTInput,\n\t\tSchema<TOutput, TOutput>,\n\t\tTOutput,\n\t\tTEventSchema,\n\t\tTEmit,\n\t\tTErrors\n\t>\n}\n\n/**\n * Fail a live subscription whose initial snapshot could not be built.\n *\n * An expected client failure - an `ORPCError` with a 4xx status, e.g. the\n * subscribed resource was not found or access was refused - reaches the\n * subscriber unchanged and is NOT logged as a server fault. Only 5xx and\n * unknown failures are logged. Unknown errors are wrapped as\n * `INTERNAL_SERVER_ERROR`.\n */\nexport function throwInitialSnapshotError(\n\terr: unknown,\n\tliveName: string,\n\tlogger: Pick<FnLogger, 'error'>,\n\t/** `createFn`'s `isExpectedError`; default: a 4xx `ORPCError`. */\n\tisExpected: (error: unknown) => boolean = (error) =>\n\t\terror instanceof ORPCError && error.status < 500\n): never {\n\tif (!isExpected(err)) {\n\t\tlogger.error('fnLive initial snapshot failed', {\n\t\t\tname: liveName,\n\t\t\terr: errorMessageOf(err)\n\t\t})\n\t}\n\tthrow toSnapshotError(err, liveName)\n}\n\n/** An `ORPCError` passes through; anything else becomes INTERNAL_SERVER_ERROR. */\nfunction toSnapshotError(\n\terr: unknown,\n\tliveName: string\n): ORPCError<string, unknown> {\n\tif (err instanceof ORPCError) return err\n\treturn new ORPCError('INTERNAL_SERVER_ERROR', {\n\t\tmessage: `Failed to load initial snapshot for ${liveName}`,\n\t\tcause: err\n\t})\n}\n\n/**\n * Drives a live subscription: yields the initial snapshot, then folds each\n * inbound event into the running snapshot via `apply`, yielding after every\n * change. With `coalesceMs`, events arriving within that window are batched so\n * bursty streams apply together.\n *\n * `apply` may return an {@link FnLivePatch} to keep the full snapshot as the\n * internal accumulator while yielding only the lighter `emit` payload.\n *\n * Invariant: there is never more than one outstanding `source.next()` read. On\n * a coalesce-window timeout the still-pending read is stashed in `pending` and\n * reused by the next `readNext()` - issuing a second concurrent read would\n * strand the in-flight event behind the next one (delivering it \"one behind\").\n */\nexport async function* streamLiveSnapshots<\n\tTEvent,\n\tTOutput,\n\tTEmit = never\n>(opts: {\n\tsource: AsyncIterator<TEvent>\n\t/** Maximum events retained in one coalescing batch. */\n\tmaxBatchSize?: number\n\tapplyBatch?: (\n\t\tevents: readonly TEvent[],\n\t\tprevious: TOutput\n\t) => MaybePromise<TOutput | undefined>\n\tinitial: TOutput\n\tcoalesceMs?: number | undefined\n\tapply: (\n\t\tevent: TEvent,\n\t\tprevious: TOutput\n\t) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>\n}): AsyncGenerator<TOutput | TEmit> {\n\tconst { source, initial, coalesceMs, apply } = opts\n\tconst maxBatchSize = positiveInteger(\n\t\topts.maxBatchSize ?? 1000,\n\t\t'maxBatchSize'\n\t)\n\tif (\n\t\tcoalesceMs !== undefined &&\n\t\t(!Number.isFinite(coalesceMs) || coalesceMs < 0)\n\t)\n\t\tthrow new RangeError('orpc-fn: coalesceMs must be finite and nonnegative')\n\n\tlet pending: Promise<IteratorResult<TEvent>> | null = null\n\tconst readNext = () => {\n\t\tconst read = pending ?? source.next()\n\t\tpending = null\n\t\treturn read\n\t}\n\n\tlet previous = initial\n\tyield previous\n\n\twhile (true) {\n\t\tconst current = await readNext()\n\t\tif (current.done) break\n\n\t\tconst batch: TEvent[] = [current.value]\n\n\t\tif (coalesceMs) {\n\t\t\tconst endAt = Date.now() + coalesceMs\n\t\t\twhile (Date.now() < endAt && batch.length < maxBatchSize) {\n\t\t\t\tconst remainingMs = endAt - Date.now()\n\t\t\t\tconst read = readNext()\n\t\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined\n\t\t\t\tconst result = await Promise.race([\n\t\t\t\t\tread,\n\t\t\t\t\tnew Promise<typeof TIMEOUT>((resolve) => {\n\t\t\t\t\t\ttimer = setTimeout(resolve, remainingMs, TIMEOUT)\n\t\t\t\t\t})\n\t\t\t\t])\n\t\t\t\tclearTimeout(timer)\n\n\t\t\t\tif (result === TIMEOUT) {\n\t\t\t\t\t// Reuse the SAME in-flight read next iteration instead of starting\n\t\t\t\t\t// a new one - this is what prevents the \"one behind\" stranding.\n\t\t\t\t\tpending = read\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif (result.done) {\n\t\t\t\t\tpending = Promise.resolve(result)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tbatch.push(result.value)\n\t\t\t}\n\t\t}\n\n\t\tif (opts.applyBatch) {\n\t\t\tconst next = await opts.applyBatch(batch, previous)\n\t\t\tif (next !== undefined) {\n\t\t\t\tprevious = next\n\t\t\t\tyield previous\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tlet changed = false\n\t\tfor (const event of batch) {\n\t\t\tconst next = await apply(event, previous)\n\t\t\tif (next === undefined) continue\n\t\t\tif (isFnLivePatch(next)) {\n\t\t\t\tif (changed) {\n\t\t\t\t\tyield previous\n\t\t\t\t\tchanged = false\n\t\t\t\t}\n\t\t\t\tprevious = next.state as TOutput\n\t\t\t\tyield next.emit as TEmit\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tprevious = next\n\t\t\tchanged = true\n\t\t}\n\t\tif (changed) yield previous\n\t}\n}\n\ntype RuntimeParams = Record<string, unknown> & {\n\tinput: Record<string, unknown>\n\tcontext: unknown\n\tsignal: AbortSignal | undefined\n\tlogger: FnLogger\n\tcall: (procedure: AnyProcedure, input: unknown) => Promise<unknown>\n\t[RAW_INPUT]: unknown\n}\n\n/** `FnLiveConfig` with the generics erased: what the implementation reads. */\ntype RuntimeLiveConfig = Omit<ChannelOptions, 'name'> & {\n\tname?: string\n\tstateSchema?: AnySchema\n\temitSchema?: AnySchema\n\treauthorize?: AuthFn<Record<string, unknown>, unknown>\n\ttransformerFn?: (params: RuntimeParams & Record<string, unknown>) => unknown\n\tshouldUpdate?: (params: RuntimeParams & Record<string, unknown>) => unknown\n\tsafePublish?: boolean\n\tcoalesceMs?: number\n\tmaxBatchSize?: number\n\tsummary?: string\n\tdescription?: string\n}\n\n/**\n * @internal Wires `fnLive` onto an `fn` and channel runtime of the same\n * instance. `createFn` returns it typed as {@link FnLive}.\n */\nexport function createFnLive(runtime: {\n\t// biome-ignore lint/suspicious/noExplicitAny: runtime half of the typed `Fn`\n\tfn: (options: any) => AnyProcedure\n\tcreateChannel: (options: ChannelOptions) => Channel\n\tcreateLogger: (scope: string, span: SpanLike | undefined) => FnLogger\n\tisGuard: (option: string) => boolean\n}) {\n\tconst { fn, createChannel, isGuard } = runtime\n\tconst liveLogger = runtime.createLogger('fn-live', undefined)\n\n\treturn (\n\t\toptions: {\n\t\t\tlive: RuntimeLiveConfig\n\t\t\thandler: (params: RuntimeParams) => unknown\n\t\t\tinput: ZodType\n\t\t\toutput?: ZodType\n\t\t\tname: string\n\t\t\tprocedure?: string\n\t\t\tsummary?: string\n\t\t\tdescription?: string\n\t\t\ttags?: string[]\n\t\t} & Record<string, unknown>\n\t) => {\n\t\tconst { live, handler, input, output, name, ...routeConfig } = options\n\t\tif (live.transformerFn && !live.stateSchema)\n\t\t\tthrow new TypeError(\n\t\t\t\t'orpc-fn: live transformers require a stateSchema for parsed state'\n\t\t\t)\n\t\tif (\n\t\t\tlive.coalesceMs !== undefined &&\n\t\t\t(!Number.isFinite(live.coalesceMs) || live.coalesceMs < 0)\n\t\t)\n\t\t\tthrow new RangeError('orpc-fn: coalesceMs must be finite and nonnegative')\n\t\tif (live.maxBatchSize !== undefined)\n\t\t\tpositiveInteger(live.maxBatchSize, 'maxBatchSize')\n\t\tconst liveName = live.name ?? `${name}.live`\n\t\tconst liveSummary =\n\t\t\tlive.summary ?? `Live updates of ${routeConfig.summary ?? name}`\n\t\tconst liveDescription = live.description ?? routeConfig.description\n\n\t\t// `createChannel` reads only the channel keys of the live config.\n\t\tconst channel = createChannel({ ...live, name: liveName })\n\n\t\tconst publish = async (event: unknown) => {\n\t\t\tif (!live.safePublish) return channel.publish(event)\n\t\t\ttry {\n\t\t\t\tawait channel.publish(event)\n\t\t\t} catch (err) {\n\t\t\t\t// Live update failures must not roll back the route that emitted them,\n\t\t\t\t// but they should still be visible in logs.\n\t\t\t\tliveLogger.error('fnLive publish failed', {\n\t\t\t\t\tname: liveName,\n\t\t\t\t\terr: errorMessageOf(err)\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst runHandler = (params: RuntimeParams) =>\n\t\t\thandler({ ...params, publish })\n\n\t\tconst procedure = fn({\n\t\t\t...routeConfig,\n\t\t\tname,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\thandler: runHandler\n\t\t})\n\n\t\tconst validate = async (schema: AnySchema, value: unknown) => {\n\t\t\tconst result = await schema['~standard'].validate(value)\n\t\t\tif (result.issues)\n\t\t\t\tthrow new ORPCError('INTERNAL_SERVER_ERROR', {\n\t\t\t\t\tmessage: 'Invalid live state or patch',\n\t\t\t\t\tcause: result.issues\n\t\t\t\t})\n\t\t\treturn result.value\n\t\t}\n\t\tconst runSnapshot = (params: RuntimeParams) =>\n\t\t\tparams.call(procedure, params[RAW_INPUT])\n\t\t// Generated streams inherit access policies and metadata; tool adapters reject streams.\n\n\t\tconst guardOptions = Object.fromEntries(\n\t\t\tObject.entries(routeConfig).filter(([option]) => isGuard(option))\n\t\t)\n\t\tconst subscribe = fn({\n\t\t\t...guardOptions,\n\t\t\tguardResolvers: routeConfig.guardResolvers,\n\t\t\terrors: routeConfig.errors,\n\t\t\tmeta: routeConfig.meta,\n\t\t\tstream: true,\n\t\t\tprocedure: routeConfig.procedure,\n\t\t\ttags: routeConfig.tags,\n\t\t\tname: liveName,\n\t\t\tmethod: 'GET',\n\t\t\tinput,\n\t\t\tsummary: liveSummary,\n\t\t\tdescription: liveDescription,\n\t\t\thandler: async function* (params: RuntimeParams) {\n\t\t\t\t// Authorize and subscribe before the snapshot: a refused subscriber\n\t\t\t\t// gets nothing, and events published while it loads are queued.\n\t\t\t\tconst subscription = await channel.open({\n\t\t\t\t\tinput: params.input,\n\t\t\t\t\tcontext: params.context,\n\t\t\t\t\tsignal: params.signal,\n\t\t\t\t\trecoverGaps: true\n\t\t\t\t})\n\t\t\t\ttry {\n\t\t\t\t\tif (subscription.isClosed()) return\n\t\t\t\t\tlet initial: unknown\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinitial = await runSnapshot(params)\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t// `fn.completed` logs it, at the level `isExpectedError` picks.\n\t\t\t\t\t\tthrow toSnapshotError(err, liveName)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst rerun = () => runSnapshot(params)\n\t\t\t\t\tconst authorize = async () => {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tlive.reauthorize &&\n\t\t\t\t\t\t\tlive.reauthorize !== true &&\n\t\t\t\t\t\t\t!(await live.reauthorize({\n\t\t\t\t\t\t\t\tinput: params.input,\n\t\t\t\t\t\t\t\tctx: params.context\n\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tthrow new ORPCError('FORBIDDEN')\n\t\t\t\t\t}\n\t\t\t\t\tconst apply = async (event: unknown, previous: unknown) => {\n\t\t\t\t\t\tawait authorize()\n\t\t\t\t\t\tif (event === LIVE_GAP) return rerun()\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tlive.shouldUpdate &&\n\t\t\t\t\t\t\t!(await live.shouldUpdate({ ...params, event, previous }))\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn undefined\n\t\t\t\t\t\tif (!live.transformerFn) return rerun()\n\t\t\t\t\t\tconst next = await live.transformerFn({\n\t\t\t\t\t\t\t...params,\n\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\tprevious,\n\t\t\t\t\t\t\trerun\n\t\t\t\t\t\t})\n\t\t\t\t\t\tif (next === undefined) return undefined\n\t\t\t\t\t\tif (isFnLivePatch(next)) {\n\t\t\t\t\t\t\tif (!live.emitSchema)\n\t\t\t\t\t\t\t\tthrow new TypeError('orpc-fn: live patches require emitSchema')\n\t\t\t\t\t\t\treturn fnLivePatch(\n\t\t\t\t\t\t\t\tawait validate(live.stateSchema as AnySchema, next.state),\n\t\t\t\t\t\t\t\tawait validate(live.emitSchema, next.emit)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn validate(live.stateSchema as AnySchema, next)\n\t\t\t\t\t}\n\t\t\t\t\tconst applyBatch = live.transformerFn\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: async (events: readonly unknown[], previous: unknown) => {\n\t\t\t\t\t\t\t\tawait authorize()\n\t\t\t\t\t\t\t\tlet invalidated = false\n\t\t\t\t\t\t\t\tfor (const event of events)\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\tevent === LIVE_GAP ||\n\t\t\t\t\t\t\t\t\t\t!live.shouldUpdate ||\n\t\t\t\t\t\t\t\t\t\t(await live.shouldUpdate({ ...params, event, previous }))\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\tinvalidated = true\n\t\t\t\t\t\t\t\treturn invalidated ? rerun() : undefined\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\tyield* streamLiveSnapshots({\n\t\t\t\t\t\tsource: subscription.events,\n\t\t\t\t\t\tinitial,\n\t\t\t\t\t\tcoalesceMs: live.coalesceMs,\n\t\t\t\t\t\t...(live.maxBatchSize !== undefined\n\t\t\t\t\t\t\t? { maxBatchSize: live.maxBatchSize }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\tapply,\n\t\t\t\t\t\t...(applyBatch ? { applyBatch } : {})\n\t\t\t\t\t})\n\t\t\t\t} finally {\n\t\t\t\t\tsubscription.close()\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\treturn {\n\t\t\tprocedure,\n\t\t\tsubscribe,\n\t\t\tpublish,\n\t\t\tgetChannelName: channel.getChannelName,\n\t\t\tgetSubscriptionChannelName: channel.getSubscriptionChannelName,\n\t\t\tgetPublishChannelName: channel.getPublishChannelName\n\t\t}\n\t}\n}\n"]}
|
package/dist/live/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { type FnLive, type FnLiveConfig, type FnLivePatch, type FnLiveReturn, fnLivePatch, streamLiveSnapshots, throwInitialSnapshotError } from './fn-live.js';
|
|
2
|
-
export { type AuthFn, type ChannelDefinition, type CreatePublisher, type CreatePubSub, createBoundedEventQueue, type FilterFn, type ObjectSchema, type Publisher, type PublisherConfig, type PublisherOptions, type PubSub, type PubSubOptions, type PubSubRuntimeOptions } from './pub-sub.js';
|
|
2
|
+
export { type AuthFn, type ChannelDefinition, type ChannelQueueOptions, type PubSubMetric, type CreatePublisher, type CreatePubSub, createBoundedEventQueue, type FilterFn, type ObjectSchema, type Publisher, type PublisherConfig, type PublisherOptions, type PubSub, type PubSubOptions, type PubSubRuntimeOptions } from './pub-sub.js';
|
|
3
3
|
export { type BacklogOptions, backlogKey, type PubSubMessage, type PubSubTransport } from './transport.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/live/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/live/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,WAAW,EACX,mBAAmB,EACnB,yBAAyB,EACzB,MAAM,cAAc,CAAA;AACrB,OAAO,EACN,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,uBAAuB,EACvB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,MAAM,cAAc,CAAA;AACrB,OAAO,EACN,KAAK,cAAc,EACnB,UAAU,EACV,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,MAAM,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/live/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,WAAW,EACX,mBAAmB,EACnB,yBAAyB,EACzB,MAAM,cAAc,CAAA;AACrB,OAAO,EACN,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,uBAAuB,EACvB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,MAAM,cAAc,CAAA;AACrB,OAAO,EACN,KAAK,cAAc,EACnB,UAAU,EACV,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,MAAM,gBAAgB,CAAA"}
|
package/dist/live/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/live/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAKN,WAAW,EACX,mBAAmB,EACnB,yBAAyB,EACzB,MAAM,cAAc,CAAA;AACrB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/live/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAKN,WAAW,EACX,mBAAmB,EACnB,yBAAyB,EACzB,MAAM,cAAc,CAAA;AACrB,OAAO,EAON,uBAAuB,EASvB,MAAM,cAAc,CAAA;AACrB,OAAO,EAEN,UAAU,EAGV,MAAM,gBAAgB,CAAA","sourcesContent":["// `fnLive`, `createPubSub` and `createPublisher` come typed from `createFn`.\nexport {\n\ttype FnLive,\n\ttype FnLiveConfig,\n\ttype FnLivePatch,\n\ttype FnLiveReturn,\n\tfnLivePatch,\n\tstreamLiveSnapshots,\n\tthrowInitialSnapshotError\n} from './fn-live.js'\nexport {\n\ttype AuthFn,\n\ttype ChannelDefinition,\n\ttype ChannelQueueOptions,\n\ttype PubSubMetric,\n\ttype CreatePublisher,\n\ttype CreatePubSub,\n\tcreateBoundedEventQueue,\n\ttype FilterFn,\n\ttype ObjectSchema,\n\ttype Publisher,\n\ttype PublisherConfig,\n\ttype PublisherOptions,\n\ttype PubSub,\n\ttype PubSubOptions,\n\ttype PubSubRuntimeOptions\n} from './pub-sub.js'\nexport {\n\ttype BacklogOptions,\n\tbacklogKey,\n\ttype PubSubMessage,\n\ttype PubSubTransport\n} from './transport.js'\n"]}
|
package/dist/live/ioredis.d.ts
CHANGED
|
@@ -4,11 +4,14 @@ export interface IORedisLike {
|
|
|
4
4
|
subscribe(...channels: string[]): Promise<unknown>;
|
|
5
5
|
unsubscribe(...channels: string[]): Promise<unknown>;
|
|
6
6
|
duplicate(): IORedisLike;
|
|
7
|
+
status?: string;
|
|
7
8
|
disconnect(): void;
|
|
8
9
|
on(event: 'message', listener: (channel: string, message: string) => void): unknown;
|
|
10
|
+
on(event: 'ready', listener: () => void): unknown;
|
|
9
11
|
on(event: 'end', listener: () => void): unknown;
|
|
10
12
|
on(event: 'error', listener: (error: Error) => void): unknown;
|
|
11
13
|
off(event: 'message', listener: (channel: string, message: string) => void): unknown;
|
|
14
|
+
off(event: 'ready', listener: () => void): unknown;
|
|
12
15
|
off(event: 'end', listener: () => void): unknown;
|
|
13
16
|
off(event: 'error', listener: (error: Error) => void): unknown;
|
|
14
17
|
}
|
|
@@ -24,6 +27,6 @@ export declare function ioredisTransport(client: IORedisLike, options?: {
|
|
|
24
27
|
subscriber?: IORedisLike;
|
|
25
28
|
onError?: (error: Error) => void;
|
|
26
29
|
}): import("./transport.js").PubSubTransport & {
|
|
27
|
-
close(): void
|
|
30
|
+
close(): Promise<void>;
|
|
28
31
|
};
|
|
29
32
|
//# sourceMappingURL=ioredis.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ioredis.d.ts","sourceRoot":"","sources":["../../src/live/ioredis.ts"],"names":[],"mappings":"AAEA,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1D,SAAS,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACpD,SAAS,IAAI,WAAW,CAAA;IACxB,UAAU,IAAI,IAAI,CAAA;IAClB,EAAE,CACD,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAClD,OAAO,CAAA;IACV,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IAC/C,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAA;IAC7D,GAAG,CACF,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAClD,OAAO,CAAA;IACV,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IAChD,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAA;CAC9D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAAO;;
|
|
1
|
+
{"version":3,"file":"ioredis.d.ts","sourceRoot":"","sources":["../../src/live/ioredis.ts"],"names":[],"mappings":"AAEA,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1D,SAAS,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACpD,SAAS,IAAI,WAAW,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,IAAI,IAAI,CAAA;IAClB,EAAE,CACD,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAClD,OAAO,CAAA;IACV,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IACjD,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IAC/C,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAA;IAC7D,GAAG,CACF,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAClD,OAAO,CAAA;IACV,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IAClD,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAA;IAChD,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAA;CAC9D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAAO;;EAyD5E"}
|
package/dist/live/ioredis.js
CHANGED
|
@@ -15,10 +15,24 @@ export function ioredisTransport(client, options = {}) {
|
|
|
15
15
|
const subscriber = options.subscriber ?? client.duplicate();
|
|
16
16
|
const onMessage = (channel, message) => handlers.onMessage(channel, message);
|
|
17
17
|
// Without a listener an ioredis 'error' event would crash the process.
|
|
18
|
-
const onError = (error) =>
|
|
18
|
+
const onError = (error) => {
|
|
19
|
+
try {
|
|
20
|
+
options.onError?.(error);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
/* Isolate telemetry. */
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
let readyOnce = subscriber.status === 'ready';
|
|
27
|
+
const onReady = () => {
|
|
28
|
+
if (readyOnce)
|
|
29
|
+
handlers.onReconnect();
|
|
30
|
+
readyOnce = true;
|
|
31
|
+
};
|
|
19
32
|
// 'end' means ioredis stopped reconnecting.
|
|
20
33
|
const onEnd = () => handlers.onLost(new Error('Redis subscriber connection ended'));
|
|
21
34
|
const ours = new Set();
|
|
35
|
+
subscriber.on('ready', onReady);
|
|
22
36
|
subscriber.on('message', onMessage);
|
|
23
37
|
subscriber.on('error', onError);
|
|
24
38
|
subscriber.on('end', onEnd);
|
|
@@ -27,19 +41,24 @@ export function ioredisTransport(client, options = {}) {
|
|
|
27
41
|
ours.add(channel);
|
|
28
42
|
return subscriber.subscribe(channel);
|
|
29
43
|
},
|
|
44
|
+
resubscribe: (channel) => subscriber.subscribe(channel),
|
|
30
45
|
unsubscribe: (channel) => {
|
|
31
46
|
ours.delete(channel);
|
|
32
47
|
return subscriber.unsubscribe(channel);
|
|
33
48
|
},
|
|
34
49
|
close() {
|
|
35
50
|
// Detach first: a given subscriber outlives this transport's use.
|
|
51
|
+
subscriber.off('ready', onReady);
|
|
36
52
|
subscriber.off('message', onMessage);
|
|
37
53
|
subscriber.off('end', onEnd);
|
|
38
54
|
if (owned)
|
|
39
55
|
return subscriber.disconnect();
|
|
40
56
|
subscriber.off('error', onError);
|
|
41
57
|
if (ours.size > 0) {
|
|
42
|
-
|
|
58
|
+
return subscriber
|
|
59
|
+
.unsubscribe(...ours)
|
|
60
|
+
.then(() => { })
|
|
61
|
+
.catch(() => { });
|
|
43
62
|
}
|
|
44
63
|
}
|
|
45
64
|
};
|
package/dist/live/ioredis.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ioredis.js","sourceRoot":"","sources":["../../src/live/ioredis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"ioredis.js","sourceRoot":"","sources":["../../src/live/ioredis.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRedisTransport } from './redis.js'\n\n/** The part of an ioredis `Redis` client this transport uses. */\nexport interface IORedisLike {\n\tcall(command: string, ...args: string[]): Promise<unknown>\n\tsubscribe(...channels: string[]): Promise<unknown>\n\tunsubscribe(...channels: string[]): Promise<unknown>\n\tduplicate(): IORedisLike\n\tstatus?: string\n\tdisconnect(): void\n\ton(\n\t\tevent: 'message',\n\t\tlistener: (channel: string, message: string) => void\n\t): unknown\n\ton(event: 'ready', listener: () => void): unknown\n\ton(event: 'end', listener: () => void): unknown\n\ton(event: 'error', listener: (error: Error) => void): unknown\n\toff(\n\t\tevent: 'message',\n\t\tlistener: (channel: string, message: string) => void\n\t): unknown\n\toff(event: 'ready', listener: () => void): unknown\n\toff(event: 'end', listener: () => void): unknown\n\toff(event: 'error', listener: (error: Error) => void): unknown\n}\n\n/**\n * `PubSubTransport` for ioredis. Subscriptions use a dedicated connection\n * (`client.duplicate()` unless `subscriber` is given); ioredis re-subscribes\n * after reconnects itself (`autoResubscribe`), so no `resubscribe` is needed. `onError` receives connection\n * errors that ioredis is already retrying.\n *\n * Call `close()` on shutdown to disconnect the subscriber it created.\n */\nexport function ioredisTransport(\n\tclient: IORedisLike,\n\toptions: { subscriber?: IORedisLike; onError?: (error: Error) => void } = {}\n) {\n\treturn createRedisTransport({\n\t\tsend: (command, args) => client.call(command, ...args),\n\t\tasync connectSubscriber(handlers) {\n\t\t\tconst owned = !options.subscriber\n\t\t\tconst subscriber = options.subscriber ?? client.duplicate()\n\t\t\tconst onMessage = (channel: string, message: string) =>\n\t\t\t\thandlers.onMessage(channel, message)\n\t\t\t// Without a listener an ioredis 'error' event would crash the process.\n\t\t\tconst onError = (error: Error) => {\n\t\t\t\ttry {\n\t\t\t\t\toptions.onError?.(error)\n\t\t\t\t} catch {\n\t\t\t\t\t/* Isolate telemetry. */\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet readyOnce = subscriber.status === 'ready'\n\t\t\tconst onReady = () => {\n\t\t\t\tif (readyOnce) handlers.onReconnect()\n\t\t\t\treadyOnce = true\n\t\t\t}\n\t\t\t// 'end' means ioredis stopped reconnecting.\n\t\t\tconst onEnd = () =>\n\t\t\t\thandlers.onLost(new Error('Redis subscriber connection ended'))\n\t\t\tconst ours = new Set<string>()\n\t\t\tsubscriber.on('ready', onReady)\n\t\t\tsubscriber.on('message', onMessage)\n\t\t\tsubscriber.on('error', onError)\n\t\t\tsubscriber.on('end', onEnd)\n\t\t\treturn {\n\t\t\t\tsubscribe: (channel) => {\n\t\t\t\t\tours.add(channel)\n\t\t\t\t\treturn subscriber.subscribe(channel)\n\t\t\t\t},\n\t\t\t\tresubscribe: (channel: string) => subscriber.subscribe(channel),\n\t\t\t\tunsubscribe: (channel) => {\n\t\t\t\t\tours.delete(channel)\n\t\t\t\t\treturn subscriber.unsubscribe(channel)\n\t\t\t\t},\n\t\t\t\tclose() {\n\t\t\t\t\t// Detach first: a given subscriber outlives this transport's use.\n\t\t\t\t\tsubscriber.off('ready', onReady)\n\t\t\t\t\tsubscriber.off('message', onMessage)\n\t\t\t\t\tsubscriber.off('end', onEnd)\n\t\t\t\t\tif (owned) return subscriber.disconnect()\n\t\t\t\t\tsubscriber.off('error', onError)\n\t\t\t\t\tif (ours.size > 0) {\n\t\t\t\t\t\treturn subscriber\n\t\t\t\t\t\t\t.unsubscribe(...ours)\n\t\t\t\t\t\t\t.then(() => {})\n\t\t\t\t\t\t\t.catch(() => {})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Internal control message: live queries reload after loss; raw streams fail. */
|
|
2
|
+
export declare const LIVE_GAP: unique symbol;
|
|
3
|
+
export declare function positiveInteger(value: number, name: string): number;
|
|
4
|
+
export declare function safely(callback: (() => unknown) | undefined): void;
|
|
5
|
+
/** Abort and timeout only stop waiting; callers release late transport results. */
|
|
6
|
+
export declare function waitFor<T>(promise: Promise<T>, timeoutMs: number, signal: AbortSignal): Promise<T>;
|
|
7
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/live/lifecycle.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,eAAO,MAAM,QAAQ,eAA4B,CAAA;AAEjD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAInE;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAMlE;AAED,mFAAmF;AACnF,wBAAsB,OAAO,CAAC,CAAC,EAC9B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,GACjB,OAAO,CAAC,CAAC,CAAC,CAqBZ"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Internal control message: live queries reload after loss; raw streams fail. */
|
|
2
|
+
export const LIVE_GAP = Symbol('orpc-fn.liveGap');
|
|
3
|
+
export function positiveInteger(value, name) {
|
|
4
|
+
if (!Number.isSafeInteger(value) || value <= 0)
|
|
5
|
+
throw new RangeError(`orpc-fn: ${name} must be a positive safe integer`);
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
export function safely(callback) {
|
|
9
|
+
try {
|
|
10
|
+
callback?.();
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
/* Observability must not disrupt delivery. */
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Abort and timeout only stop waiting; callers release late transport results. */
|
|
17
|
+
export async function waitFor(promise, timeoutMs, signal) {
|
|
18
|
+
signal.throwIfAborted();
|
|
19
|
+
let timer;
|
|
20
|
+
let abort = () => { };
|
|
21
|
+
try {
|
|
22
|
+
return await Promise.race([
|
|
23
|
+
promise,
|
|
24
|
+
new Promise((_resolve, reject) => {
|
|
25
|
+
abort = () => reject(signal.reason);
|
|
26
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
27
|
+
timer = setTimeout(() => reject(new Error('orpc-fn: subscription initialization timed out')), timeoutMs);
|
|
28
|
+
})
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
signal.removeEventListener('abort', abort);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/live/lifecycle.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAA;AAEjD,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,IAAY;IAC1D,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAC7C,MAAM,IAAI,UAAU,CAAC,YAAY,IAAI,kCAAkC,CAAC,CAAA;IACzE,OAAO,KAAK,CAAA;AACb,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,QAAqC;IAC3D,IAAI,CAAC;QACJ,QAAQ,EAAE,EAAE,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACR,8CAA8C;IAC/C,CAAC;AACF,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,OAAO,CAC5B,OAAmB,EACnB,SAAiB,EACjB,MAAmB;IAEnB,MAAM,CAAC,cAAc,EAAE,CAAA;IACvB,IAAI,KAAgD,CAAA;IACpD,IAAI,KAAK,GAAG,GAAG,EAAE,GAAE,CAAC,CAAA;IACpB,IAAI,CAAC;QACJ,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;YACzB,OAAO;YACP,IAAI,OAAO,CAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;gBACvC,KAAK,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;gBACnC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;gBACvD,KAAK,GAAG,UAAU,CACjB,GAAG,EAAE,CACJ,MAAM,CAAC,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC,EACpE,SAAS,CACT,CAAA;YACF,CAAC,CAAC;SACF,CAAC,CAAA;IACH,CAAC;YAAS,CAAC;QACV,YAAY,CAAC,KAAK,CAAC,CAAA;QACnB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC3C,CAAC;AACF,CAAC","sourcesContent":["/** Internal control message: live queries reload after loss; raw streams fail. */\nexport const LIVE_GAP = Symbol('orpc-fn.liveGap')\n\nexport function positiveInteger(value: number, name: string): number {\n\tif (!Number.isSafeInteger(value) || value <= 0)\n\t\tthrow new RangeError(`orpc-fn: ${name} must be a positive safe integer`)\n\treturn value\n}\n\nexport function safely(callback: (() => unknown) | undefined): void {\n\ttry {\n\t\tcallback?.()\n\t} catch {\n\t\t/* Observability must not disrupt delivery. */\n\t}\n}\n\n/** Abort and timeout only stop waiting; callers release late transport results. */\nexport async function waitFor<T>(\n\tpromise: Promise<T>,\n\ttimeoutMs: number,\n\tsignal: AbortSignal\n): Promise<T> {\n\tsignal.throwIfAborted()\n\tlet timer: ReturnType<typeof setTimeout> | undefined\n\tlet abort = () => {}\n\ttry {\n\t\treturn await Promise.race([\n\t\t\tpromise,\n\t\t\tnew Promise<never>((_resolve, reject) => {\n\t\t\t\tabort = () => reject(signal.reason)\n\t\t\t\tsignal.addEventListener('abort', abort, { once: true })\n\t\t\t\ttimer = setTimeout(\n\t\t\t\t\t() =>\n\t\t\t\t\t\treject(new Error('orpc-fn: subscription initialization timed out')),\n\t\t\t\t\ttimeoutMs\n\t\t\t\t)\n\t\t\t})\n\t\t])\n\t} finally {\n\t\tclearTimeout(timer)\n\t\tsignal.removeEventListener('abort', abort)\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/live/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,eAAe,GAAG;IACpD,oDAAoD;IACpD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CACtC,
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/live/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,eAAe,GAAG;IACpD,oDAAoD;IACpD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CACtC,CA4CA"}
|
package/dist/live/memory.js
CHANGED
|
@@ -6,6 +6,10 @@ export function memoryTransport() {
|
|
|
6
6
|
const listeners = new Map();
|
|
7
7
|
const backlogs = new Map();
|
|
8
8
|
return {
|
|
9
|
+
async close() {
|
|
10
|
+
listeners.clear();
|
|
11
|
+
backlogs.clear();
|
|
12
|
+
},
|
|
9
13
|
async publish(messages, backlog) {
|
|
10
14
|
for (const { channel, payload } of messages) {
|
|
11
15
|
if (backlog) {
|
package/dist/live/memory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/live/memory.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,eAAe;IAI9B,MAAM,SAAS,GAAG,IAAI,GAAG,EAA0C,CAAA;IACnE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkD,CAAA;IAE1E,OAAO;QACN,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO;YAC9B,KAAK,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC7C,IAAI,OAAO,EAAE,CAAC;oBACb,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;oBACrC,MAAM,KAAK,GACV,OAAO,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;oBAC/D,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;oBACnB,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;oBACzD,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE;wBACrB,KAAK;wBACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI;qBACjD,CAAC,CAAA;gBACH,CAAC;gBACD,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;oBAC5D,cAAc,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;gBACxC,CAAC;YACF,CAAC;QACF,CAAC;QACD,KAAK,CAAC,WAAW,CAAC,OAAO;YACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YACrC,OAAO,OAAO,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAC3E,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,QAAQ;YAChC,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,CAAA;YAC/C,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;YAC3B,sEAAsE;YACtE,MAAM,KAAK,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;YACpD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACd,OAAO,KAAK,IAAI,EAAE;gBACjB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACjB,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;oBAAE,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAC9C,CAAC,CAAA;QACF,CAAC;QACD,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC;KAC7D,CAAA;AACF,CAAC","sourcesContent":["import type { PubSubTransport } from './transport.js'\n\n/**\n * In-process transport for tests and single-process development. Delivery is\n * asynchronous (a microtask), like a real broker.\n */\nexport function memoryTransport(): PubSubTransport & {\n\t/** Active listeners per channel, for assertions. */\n\tlistenerCount(channel: string): number\n} {\n\tconst listeners = new Map<string, Set<(payload: string) => void>>()\n\tconst backlogs = new Map<string, { items: string[]; expiresAt: number }>()\n\n\treturn {\n\t\tasync publish(messages, backlog) {\n\t\t\tfor (const { channel, payload } of messages) {\n\t\t\t\tif (backlog) {\n\t\t\t\t\tconst current = backlogs.get(channel)\n\t\t\t\t\tconst items =\n\t\t\t\t\t\tcurrent && current.expiresAt > Date.now() ? current.items : []\n\t\t\t\t\titems.push(payload)\n\t\t\t\t\titems.splice(0, Math.max(0, items.length - backlog.size))\n\t\t\t\t\tbacklogs.set(channel, {\n\t\t\t\t\t\titems,\n\t\t\t\t\t\texpiresAt: Date.now() + backlog.ttlSeconds * 1000\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tfor (const listener of [...(listeners.get(channel) ?? [])]) {\n\t\t\t\t\tqueueMicrotask(() => listener(payload))\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tasync readBacklog(channel) {\n\t\t\tconst backlog = backlogs.get(channel)\n\t\t\treturn backlog && backlog.expiresAt > Date.now() ? [...backlog.items] : []\n\t\t},\n\t\tasync subscribe(channel, listener) {\n\t\t\tconst set = listeners.get(channel) ?? new Set()\n\t\t\tlisteners.set(channel, set)\n\t\t\t// Wrap so the same listener can subscribe twice and unsubscribe once.\n\t\t\tconst entry = (payload: string) => listener(payload)\n\t\t\tset.add(entry)\n\t\t\treturn async () => {\n\t\t\t\tset.delete(entry)\n\t\t\t\tif (set.size === 0) listeners.delete(channel)\n\t\t\t}\n\t\t},\n\t\tlistenerCount: (channel) => listeners.get(channel)?.size ?? 0\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/live/memory.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,eAAe;IAI9B,MAAM,SAAS,GAAG,IAAI,GAAG,EAA0C,CAAA;IACnE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkD,CAAA;IAE1E,OAAO;QACN,KAAK,CAAC,KAAK;YACV,SAAS,CAAC,KAAK,EAAE,CAAA;YACjB,QAAQ,CAAC,KAAK,EAAE,CAAA;QACjB,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO;YAC9B,KAAK,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC7C,IAAI,OAAO,EAAE,CAAC;oBACb,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;oBACrC,MAAM,KAAK,GACV,OAAO,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;oBAC/D,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;oBACnB,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;oBACzD,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE;wBACrB,KAAK;wBACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI;qBACjD,CAAC,CAAA;gBACH,CAAC;gBACD,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;oBAC5D,cAAc,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;gBACxC,CAAC;YACF,CAAC;QACF,CAAC;QACD,KAAK,CAAC,WAAW,CAAC,OAAO;YACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YACrC,OAAO,OAAO,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAC3E,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,QAAQ;YAChC,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,CAAA;YAC/C,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;YAC3B,sEAAsE;YACtE,MAAM,KAAK,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;YACpD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACd,OAAO,KAAK,IAAI,EAAE;gBACjB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACjB,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;oBAAE,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAC9C,CAAC,CAAA;QACF,CAAC;QACD,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC;KAC7D,CAAA;AACF,CAAC","sourcesContent":["import type { PubSubTransport } from './transport.js'\n\n/**\n * In-process transport for tests and single-process development. Delivery is\n * asynchronous (a microtask), like a real broker.\n */\nexport function memoryTransport(): PubSubTransport & {\n\t/** Active listeners per channel, for assertions. */\n\tlistenerCount(channel: string): number\n} {\n\tconst listeners = new Map<string, Set<(payload: string) => void>>()\n\tconst backlogs = new Map<string, { items: string[]; expiresAt: number }>()\n\n\treturn {\n\t\tasync close() {\n\t\t\tlisteners.clear()\n\t\t\tbacklogs.clear()\n\t\t},\n\t\tasync publish(messages, backlog) {\n\t\t\tfor (const { channel, payload } of messages) {\n\t\t\t\tif (backlog) {\n\t\t\t\t\tconst current = backlogs.get(channel)\n\t\t\t\t\tconst items =\n\t\t\t\t\t\tcurrent && current.expiresAt > Date.now() ? current.items : []\n\t\t\t\t\titems.push(payload)\n\t\t\t\t\titems.splice(0, Math.max(0, items.length - backlog.size))\n\t\t\t\t\tbacklogs.set(channel, {\n\t\t\t\t\t\titems,\n\t\t\t\t\t\texpiresAt: Date.now() + backlog.ttlSeconds * 1000\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tfor (const listener of [...(listeners.get(channel) ?? [])]) {\n\t\t\t\t\tqueueMicrotask(() => listener(payload))\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tasync readBacklog(channel) {\n\t\t\tconst backlog = backlogs.get(channel)\n\t\t\treturn backlog && backlog.expiresAt > Date.now() ? [...backlog.items] : []\n\t\t},\n\t\tasync subscribe(channel, listener) {\n\t\t\tconst set = listeners.get(channel) ?? new Set()\n\t\t\tlisteners.set(channel, set)\n\t\t\t// Wrap so the same listener can subscribe twice and unsubscribe once.\n\t\t\tconst entry = (payload: string) => listener(payload)\n\t\t\tset.add(entry)\n\t\t\treturn async () => {\n\t\t\t\tset.delete(entry)\n\t\t\t\tif (set.size === 0) listeners.delete(channel)\n\t\t\t}\n\t\t},\n\t\tlistenerCount: (channel) => listeners.get(channel)?.size ?? 0\n\t}\n}\n"]}
|