@moeru/eventa 1.0.0-alpha.9 → 1.0.0-beta.1

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 (54) hide show
  1. package/README.md +238 -1
  2. package/dist/adapters/broadcast-channel/index.d.mts +2 -2
  3. package/dist/adapters/broadcast-channel/index.mjs +2 -2
  4. package/dist/adapters/electron/main.d.mts +10 -3
  5. package/dist/adapters/electron/main.mjs +3 -3
  6. package/dist/adapters/electron/main.mjs.map +1 -1
  7. package/dist/adapters/electron/renderer.d.mts +2 -2
  8. package/dist/adapters/electron/renderer.mjs +3 -3
  9. package/dist/adapters/event-emitter/index.d.mts +2 -2
  10. package/dist/adapters/event-emitter/index.mjs +2 -2
  11. package/dist/adapters/event-target/index.d.mts +2 -2
  12. package/dist/adapters/event-target/index.mjs +2 -2
  13. package/dist/adapters/websocket/h3/index.d.mts +2 -2
  14. package/dist/adapters/websocket/h3/index.mjs +2 -2
  15. package/dist/adapters/websocket/h3/index.mjs.map +1 -1
  16. package/dist/adapters/websocket/index.d.mts +1 -1
  17. package/dist/adapters/websocket/native/index.d.mts +2 -2
  18. package/dist/adapters/websocket/native/index.mjs +2 -2
  19. package/dist/adapters/webworkers/index.d.mts +4 -43
  20. package/dist/adapters/webworkers/index.mjs +5 -4
  21. package/dist/adapters/webworkers/index.mjs.map +1 -1
  22. package/dist/adapters/webworkers/worker/index.d.mts +2 -1
  23. package/dist/adapters/webworkers/worker/index.mjs +4 -3
  24. package/dist/adapters/webworkers/worker/index.mjs.map +1 -1
  25. package/dist/adapters/worker-threads/index.d.mts +25 -0
  26. package/dist/adapters/worker-threads/index.mjs +43 -0
  27. package/dist/adapters/worker-threads/index.mjs.map +1 -0
  28. package/dist/adapters/worker-threads/worker/index.d.mts +26 -0
  29. package/dist/adapters/worker-threads/worker/index.mjs +46 -0
  30. package/dist/adapters/worker-threads/worker/index.mjs.map +1 -0
  31. package/dist/{context-C0RYgQg8.d.mts → context-ZVv99bcM.d.mts} +7 -4
  32. package/dist/{context-BygZzwvo.mjs → context-ex8urwfs.mjs} +1 -1
  33. package/dist/context-ex8urwfs.mjs.map +1 -0
  34. package/dist/{eventa-DWOtUOEf.d.mts → eventa-AJyw28P8.d.mts} +3 -2
  35. package/dist/index-CI_gUGXg.d.mts +522 -0
  36. package/dist/index.d.mts +4 -5
  37. package/dist/index.mjs +3 -3
  38. package/dist/{internal-C-bIJqJC.mjs → internal-De3z6hO5.mjs} +2 -2
  39. package/dist/{internal-C-bIJqJC.mjs.map → internal-De3z6hO5.mjs.map} +1 -1
  40. package/dist/{shared-BExRc0zC.mjs → shared-BZOulnwC.mjs} +2 -2
  41. package/dist/{shared-BExRc0zC.mjs.map → shared-BZOulnwC.mjs.map} +1 -1
  42. package/dist/{shared-DRAsaLuo.mjs → shared-BdqIf6iZ.mjs} +4 -10
  43. package/dist/shared-BdqIf6iZ.mjs.map +1 -0
  44. package/dist/{shared-Q10kRJA8.d.mts → shared-Cd4CLAdD.d.mts} +2 -2
  45. package/dist/shared-DgX1R_nY.d.mts +34 -0
  46. package/dist/src-DZ7si0kE.mjs +1169 -0
  47. package/dist/src-DZ7si0kE.mjs.map +1 -0
  48. package/package.json +19 -6
  49. package/dist/context-BygZzwvo.mjs.map +0 -1
  50. package/dist/index-DXQGU0bi.d.mts +0 -24
  51. package/dist/invoke-BB3tmZlr.d.mts +0 -137
  52. package/dist/shared-DRAsaLuo.mjs.map +0 -1
  53. package/dist/src-Bnf7MdlN.mjs +0 -284
  54. package/dist/src-Bnf7MdlN.mjs.map +0 -1
@@ -0,0 +1,1169 @@
1
+ import { a as defineEventa, l as nanoid } from "./context-ex8urwfs.mjs";
2
+
3
+ //#region src/context-extension-invoke-internal.ts
4
+ /**
5
+ * Read the internal invoke configuration from context extensions, if present.
6
+ * This is used by defineInvoke to determine which events should abort inflight invokes.
7
+ */
8
+ function getContextExtensionInvokeInternalConfig(ctx) {
9
+ const extensions = ctx.extensions;
10
+ if (!extensions || typeof extensions !== "object") return;
11
+ const internal = extensions.__internal;
12
+ if (!internal || typeof internal !== "object") return;
13
+ const invoke = internal.invoke;
14
+ if (!invoke || typeof invoke !== "object") return;
15
+ return invoke;
16
+ }
17
+ /**
18
+ * Register a fatal event/match expression that should terminate pending invokes.
19
+ * Adapters call this to wire their error events (e.g. worker error) into invoke.
20
+ */
21
+ function registerInvokeAbortEventListeners(ctx, eventOrMatch) {
22
+ const extensions = ctx.extensions ?? {};
23
+ const internal = extensions.__internal ?? {};
24
+ const invokeInternal = internal.invoke ?? {};
25
+ const abortOnEvents = Array.isArray(invokeInternal.abortOnEvents) ? invokeInternal.abortOnEvents : [];
26
+ if (!abortOnEvents.includes(eventOrMatch)) abortOnEvents.push(eventOrMatch);
27
+ invokeInternal.abortOnEvents = abortOnEvents;
28
+ internal.invoke = invokeInternal;
29
+ extensions.__internal = internal;
30
+ ctx.extensions = extensions;
31
+ return invokeInternal;
32
+ }
33
+
34
+ //#endregion
35
+ //#region src/invoke-shared.ts
36
+ let InvokeEventType = /* @__PURE__ */ function(InvokeEventType$1) {
37
+ InvokeEventType$1[InvokeEventType$1["SendEvent"] = 0] = "SendEvent";
38
+ InvokeEventType$1[InvokeEventType$1["SendEventError"] = 1] = "SendEventError";
39
+ InvokeEventType$1[InvokeEventType$1["SendEventStreamEnd"] = 2] = "SendEventStreamEnd";
40
+ InvokeEventType$1[InvokeEventType$1["SendEventAbort"] = 3] = "SendEventAbort";
41
+ InvokeEventType$1[InvokeEventType$1["ReceiveEvent"] = 4] = "ReceiveEvent";
42
+ InvokeEventType$1[InvokeEventType$1["ReceiveEventError"] = 5] = "ReceiveEventError";
43
+ InvokeEventType$1[InvokeEventType$1["ReceiveEventStreamEnd"] = 6] = "ReceiveEventStreamEnd";
44
+ return InvokeEventType$1;
45
+ }({});
46
+ function defineInvokeEventa(tag) {
47
+ if (!tag) tag = nanoid();
48
+ return {
49
+ sendEvent: {
50
+ ...defineEventa(`${tag}-send`),
51
+ invokeType: InvokeEventType.SendEvent
52
+ },
53
+ sendEventError: {
54
+ ...defineEventa(`${tag}-send-error`),
55
+ invokeType: InvokeEventType.SendEventError
56
+ },
57
+ sendEventStreamEnd: {
58
+ ...defineEventa(`${tag}-send-stream-end`),
59
+ invokeType: InvokeEventType.SendEventStreamEnd
60
+ },
61
+ sendEventAbort: {
62
+ ...defineEventa(`${tag}-send-abort`),
63
+ invokeType: InvokeEventType.SendEventAbort
64
+ },
65
+ receiveEvent: {
66
+ ...defineEventa(`${tag}-receive`),
67
+ invokeType: InvokeEventType.ReceiveEvent
68
+ },
69
+ receiveEventError: {
70
+ ...defineEventa(`${tag}-receive-error`),
71
+ invokeType: InvokeEventType.ReceiveEventError
72
+ },
73
+ receiveEventStreamEnd: {
74
+ ...defineEventa(`${tag}-receive-stream-end`),
75
+ invokeType: InvokeEventType.ReceiveEventStreamEnd
76
+ }
77
+ };
78
+ }
79
+ function isInvokeEventa(event) {
80
+ if (typeof event !== "object") return false;
81
+ if ("invokeType" in event) return true;
82
+ return false;
83
+ }
84
+ function isSendEvent(event) {
85
+ if (!isInvokeEventa(event)) return false;
86
+ return event.invokeType === InvokeEventType.SendEvent || event.invokeType === InvokeEventType.SendEventError || event.invokeType === InvokeEventType.SendEventStreamEnd || event.invokeType === InvokeEventType.SendEventAbort;
87
+ }
88
+ function isReceiveEvent(event) {
89
+ if (!isInvokeEventa(event)) return false;
90
+ return event.invokeType === InvokeEventType.ReceiveEvent || event.invokeType === InvokeEventType.ReceiveEventError || event.invokeType === InvokeEventType.ReceiveEventStreamEnd;
91
+ }
92
+
93
+ //#endregion
94
+ //#region src/utils.ts
95
+ function randomBetween(min, max) {
96
+ return Math.floor(Math.random() * (max - min + 1)) + min;
97
+ }
98
+ /**
99
+ * Checks if a value is an AsyncIterable.
100
+ *
101
+ * @param value
102
+ * @returns True if the value is an AsyncIterable.
103
+ */
104
+ function isAsyncIterable(value) {
105
+ return typeof value === "object" && value !== null && Symbol.asyncIterator in value;
106
+ }
107
+ /**
108
+ * Checks if an object is a ReadableStream.
109
+ *
110
+ * @link https://github.com/cloudflare/workerd/blob/88e8696ce7a5f8969a7e02a2dcfb6504c17c9e8d/src/cloudflare/internal/streaming-forms.ts#L3
111
+ * @param obj
112
+ * @returns True if the object looks like a ReadableStream.
113
+ */
114
+ function isReadableStream(obj) {
115
+ return !!(obj && typeof obj === "object" && "getReader" in obj && typeof obj.getReader === "function");
116
+ }
117
+ function createAbortError(reason) {
118
+ if (reason instanceof Error && reason.name === "AbortError") return reason;
119
+ if (typeof DOMException !== "undefined") try {
120
+ return new DOMException(reason ? String(reason) : "Aborted", "AbortError");
121
+ } catch {}
122
+ const error = reason instanceof Error ? reason : new Error(reason ? String(reason) : "Aborted");
123
+ error.name = "AbortError";
124
+ return error;
125
+ }
126
+ function isAbortError(error) {
127
+ return error instanceof Error && error.name === "AbortError";
128
+ }
129
+ function createUntilTriggeredOnce(fn) {
130
+ let resolve;
131
+ const promise = new Promise((res) => {
132
+ resolve = res;
133
+ });
134
+ const handler = async (...args) => {
135
+ const res = await fn(...args);
136
+ resolve(res);
137
+ return res;
138
+ };
139
+ return {
140
+ onceTriggered: promise,
141
+ wrapper: handler
142
+ };
143
+ }
144
+ function createUntilTriggered(fn) {
145
+ let resolve;
146
+ const promise = new Promise((res) => {
147
+ resolve = res;
148
+ });
149
+ const handler = (...args) => {
150
+ resolve();
151
+ return fn(...args);
152
+ };
153
+ return {
154
+ promise,
155
+ handler
156
+ };
157
+ }
158
+ function createUntil(options) {
159
+ let resolve;
160
+ const promise = new Promise((res) => {
161
+ resolve = res;
162
+ });
163
+ if (options?.intervalHandler) setInterval(() => {
164
+ options?.intervalHandler?.().then((shouldResolve) => {
165
+ if (shouldResolve) resolve(void 0);
166
+ });
167
+ }, options.interval ?? 50);
168
+ return {
169
+ promise,
170
+ handler: resolve
171
+ };
172
+ }
173
+
174
+ //#endregion
175
+ //#region src/invoke.ts
176
+ function isExtendableInvokeResponseLike(value) {
177
+ if (!isReceiveEvent(value)) return false;
178
+ return typeof value.body?.content === "object" && value.body?.content != null && "response" in value.body.content && (!("invokeResponse" in value.body.content) || "invokeResponse" in value.body.content && (typeof value.body.content.invokeResponse === "object" || typeof value.body.content.invokeResponse === "undefined"));
179
+ }
180
+ /**
181
+ * Create a unary invoke function (client side).
182
+ *
183
+ * It supports unary or streaming requests, but returns a single response.
184
+ * Use `defineStreamInvoke` when you expect a stream of responses.
185
+ *
186
+ * If you want stream input, set `Req` to `ReadableStream<T>` or `AsyncIterable<T>`
187
+ * (or a union type like `T | ReadableStream<T>` for optional streaming).
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * // 1) Define eventa once (shared by client/server)
192
+ * const events = defineInvokeEventa<{ id: string }, { name: string }>()
193
+ *
194
+ * // 2) Client: define invoke function
195
+ * const invoke = defineInvoke(clientCtx, events)
196
+ *
197
+ * // 3) Call
198
+ * const res = await invoke({ name: 'alice' })
199
+ * ```
200
+ *
201
+ * @example
202
+ * ```ts
203
+ * // Stream request -> unary response
204
+ * const events = defineInvokeEventa<number, ReadableStream<number>>()
205
+ *
206
+ * defineInvokeHandler(serverCtx, events, async (payload) => {
207
+ * let sum = 0
208
+ * for await (const value of payload) {
209
+ * sum += value
210
+ * }
211
+ *
212
+ * return sum
213
+ * })
214
+ *
215
+ * const invoke = defineInvoke(clientCtx, events)
216
+ * const input = new ReadableStream<number>({
217
+ * start(controller) {
218
+ * controller.enqueue(1)
219
+ * controller.enqueue(2)
220
+ * controller.close()
221
+ * },
222
+ * })
223
+ *
224
+ * const total = await invoke(input)
225
+ * ```
226
+ *
227
+ * @param ctx Event context on the caller/client side.
228
+ * @param event Invoke event definition created by `defineInvokeEventa`.
229
+ */
230
+ function defineInvoke(ctx, event) {
231
+ async function getContext() {
232
+ if (typeof ctx === "function") {
233
+ const resolvedCtx = ctx();
234
+ if (resolvedCtx instanceof Promise) return await resolvedCtx;
235
+ return resolvedCtx;
236
+ }
237
+ return ctx;
238
+ }
239
+ function _invoke(req, options) {
240
+ return new Promise((resolve, reject) => {
241
+ getContext().then((ctx$1) => {
242
+ const invokeId = nanoid();
243
+ const invokeReceiveEvent = defineEventa(`${event.receiveEvent.id}-${invokeId}`);
244
+ const invokeReceiveEventError = defineEventa(`${event.receiveEventError.id}-${invokeId}`);
245
+ const { signal, ...emitOptions } = options ?? {};
246
+ let finished = false;
247
+ const onAbort = () => {
248
+ ctx$1.emit(event.sendEventAbort, {
249
+ invokeId,
250
+ content: signal?.reason
251
+ }, emitOptions);
252
+ finishReject(createAbortError(signal?.reason));
253
+ };
254
+ const invokeInternalConfig = getContextExtensionInvokeInternalConfig(ctx$1);
255
+ const abortOffs = [];
256
+ const onAbortEvent = (payload, eventOptions) => {
257
+ const mappedError = invokeInternalConfig?.mapAbortError?.(payload, eventOptions);
258
+ if (typeof mappedError !== "undefined") {
259
+ finishReject(mappedError);
260
+ return;
261
+ }
262
+ const body = payload?.body;
263
+ finishReject(body && typeof body === "object" && "error" in body ? body.error : typeof body !== "undefined" ? body : payload);
264
+ };
265
+ const cleanup = () => {
266
+ ctx$1.off(invokeReceiveEvent);
267
+ ctx$1.off(invokeReceiveEventError);
268
+ for (const off of abortOffs) off();
269
+ if (signal) signal.removeEventListener("abort", onAbort);
270
+ };
271
+ const finishReject = (error) => {
272
+ if (finished) return;
273
+ finished = true;
274
+ reject(error);
275
+ cleanup();
276
+ };
277
+ const finishResolve = (value) => {
278
+ if (finished) return;
279
+ finished = true;
280
+ resolve(value);
281
+ cleanup();
282
+ };
283
+ ctx$1.on(invokeReceiveEvent, (payload) => {
284
+ if (!payload.body) return;
285
+ if (payload.body.invokeId !== invokeId) return;
286
+ const { content } = payload.body;
287
+ finishResolve(content);
288
+ });
289
+ ctx$1.on(invokeReceiveEventError, (payload) => {
290
+ if (!payload.body) return;
291
+ if (payload.body.invokeId !== invokeId) return;
292
+ const { error } = payload.body.content;
293
+ finishReject(error);
294
+ });
295
+ if (invokeInternalConfig?.abortOnEvents?.length) for (const eventOrMatch of invokeInternalConfig.abortOnEvents) abortOffs.push(ctx$1.on(eventOrMatch, onAbortEvent));
296
+ if (signal) {
297
+ if (signal.aborted) {
298
+ onAbort();
299
+ return;
300
+ }
301
+ signal.addEventListener("abort", onAbort, { once: true });
302
+ }
303
+ if (!isReadableStream(req) && !isAsyncIterable(req)) ctx$1.emit(event.sendEvent, {
304
+ invokeId,
305
+ content: req
306
+ }, emitOptions);
307
+ else {
308
+ const sendChunk = (chunk) => {
309
+ if (finished) return;
310
+ ctx$1.emit(event.sendEvent, {
311
+ invokeId,
312
+ content: chunk,
313
+ isReqStream: true
314
+ }, emitOptions);
315
+ };
316
+ const sendEnd = () => {
317
+ if (finished) return;
318
+ ctx$1.emit(event.sendEventStreamEnd, {
319
+ invokeId,
320
+ content: void 0
321
+ }, emitOptions);
322
+ };
323
+ const pump = async () => {
324
+ try {
325
+ for await (const chunk of req) {
326
+ if (signal?.aborted) return;
327
+ sendChunk(chunk);
328
+ }
329
+ sendEnd();
330
+ } catch (error) {
331
+ if (signal?.aborted) return;
332
+ if (isAbortError(error)) {
333
+ ctx$1.emit(event.sendEventAbort, {
334
+ invokeId,
335
+ content: error
336
+ }, emitOptions);
337
+ return;
338
+ }
339
+ ctx$1.emit(event.sendEventError, {
340
+ invokeId,
341
+ content: error
342
+ }, emitOptions);
343
+ }
344
+ };
345
+ pump();
346
+ }
347
+ });
348
+ });
349
+ }
350
+ return _invoke;
351
+ }
352
+ /**
353
+ * Create a map of invoke functions from a map of invoke events (client side).
354
+ *
355
+ * @example
356
+ * ```ts
357
+ * const events = {
358
+ * double: defineInvokeEventa<number, number>(),
359
+ * greet: defineInvokeEventa<string, { name: string }>(),
360
+ * }
361
+ *
362
+ * const invokes = defineInvokes(ctx, events)
363
+ * const result = await invokes.double(2)
364
+ * ```
365
+ *
366
+ * @param ctx Event context on the caller/client side.
367
+ * @param events Map of invoke events created by `defineInvokeEventa`.
368
+ */
369
+ function defineInvokes(ctx, events) {
370
+ return Object.keys(events).reduce((invokes, key) => {
371
+ invokes[key] = defineInvoke(ctx, events[key]);
372
+ return invokes;
373
+ }, {});
374
+ }
375
+ /**
376
+ * Define a unary invoke handler (server side).
377
+ *
378
+ * The handler can accept a unary or streaming request; it must return
379
+ * a single response (or an extendable response envelope).
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * const events = defineInvokeEventa<{ id: string }, { name: string }>()
384
+ *
385
+ * defineInvokeHandler(serverCtx, events, ({ name }) => ({
386
+ * id: `user-${name}`,
387
+ * }))
388
+ * ```
389
+ *
390
+ * @param ctx Event context on the handler/server side.
391
+ * @param event Invoke event definition created by `defineInvokeEventa`.
392
+ * @param handler Handler that returns a response (or response + metadata).
393
+ */
394
+ function defineInvokeHandler(ctx, event, handler) {
395
+ if (!ctx.invokeHandlers) ctx.invokeHandlers = /* @__PURE__ */ new Map();
396
+ let handlers = ctx.invokeHandlers?.get(event.sendEvent.id);
397
+ if (!handlers) {
398
+ handlers = /* @__PURE__ */ new Map();
399
+ ctx.invokeHandlers?.set(event.sendEvent.id, handlers);
400
+ }
401
+ let internalHandler = handlers.get(handler);
402
+ if (!internalHandler) {
403
+ const streamStates = /* @__PURE__ */ new Map();
404
+ const abortControllers = /* @__PURE__ */ new Map();
405
+ const abortReasons = /* @__PURE__ */ new Map();
406
+ const scheduleAbort = (controller, reason) => {
407
+ if (typeof queueMicrotask !== "undefined") {
408
+ queueMicrotask(() => controller.abort(reason));
409
+ return;
410
+ }
411
+ Promise.resolve().then(() => controller.abort(reason));
412
+ };
413
+ const handleInvoke = async (invokeId, payload, options) => {
414
+ const abortController = new AbortController();
415
+ abortControllers.set(invokeId, abortController);
416
+ if (abortReasons.has(invokeId)) scheduleAbort(abortController, abortReasons.get(invokeId));
417
+ const handlerOptions = options ? {
418
+ ...options,
419
+ abortController
420
+ } : { abortController };
421
+ try {
422
+ const response = await handler(payload, handlerOptions);
423
+ ctx.emit({
424
+ ...defineEventa(`${event.receiveEvent.id}-${invokeId}`),
425
+ invokeType: event.receiveEvent.invokeType
426
+ }, {
427
+ invokeId,
428
+ content: response
429
+ }, options);
430
+ } catch (error) {
431
+ ctx.emit({
432
+ ...defineEventa(`${event.receiveEventError.id}-${invokeId}`),
433
+ invokeType: event.receiveEventError.invokeType
434
+ }, {
435
+ invokeId,
436
+ content: { error }
437
+ }, options);
438
+ } finally {
439
+ abortControllers.delete(invokeId);
440
+ abortReasons.delete(invokeId);
441
+ }
442
+ };
443
+ const onSend = async (payload, options) => {
444
+ if (!payload.body) return;
445
+ if (!payload.body.invokeId) return;
446
+ const invokeId = payload.body.invokeId;
447
+ if (payload.body.isReqStream) {
448
+ let controller = streamStates.get(invokeId);
449
+ if (!controller) {
450
+ let localController;
451
+ const reqStream = new ReadableStream({ start(c) {
452
+ localController = c;
453
+ } });
454
+ controller = localController;
455
+ streamStates.set(invokeId, controller);
456
+ handleInvoke(invokeId, reqStream, options);
457
+ }
458
+ controller.enqueue(payload.body.content);
459
+ return;
460
+ }
461
+ handleInvoke(invokeId, payload.body?.content, options);
462
+ };
463
+ const onSendStreamEnd = (payload, options) => {
464
+ if (!payload.body) return;
465
+ if (!payload.body.invokeId) return;
466
+ const invokeId = payload.body.invokeId;
467
+ let controller = streamStates.get(invokeId);
468
+ if (!controller) {
469
+ let localController;
470
+ const reqStream = new ReadableStream({ start(c) {
471
+ localController = c;
472
+ } });
473
+ controller = localController;
474
+ streamStates.set(invokeId, controller);
475
+ handleInvoke(invokeId, reqStream, options);
476
+ }
477
+ controller.close();
478
+ streamStates.delete(invokeId);
479
+ };
480
+ const onSendAbort = (payload, options) => {
481
+ if (!payload.body) return;
482
+ if (!payload.body.invokeId) return;
483
+ const invokeId = payload.body.invokeId;
484
+ const reason = payload.body.content;
485
+ const abortController = abortControllers.get(invokeId);
486
+ if (!abortController) {
487
+ abortReasons.set(invokeId, reason);
488
+ let streamController$1 = streamStates.get(invokeId);
489
+ if (!streamController$1) {
490
+ let localController;
491
+ const reqStream = new ReadableStream({ start(c) {
492
+ localController = c;
493
+ } });
494
+ streamController$1 = localController;
495
+ streamStates.set(invokeId, streamController$1);
496
+ handleInvoke(invokeId, reqStream, options);
497
+ }
498
+ streamController$1.error(createAbortError(reason));
499
+ streamStates.delete(invokeId);
500
+ return;
501
+ }
502
+ scheduleAbort(abortController, reason);
503
+ const streamController = streamStates.get(invokeId);
504
+ if (streamController) {
505
+ streamController.error(createAbortError(reason));
506
+ streamStates.delete(invokeId);
507
+ }
508
+ };
509
+ internalHandler = {
510
+ onSend,
511
+ onSendStreamEnd,
512
+ onSendAbort
513
+ };
514
+ handlers.set(handler, internalHandler);
515
+ ctx.on(event.sendEvent, internalHandler.onSend);
516
+ ctx.on(event.sendEventStreamEnd, internalHandler.onSendStreamEnd);
517
+ ctx.on(event.sendEventAbort, internalHandler.onSendAbort);
518
+ }
519
+ return () => {
520
+ ctx.off(event.sendEvent, internalHandler.onSend);
521
+ ctx.off(event.sendEventStreamEnd, internalHandler.onSendStreamEnd);
522
+ ctx.off(event.sendEventAbort, internalHandler.onSendAbort);
523
+ };
524
+ }
525
+ /**
526
+ * Define multiple invoke handlers in batch (server side).
527
+ *
528
+ * @example
529
+ * ```ts
530
+ * const events = {
531
+ * double: defineInvokeEventa<number, number>(),
532
+ * greet: defineInvokeEventa<string, { name: string }>(),
533
+ * }
534
+ *
535
+ * defineInvokeHandlers(ctx, events, {
536
+ * double: value => value * 2,
537
+ * greet: ({ name }) => `hi ${name}`,
538
+ * })
539
+ * ```
540
+ *
541
+ * @param ctx Event context on the handler/server side.
542
+ * @param events Map of invoke events created by `defineInvokeEventa`.
543
+ * @param handlers Map of handlers keyed by event name.
544
+ */
545
+ function defineInvokeHandlers(ctx, events, handlers) {
546
+ const eventKeys = Object.keys(events);
547
+ const handlerKeys = new Set(Object.keys(handlers));
548
+ if (eventKeys.length !== handlerKeys.size || !eventKeys.every((key) => handlerKeys.has(key))) throw new Error("The keys of events and handlers must match.");
549
+ return eventKeys.reduce((returnValues, key) => {
550
+ returnValues[key] = defineInvokeHandler(ctx, events[key], handlers[key]);
551
+ return returnValues;
552
+ }, {});
553
+ }
554
+ /**
555
+ * Remove one or all invoke handlers for a specific invoke event (server side).
556
+ *
557
+ * @example
558
+ * ```ts
559
+ * const off = defineInvokeHandler(ctx, events, handler)
560
+ * off() // remove one handler
561
+ *
562
+ * // or remove all handlers for the event:
563
+ * undefineInvokeHandler(ctx, events)
564
+ * ```
565
+ *
566
+ * @param ctx Event context on the handler/server side.
567
+ * @param event Invoke event definition created by `defineInvokeEventa`.
568
+ * @param handler Specific handler to remove (omit to remove all).
569
+ * @returns `true` if at least one handler was removed, `false` otherwise
570
+ */
571
+ function undefineInvokeHandler(ctx, event, handler) {
572
+ if (!ctx.invokeHandlers) return false;
573
+ const handlers = ctx.invokeHandlers?.get(event.sendEvent.id);
574
+ if (!handlers) return false;
575
+ if (handler) {
576
+ const internalHandler = handlers.get(handler);
577
+ if (!internalHandler) return false;
578
+ ctx.off(event.sendEvent, internalHandler.onSend);
579
+ ctx.off(event.sendEventStreamEnd, internalHandler.onSendStreamEnd);
580
+ ctx.off(event.sendEventAbort, internalHandler.onSendAbort);
581
+ ctx.invokeHandlers.delete(event.sendEvent.id);
582
+ return true;
583
+ }
584
+ let returnValue = false;
585
+ for (const internalHandlers of handlers.values()) {
586
+ ctx.off(event.sendEvent, internalHandlers.onSend);
587
+ ctx.off(event.sendEventStreamEnd, internalHandlers.onSendStreamEnd);
588
+ ctx.off(event.sendEventAbort, internalHandlers.onSendAbort);
589
+ returnValue = true;
590
+ }
591
+ ctx.invokeHandlers.delete(event.sendEvent.id);
592
+ return returnValue;
593
+ }
594
+
595
+ //#endregion
596
+ //#region src/invoke-extension-transfer.ts
597
+ function withTransfer(body, transfer) {
598
+ return {
599
+ response: body,
600
+ invokeResponse: { transfer: transfer ?? [] }
601
+ };
602
+ }
603
+
604
+ //#endregion
605
+ //#region src/invoke-remote-methods.ts
606
+ const DEFAULT_FUNCTION_STUB_OPTIONS = {
607
+ maxDepth: 32,
608
+ maxFunctions: 32,
609
+ tagPrefix: "eventa-invoke-fn-",
610
+ onDisallowedTag: "ignore",
611
+ autoDisposeMs: 0,
612
+ strict: false
613
+ };
614
+ function createRemoteMethodTagPrefix(prefix = DEFAULT_FUNCTION_STUB_OPTIONS.tagPrefix) {
615
+ return `${prefix}${nanoid()}-`;
616
+ }
617
+ function normalizeFunctionStubOptions(options) {
618
+ if (options === true) return {
619
+ allow: true,
620
+ ...DEFAULT_FUNCTION_STUB_OPTIONS
621
+ };
622
+ if (!options) return {
623
+ allow: false,
624
+ ...DEFAULT_FUNCTION_STUB_OPTIONS
625
+ };
626
+ return {
627
+ allow: options.allow ?? true,
628
+ maxDepth: options.maxDepth ?? DEFAULT_FUNCTION_STUB_OPTIONS.maxDepth,
629
+ maxFunctions: options.maxFunctions ?? DEFAULT_FUNCTION_STUB_OPTIONS.maxFunctions,
630
+ tagPrefix: options.tagPrefix ?? DEFAULT_FUNCTION_STUB_OPTIONS.tagPrefix,
631
+ onDisallowedTag: options.onDisallowedTag ?? DEFAULT_FUNCTION_STUB_OPTIONS.onDisallowedTag,
632
+ autoDisposeMs: options.autoDisposeMs ?? DEFAULT_FUNCTION_STUB_OPTIONS.autoDisposeMs,
633
+ strict: options.strict ?? DEFAULT_FUNCTION_STUB_OPTIONS.strict
634
+ };
635
+ }
636
+ function resolveFunctionStubOptions(defaults, override) {
637
+ const base = normalizeFunctionStubOptions(defaults);
638
+ if (typeof override === "undefined") return base;
639
+ if (typeof override === "boolean") return {
640
+ ...base,
641
+ allow: override
642
+ };
643
+ return {
644
+ ...base,
645
+ ...normalizeFunctionStubOptions(override)
646
+ };
647
+ }
648
+ function isPlainObject(value) {
649
+ if (value == null || typeof value !== "object") return false;
650
+ const prototype = Object.getPrototypeOf(value);
651
+ return prototype === Object.prototype || prototype === null;
652
+ }
653
+ function isInvokeFunctionStubPayload(value) {
654
+ if (!isPlainObject(value)) return false;
655
+ if (!("__eventaInvoke" in value)) return false;
656
+ const stub = value.__eventaInvoke;
657
+ return !!stub && typeof stub === "object" && typeof stub.tag === "string";
658
+ }
659
+ function hasInvokeFunctionStubKey(value) {
660
+ return isPlainObject(value) && "__eventaInvoke" in value;
661
+ }
662
+ function serializeInvokeFunctionPayload(value, ctx, options) {
663
+ if (!options.allow) return {
664
+ value,
665
+ dispose: () => void 0
666
+ };
667
+ let functionCount = 0;
668
+ const seen = /* @__PURE__ */ new WeakMap();
669
+ const disposers = [];
670
+ const walk = (input, depth) => {
671
+ if (typeof input === "function") {
672
+ if (functionCount >= options.maxFunctions) throw new Error(`Too many function stubs in invoke payload (max ${options.maxFunctions}).`);
673
+ functionCount += 1;
674
+ const tag = `${options.tagPrefix}${nanoid()}`;
675
+ const off = defineInvokeHandler(ctx, defineInvokeEventa(tag), (payload, handlerOptions) => {
676
+ return input(payload, handlerOptions);
677
+ });
678
+ disposers.push(off);
679
+ return { __eventaInvoke: { tag } };
680
+ }
681
+ if (input == null || typeof input !== "object") return input;
682
+ if (depth > options.maxDepth) throw new Error(`Invoke payload is too deep (max ${options.maxDepth}).`);
683
+ if (seen.has(input)) return seen.get(input);
684
+ if (Array.isArray(input)) {
685
+ const output$1 = Array.from({ length: input.length });
686
+ seen.set(input, output$1);
687
+ for (let i = 0; i < input.length; i += 1) output$1[i] = walk(input[i], depth + 1);
688
+ return output$1;
689
+ }
690
+ if (!isPlainObject(input)) return input;
691
+ const output = Object.create(null);
692
+ seen.set(input, output);
693
+ for (const [key, child] of Object.entries(input)) output[key] = walk(child, depth + 1);
694
+ return output;
695
+ };
696
+ return {
697
+ value: walk(value, 0),
698
+ dispose: () => {
699
+ for (const off of disposers) off();
700
+ }
701
+ };
702
+ }
703
+ function deserializeInvokeFunctionPayload(value, ctx, options) {
704
+ if (!options.allow) return value;
705
+ let functionCount = 0;
706
+ const seen = /* @__PURE__ */ new WeakMap();
707
+ const walk = (input, depth) => {
708
+ if (input == null || typeof input !== "object") return input;
709
+ if (depth > options.maxDepth) throw new Error(`Invoke payload is too deep (max ${options.maxDepth}).`);
710
+ if (isInvokeFunctionStubPayload(input)) {
711
+ if (functionCount >= options.maxFunctions) throw new Error(`Too many function stubs in invoke payload (max ${options.maxFunctions}).`);
712
+ const tag = input.__eventaInvoke.tag;
713
+ if (options.tagPrefix && !tag.startsWith(options.tagPrefix)) {
714
+ if (options.onDisallowedTag === "throw") throw new Error(`Invoke function tag not allowed: ${tag}`);
715
+ return input;
716
+ }
717
+ functionCount += 1;
718
+ return defineInvoke(ctx, defineInvokeEventa(tag));
719
+ } else if (options.strict && hasInvokeFunctionStubKey(input)) throw new Error("Invalid invoke function stub payload.");
720
+ if (seen.has(input)) return seen.get(input);
721
+ if (Array.isArray(input)) {
722
+ const output$1 = Array.from({ length: input.length });
723
+ seen.set(input, output$1);
724
+ for (let i = 0; i < input.length; i += 1) output$1[i] = walk(input[i], depth + 1);
725
+ return output$1;
726
+ }
727
+ if (!isPlainObject(input)) return input;
728
+ const output = Object.create(null);
729
+ seen.set(input, output);
730
+ for (const [key, child] of Object.entries(input)) output[key] = walk(child, depth + 1);
731
+ return output;
732
+ };
733
+ return walk(value, 0);
734
+ }
735
+ /**
736
+ * Enable "remote method" payloads for invoke: functions in the request body are
737
+ * serialized into stub descriptors and rehydrated into invoke callers on the
738
+ * receiving side.
739
+ *
740
+ * This is an adapter around the plain-value RPC primitives `defineInvoke` and
741
+ * `defineInvokeHandler`. It keeps the core invoke APIs clean while offering an
742
+ * opt-in bridge for function values.
743
+ *
744
+ * @example
745
+ * ```ts
746
+ * const remote = withRemoteMethods({ allow: true })
747
+ * const events = defineInvokeEventa<{ output: number }, { helper: (n: number) => Promise<number> }>()
748
+ *
749
+ * // server (handler)
750
+ * remote.defineInvokeHandler(serverCtx, events, async ({ helper }) => {
751
+ * const output = await helper(21)
752
+ * return { output }
753
+ * })
754
+ *
755
+ * // client (caller)
756
+ * const invoke = remote.defineInvoke(clientCtx, events)
757
+ * const result = await invoke({ helper: async n => n * 2 }, { functionStubs: true })
758
+ * ```
759
+ *
760
+ * @example
761
+ * ```ts
762
+ * // Manual cleanup when you fire-and-forget or cancel midway:
763
+ * const invoke = remote.defineInvoke(clientCtx, events)
764
+ * const result = invoke({ helper: () => 'ok' }, { functionStubs: true })
765
+ * result.dispose()
766
+ * await result
767
+ * ```
768
+ *
769
+ * Security notes:
770
+ * - This feature is off by default. Enabling it allows the remote side to call
771
+ * back into your process; only use with trusted peers.
772
+ * - Function stubs are tagged; prefer a unique `tagPrefix` to avoid collisions
773
+ * (see `createRemoteMethodTagPrefix`).
774
+ * - `maxDepth`, `maxFunctions`, and `autoDisposeMs` limit attack surface and
775
+ * resource usage. `autoDisposeMs` is useful for fire-and-forget calls.
776
+ * - Objects are rebuilt with a null prototype to mitigate `__proto__` pollution.
777
+ * - Enable `strict` to reject malformed `__eventaInvoke` payloads.
778
+ *
779
+ * @param defaultOptions Defaults for function stub behavior. Use `{ allow: true }`
780
+ * to enable, or provide `maxDepth`, `maxFunctions`, `tagPrefix`,
781
+ * `onDisallowedTag`, `autoDisposeMs`, and `strict` for stricter control.
782
+ */
783
+ function withRemoteMethods(defaultOptions) {
784
+ return {
785
+ defineInvoke(ctx, event) {
786
+ const baseInvoke = defineInvoke(ctx, event);
787
+ const invoke = ((req, options) => {
788
+ const { functionStubs, ...invokeOptions } = options ?? {};
789
+ const normalizedOptions = resolveFunctionStubOptions(defaultOptions, functionStubs);
790
+ if (!normalizedOptions.allow) {
791
+ const wrapped$1 = baseInvoke(req, invokeOptions);
792
+ wrapped$1.dispose = () => void 0;
793
+ return wrapped$1;
794
+ }
795
+ let serialized;
796
+ try {
797
+ serialized = serializeInvokeFunctionPayload(req, ctx, normalizedOptions);
798
+ } catch (error) {
799
+ const rejected = Promise.reject(error);
800
+ rejected.dispose = () => void 0;
801
+ return rejected;
802
+ }
803
+ let disposed = false;
804
+ const dispose = () => {
805
+ if (disposed) return;
806
+ disposed = true;
807
+ serialized.dispose();
808
+ };
809
+ let autoDisposeTimer;
810
+ if (normalizedOptions.autoDisposeMs > 0) autoDisposeTimer = setTimeout(() => {
811
+ dispose();
812
+ }, normalizedOptions.autoDisposeMs);
813
+ const finalize = () => {
814
+ if (autoDisposeTimer) clearTimeout(autoDisposeTimer);
815
+ dispose();
816
+ };
817
+ const wrapped = baseInvoke(serialized.value, invokeOptions).finally(finalize);
818
+ wrapped.dispose = finalize;
819
+ return wrapped;
820
+ });
821
+ return invoke;
822
+ },
823
+ defineInvokeHandler(ctx, event, handler) {
824
+ const normalizedOptions = resolveFunctionStubOptions(defaultOptions);
825
+ return defineInvokeHandler(ctx, event, async (payload, options) => {
826
+ return handler(normalizedOptions.allow ? deserializeInvokeFunctionPayload(payload, ctx, normalizedOptions) : payload, options);
827
+ });
828
+ }
829
+ };
830
+ }
831
+
832
+ //#endregion
833
+ //#region src/stream.ts
834
+ /**
835
+ * Create a stream invoke function (client side).
836
+ *
837
+ * Use when the response is streamed and the request may be unary or streaming.
838
+ *
839
+ * Common patterns:
840
+ * - Unary request -> stream response (server-streaming)
841
+ * - Stream request -> stream response (bi-directional streaming)
842
+ *
843
+ * @example
844
+ * ```ts
845
+ * // 1) Define eventa once (shared by client/server)
846
+ * const events = defineInvokeEventa<Progress | Result, Params>()
847
+ *
848
+ * // 2) Client: define invoke function
849
+ * const invoke = defineStreamInvoke(clientCtx, events)
850
+ *
851
+ * // 3) Call with unary request
852
+ * for await (const msg of invoke({ name: 'alice' })) {
853
+ * console.log(msg)
854
+ * }
855
+ * ```
856
+ *
857
+ * @example
858
+ * ```ts
859
+ * // Client-streaming request
860
+ * const input = new ReadableStream<number>({
861
+ * start(c) { c.enqueue(1); c.enqueue(2); c.close() },
862
+ * })
863
+ *
864
+ * for await (const msg of invoke(input)) {
865
+ * console.log(msg)
866
+ * }
867
+ * ```
868
+ *
869
+ * @param clientCtx Event context on the caller/client side.
870
+ * @param event Invoke event definition created by `defineInvokeEventa`.
871
+ */
872
+ function defineStreamInvoke(clientCtx, event) {
873
+ return (req, options) => {
874
+ const invokeId = nanoid();
875
+ const { signal, ...emitOptions } = options ?? {};
876
+ let onAbort;
877
+ const invokeReceiveEvent = defineEventa(`${event.receiveEvent.id}-${invokeId}`);
878
+ const invokeReceiveEventError = defineEventa(`${event.receiveEventError.id}-${invokeId}`);
879
+ const invokeReceiveEventStreamEnd = defineEventa(`${event.receiveEventStreamEnd.id}-${invokeId}`);
880
+ const stream = new ReadableStream({
881
+ start(controller) {
882
+ const cleanup = () => {
883
+ clientCtx.off(invokeReceiveEvent);
884
+ clientCtx.off(invokeReceiveEventError);
885
+ clientCtx.off(invokeReceiveEventStreamEnd);
886
+ if (signal && onAbort) signal.removeEventListener("abort", onAbort);
887
+ };
888
+ onAbort = () => {
889
+ clientCtx.emit(event.sendEventAbort, {
890
+ invokeId,
891
+ content: signal?.reason
892
+ }, emitOptions);
893
+ controller.error(createAbortError(signal?.reason));
894
+ cleanup();
895
+ };
896
+ clientCtx.on(invokeReceiveEvent, (payload) => {
897
+ if (!payload.body) return;
898
+ if (payload.body.invokeId !== invokeId) return;
899
+ controller.enqueue(payload.body.content);
900
+ });
901
+ clientCtx.on(invokeReceiveEventError, (payload) => {
902
+ if (!payload.body) return;
903
+ if (payload.body.invokeId !== invokeId) return;
904
+ controller.error(payload.body.content.error);
905
+ cleanup();
906
+ });
907
+ clientCtx.on(invokeReceiveEventStreamEnd, (payload) => {
908
+ if (!payload.body) return;
909
+ if (payload.body.invokeId !== invokeId) return;
910
+ controller.close();
911
+ cleanup();
912
+ });
913
+ if (signal && onAbort) {
914
+ if (signal.aborted) {
915
+ onAbort();
916
+ return;
917
+ }
918
+ signal.addEventListener("abort", onAbort, { once: true });
919
+ }
920
+ },
921
+ cancel(reason) {
922
+ clientCtx.emit(event.sendEventAbort, {
923
+ invokeId,
924
+ content: reason
925
+ }, emitOptions);
926
+ clientCtx.off(invokeReceiveEvent);
927
+ clientCtx.off(invokeReceiveEventError);
928
+ clientCtx.off(invokeReceiveEventStreamEnd);
929
+ if (signal && onAbort) signal.removeEventListener("abort", onAbort);
930
+ }
931
+ });
932
+ if (isReadableStream(req) || isAsyncIterable(req)) {
933
+ const sendChunk = (chunk) => {
934
+ clientCtx.emit(event.sendEvent, {
935
+ invokeId,
936
+ content: chunk,
937
+ isReqStream: true
938
+ }, emitOptions);
939
+ };
940
+ const sendEnd = () => {
941
+ clientCtx.emit(event.sendEventStreamEnd, {
942
+ invokeId,
943
+ content: void 0
944
+ }, emitOptions);
945
+ };
946
+ const pump = async () => {
947
+ try {
948
+ for await (const chunk of req) {
949
+ if (signal?.aborted) return;
950
+ sendChunk(chunk);
951
+ }
952
+ sendEnd();
953
+ } catch (error) {
954
+ if (signal?.aborted) return;
955
+ if (isAbortError(error)) {
956
+ clientCtx.emit(event.sendEventAbort, {
957
+ invokeId,
958
+ content: error
959
+ }, emitOptions);
960
+ return;
961
+ }
962
+ clientCtx.emit(event.sendEventError, {
963
+ invokeId,
964
+ content: error
965
+ }, emitOptions);
966
+ }
967
+ };
968
+ pump();
969
+ } else clientCtx.emit(event.sendEvent, {
970
+ invokeId,
971
+ content: req
972
+ }, emitOptions);
973
+ return stream;
974
+ };
975
+ }
976
+ /**
977
+ * Define a stream invoke handler (server side).
978
+ *
979
+ * The handler can receive either:
980
+ * - a unary request `Req`
981
+ * - a streaming request `ReadableStream<Req>` / `AsyncIterable<Req>`
982
+ *
983
+ * It must return an async generator of response messages.
984
+ *
985
+ * @example
986
+ * ```ts
987
+ * const events = defineInvokeEventa<Progress | Result, Params>()
988
+ *
989
+ * defineStreamInvokeHandler(serverCtx, events, async function* (payload) {
990
+ * if (isReadableStream<Params>(payload) || isAsyncIterable<Params>(payload)) {
991
+ * for await (const item of payload) {
992
+ * yield { type: 'progress', value: item }
993
+ * }
994
+ * }
995
+ *
996
+ * yield { type: 'result', ok: true }
997
+ * })
998
+ * ```
999
+ *
1000
+ * @param serverCtx Event context on the handler/server side.
1001
+ * @param event Invoke event definition created by `defineInvokeEventa`.
1002
+ * @param fn Stream handler that yields response chunks.
1003
+ */
1004
+ function defineStreamInvokeHandler(serverCtx, event, fn) {
1005
+ const invokeReceiveEvent = (invokeId) => defineEventa(`${event.receiveEvent.id}-${invokeId}`);
1006
+ const invokeReceiveEventError = (invokeId) => defineEventa(`${event.receiveEventError.id}-${invokeId}`);
1007
+ const invokeReceiveEventStreamEnd = (invokeId) => defineEventa(`${event.receiveEventStreamEnd.id}-${invokeId}`);
1008
+ const streamStates = /* @__PURE__ */ new Map();
1009
+ const abortControllers = /* @__PURE__ */ new Map();
1010
+ const abortReasons = /* @__PURE__ */ new Map();
1011
+ const scheduleAbort = (controller, reason) => {
1012
+ if (typeof queueMicrotask !== "undefined") {
1013
+ queueMicrotask(() => controller.abort(reason));
1014
+ return;
1015
+ }
1016
+ Promise.resolve().then(() => controller.abort(reason));
1017
+ };
1018
+ const handleInvoke = async (invokeId, payload, options) => {
1019
+ const receiveEvent = invokeReceiveEvent(invokeId);
1020
+ const receiveEventError = invokeReceiveEventError(invokeId);
1021
+ const receiveEventStreamEnd = invokeReceiveEventStreamEnd(invokeId);
1022
+ const abortController = new AbortController();
1023
+ abortControllers.set(invokeId, abortController);
1024
+ if (abortReasons.has(invokeId)) scheduleAbort(abortController, abortReasons.get(invokeId));
1025
+ const handlerOptions = options ? {
1026
+ ...options,
1027
+ abortController
1028
+ } : { abortController };
1029
+ try {
1030
+ const generator = fn(payload, handlerOptions);
1031
+ for await (const res of generator) serverCtx.emit(receiveEvent, {
1032
+ invokeId,
1033
+ content: res
1034
+ }, options);
1035
+ serverCtx.emit(receiveEventStreamEnd, {
1036
+ invokeId,
1037
+ content: void 0
1038
+ }, options);
1039
+ } catch (error) {
1040
+ serverCtx.emit(receiveEventError, {
1041
+ invokeId,
1042
+ content: { error }
1043
+ }, options);
1044
+ } finally {
1045
+ abortControllers.delete(invokeId);
1046
+ abortReasons.delete(invokeId);
1047
+ }
1048
+ };
1049
+ serverCtx.on(event.sendEvent, async (payload, options) => {
1050
+ if (!payload.body) return;
1051
+ if (!payload.body.invokeId) return;
1052
+ const invokeId = payload.body.invokeId;
1053
+ if (payload.body.isReqStream) {
1054
+ let controller = streamStates.get(invokeId);
1055
+ if (!controller) {
1056
+ let localController;
1057
+ const reqStream = new ReadableStream({ start(c) {
1058
+ localController = c;
1059
+ } });
1060
+ controller = localController;
1061
+ streamStates.set(invokeId, controller);
1062
+ handleInvoke(invokeId, reqStream, options);
1063
+ }
1064
+ controller.enqueue(payload.body.content);
1065
+ return;
1066
+ }
1067
+ handleInvoke(invokeId, payload.body.content, options);
1068
+ });
1069
+ serverCtx.on(event.sendEventStreamEnd, (payload) => {
1070
+ if (!payload.body) return;
1071
+ if (!payload.body.invokeId) return;
1072
+ const controller = streamStates.get(payload.body.invokeId);
1073
+ if (!controller) return;
1074
+ controller.close();
1075
+ streamStates.delete(payload.body.invokeId);
1076
+ });
1077
+ serverCtx.on(event.sendEventAbort, (payload) => {
1078
+ if (!payload.body) return;
1079
+ if (!payload.body.invokeId) return;
1080
+ const invokeId = payload.body.invokeId;
1081
+ const reason = payload.body.content;
1082
+ const abortController = abortControllers.get(invokeId);
1083
+ if (!abortController) {
1084
+ abortReasons.set(invokeId, reason);
1085
+ let controller$1 = streamStates.get(invokeId);
1086
+ if (!controller$1) {
1087
+ let localController;
1088
+ const reqStream = new ReadableStream({ start(c) {
1089
+ localController = c;
1090
+ } });
1091
+ controller$1 = localController;
1092
+ streamStates.set(invokeId, controller$1);
1093
+ handleInvoke(invokeId, reqStream);
1094
+ }
1095
+ controller$1.error(createAbortError(reason));
1096
+ streamStates.delete(invokeId);
1097
+ return;
1098
+ }
1099
+ scheduleAbort(abortController, reason);
1100
+ const controller = streamStates.get(invokeId);
1101
+ if (controller) {
1102
+ controller.error(createAbortError(reason));
1103
+ streamStates.delete(invokeId);
1104
+ }
1105
+ });
1106
+ }
1107
+ /**
1108
+ * Convert a callback-style handler into a stream handler.
1109
+ *
1110
+ * Use `emit` to push response chunks, and return when done.
1111
+ * Works for unary or streaming requests.
1112
+ *
1113
+ * @example
1114
+ * ```ts
1115
+ * defineStreamInvokeHandler(ctx, events, toStreamHandler(async ({ payload, emit }) => {
1116
+ * if (isReadableStream<Params>(payload) || isAsyncIterable<Params>(payload)) {
1117
+ * for await (const item of payload) {
1118
+ * emit({ type: 'progress', value: item })
1119
+ * }
1120
+ *
1121
+ * emit({ type: 'result', ok: true })
1122
+ * return
1123
+ * }
1124
+ *
1125
+ * emit({ type: 'result', ok: true })
1126
+ * }))
1127
+ * ```
1128
+ *
1129
+ * @param handler Callback handler with `emit` for streaming responses.
1130
+ */
1131
+ function toStreamHandler(handler) {
1132
+ return (payload, options) => {
1133
+ const values = [];
1134
+ let resolve;
1135
+ let handlerError = null;
1136
+ values.push(new Promise((r) => {
1137
+ resolve = r;
1138
+ }));
1139
+ const emit = (data) => {
1140
+ resolve([data, false]);
1141
+ values.push(new Promise((r) => {
1142
+ resolve = r;
1143
+ }));
1144
+ };
1145
+ handler({
1146
+ payload,
1147
+ options,
1148
+ emit
1149
+ }).then(() => {
1150
+ resolve([void 0, true]);
1151
+ }).catch((err) => {
1152
+ handlerError = err;
1153
+ resolve([void 0, true]);
1154
+ });
1155
+ return async function* () {
1156
+ let val;
1157
+ for (let i = 0, done = false; !done; i++) {
1158
+ [val, done] = await values[i];
1159
+ delete values[i];
1160
+ if (handlerError) throw handlerError;
1161
+ if (!done) yield val;
1162
+ }
1163
+ }();
1164
+ };
1165
+ }
1166
+
1167
+ //#endregion
1168
+ export { isInvokeEventa as C, registerInvokeAbortEventListeners as E, defineInvokeEventa as S, isSendEvent as T, isAbortError as _, withRemoteMethods as a, randomBetween as b, defineInvokeHandler as c, isExtendableInvokeResponseLike as d, undefineInvokeHandler as f, createUntilTriggeredOnce as g, createUntilTriggered as h, createRemoteMethodTagPrefix as i, defineInvokeHandlers as l, createUntil as m, defineStreamInvokeHandler as n, withTransfer as o, createAbortError as p, toStreamHandler as r, defineInvoke as s, defineStreamInvoke as t, defineInvokes as u, isAsyncIterable as v, isReceiveEvent as w, InvokeEventType as x, isReadableStream as y };
1169
+ //# sourceMappingURL=src-DZ7si0kE.mjs.map