@requence/service 0.7.1 → 0.8.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 (87) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +15 -0
  3. package/build/{chunk-6w7td62p.js → chunk-8r349zge.js} +46 -3
  4. package/build/chunk-8r349zge.js.map +11 -0
  5. package/build/cli.js +17 -7
  6. package/build/cli.js.map +3 -3
  7. package/build/index.js +1261 -446
  8. package/build/index.js.map +28 -14
  9. package/build/types/helpers/src/index.d.ts +8 -2
  10. package/build/types/helpers/src/index.d.ts.map +1 -1
  11. package/build/types/helpers/src/jsonschema/validate.d.ts +1 -5
  12. package/build/types/helpers/src/jsonschema/validate.d.ts.map +1 -1
  13. package/build/types/helpers/src/jsonschema/zod.d.ts +11 -1
  14. package/build/types/helpers/src/jsonschema/zod.d.ts.map +1 -1
  15. package/build/types/helpers/src/protocol/NodeTree.d.ts +450 -144
  16. package/build/types/helpers/src/protocol/NodeTree.d.ts.map +1 -1
  17. package/build/types/helpers/src/protocol/command.d.ts +364 -142
  18. package/build/types/helpers/src/protocol/command.d.ts.map +1 -1
  19. package/build/types/helpers/src/protocol/configurationScript.d.ts +10 -0
  20. package/build/types/helpers/src/protocol/configurationScript.d.ts.map +1 -0
  21. package/build/types/helpers/src/protocol/helpers.d.ts.map +1 -1
  22. package/build/types/helpers/src/protocol/index.d.ts +4 -0
  23. package/build/types/helpers/src/protocol/index.d.ts.map +1 -1
  24. package/build/types/helpers/src/protocol/logicLanguages.d.ts +19 -0
  25. package/build/types/helpers/src/protocol/logicLanguages.d.ts.map +1 -0
  26. package/build/types/helpers/src/protocol/loopDetection.d.ts +23 -0
  27. package/build/types/helpers/src/protocol/loopDetection.d.ts.map +1 -0
  28. package/build/types/helpers/src/protocol/nodeType.d.ts +73 -27
  29. package/build/types/helpers/src/protocol/nodeType.d.ts.map +1 -1
  30. package/build/types/helpers/src/protocol/taskOptions.d.ts +4 -1
  31. package/build/types/helpers/src/protocol/taskOptions.d.ts.map +1 -1
  32. package/build/types/helpers/src/protocol/templateNodeTypes.d.ts +36 -20
  33. package/build/types/helpers/src/protocol/templateNodeTypes.d.ts.map +1 -1
  34. package/build/types/helpers/src/protocol/treeNodes.d.ts +476 -164
  35. package/build/types/helpers/src/protocol/treeNodes.d.ts.map +1 -1
  36. package/build/types/helpers/src/protocol/update.d.ts +22 -22
  37. package/build/types/helpers/src/protocol/validateTreeStructure.d.ts +22 -0
  38. package/build/types/helpers/src/protocol/validateTreeStructure.d.ts.map +1 -0
  39. package/build/types/helpers/src/utils/amqpHeartbeat.d.ts +3 -0
  40. package/build/types/helpers/src/utils/amqpHeartbeat.d.ts.map +1 -0
  41. package/build/types/helpers/src/utils/amqpPublishRetry.d.ts +5 -0
  42. package/build/types/helpers/src/utils/amqpPublishRetry.d.ts.map +1 -0
  43. package/build/types/helpers/src/utils/claimCheckObject.d.ts +40 -0
  44. package/build/types/helpers/src/utils/claimCheckObject.d.ts.map +1 -0
  45. package/build/types/helpers/src/utils/debounce.d.ts.map +1 -1
  46. package/build/types/helpers/src/{files → utils}/fileObject.d.ts.map +1 -1
  47. package/build/types/helpers/src/{files → utils}/isValidMimeType.d.ts.map +1 -1
  48. package/build/types/helpers/src/utils/mapData.d.ts +1 -1
  49. package/build/types/helpers/src/utils/mapData.d.ts.map +1 -1
  50. package/build/types/helpers/src/{files → utils}/streamObject.d.ts.map +1 -1
  51. package/build/types/helpers/src/utils/variableRef.d.ts +19 -0
  52. package/build/types/helpers/src/utils/variableRef.d.ts.map +1 -0
  53. package/build/types/helpers/src/utils/variableScriptPatterns.d.ts +125 -0
  54. package/build/types/helpers/src/utils/variableScriptPatterns.d.ts.map +1 -0
  55. package/build/types/service/src/boundary.d.ts +75 -0
  56. package/build/types/service/src/boundary.d.ts.map +1 -0
  57. package/build/types/service/src/createAmqpConnection.d.ts +21 -4
  58. package/build/types/service/src/createAmqpConnection.d.ts.map +1 -1
  59. package/build/types/service/src/errors.d.ts +31 -0
  60. package/build/types/service/src/errors.d.ts.map +1 -1
  61. package/build/types/service/src/helpers.d.ts +59 -56
  62. package/build/types/service/src/helpers.d.ts.map +1 -1
  63. package/build/types/service/src/index.d.ts +7 -1
  64. package/build/types/service/src/index.d.ts.map +1 -1
  65. package/build/types/service/src/transformer.d.ts +16 -0
  66. package/build/types/service/src/transformer.d.ts.map +1 -0
  67. package/package.json +6 -3
  68. package/build/chunk-6w7td62p.js.map +0 -10
  69. package/build/types/helpers/src/files/RequenceFile.d.ts +0 -40
  70. package/build/types/helpers/src/files/RequenceFile.d.ts.map +0 -1
  71. package/build/types/helpers/src/files/RequenceStream.d.ts +0 -32
  72. package/build/types/helpers/src/files/RequenceStream.d.ts.map +0 -1
  73. package/build/types/helpers/src/files/index.d.ts +0 -7
  74. package/build/types/helpers/src/files/index.d.ts.map +0 -1
  75. package/build/types/helpers/src/files/mapOutput.d.ts +0 -10
  76. package/build/types/helpers/src/files/mapOutput.d.ts.map +0 -1
  77. package/build/types/helpers/src/files/types.d.ts +0 -4
  78. package/build/types/helpers/src/files/types.d.ts.map +0 -1
  79. package/build/types/helpers/src/utils/createObjectProxy.d.ts +0 -2
  80. package/build/types/helpers/src/utils/createObjectProxy.d.ts.map +0 -1
  81. package/build/types/helpers/src/utils/resolveRequenceTypes.d.ts +0 -8
  82. package/build/types/helpers/src/utils/resolveRequenceTypes.d.ts.map +0 -1
  83. package/build/types/service/src/mapInput.d.ts +0 -2
  84. package/build/types/service/src/mapInput.d.ts.map +0 -1
  85. /package/build/types/helpers/src/{files → utils}/fileObject.d.ts +0 -0
  86. /package/build/types/helpers/src/{files → utils}/isValidMimeType.d.ts +0 -0
  87. /package/build/types/helpers/src/{files → utils}/streamObject.d.ts +0 -0
package/build/index.js CHANGED
@@ -1,7 +1,13 @@
1
1
  import {
2
+ PayloadTooLargeError,
3
+ RequenceConnectionError,
4
+ RequenceUnreachableError,
5
+ assertReachable,
2
6
  deobfuscate,
3
- obfuscate
4
- } from "./chunk-6w7td62p.js";
7
+ isUnreachableStatus,
8
+ obfuscate,
9
+ reachableFetch
10
+ } from "./chunk-8r349zge.js";
5
11
 
6
12
  // src/index.ts
7
13
  import fs from "node:fs";
@@ -49,7 +55,8 @@ function mapData(data, visitors) {
49
55
  if (data2 === null) {
50
56
  return notUndefined(visitors.Null?.(data2, path), data2);
51
57
  }
52
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(data2)) {
58
+ const runtimeBuffer = globalThis.Buffer;
59
+ if (runtimeBuffer?.isBuffer(data2)) {
53
60
  return notUndefined(visitors.Buffer?.(data2, path), data2);
54
61
  }
55
62
  if (typeof data2 === "string") {
@@ -65,7 +72,7 @@ function mapData(data, visitors) {
65
72
  return notUndefined(visitors.Function?.(data2, path), data2);
66
73
  }
67
74
  if (isRecord(data2)) {
68
- return resolve(visitors.Object?.(structuredClone(data2), path), (resolvedData) => {
75
+ return resolve(visitors.Object?.({ ...data2 }, path), (resolvedData) => {
69
76
  const nextData = resolvedData ?? data2;
70
77
  if (!isRecord(nextData)) {
71
78
  return nextData;
@@ -98,14 +105,66 @@ mapData.abort = () => {
98
105
  throw new AbortMapData;
99
106
  };
100
107
 
101
- // ../helpers/src/utils/requenceCallback.ts
108
+ // ../helpers/src/utils/fileObject.ts
102
109
  import { z as z2 } from "zod/v4";
103
- var callbackObjectSchema = z2.object({
104
- sourceId: z2.string(),
105
- outputName: z2.string().nullable(),
106
- propertyPath: z2.array(z2.union([z2.string(), z2.int()])),
107
- callbackId: z2.uuid(),
108
- __REQUENCE_type: z2.literal("RequenceCallback")
110
+ var fileObjectSchema = z2.object({
111
+ size: z2.int().positive(),
112
+ mime: z2.string(),
113
+ url: z2.url(),
114
+ __REQUENCE_type: z2.literal("RequenceFile")
115
+ });
116
+ function toFileObject(fileInfo) {
117
+ return {
118
+ ...fileInfo,
119
+ __REQUENCE_type: "RequenceFile"
120
+ };
121
+ }
122
+ function isFileObject(data) {
123
+ return fileObjectSchema.safeParse(data).success;
124
+ }
125
+
126
+ // ../helpers/src/utils/streamObject.ts
127
+ import { z as z3 } from "zod/v4";
128
+ var streamObjectSchema = z3.object({
129
+ mime: z3.string(),
130
+ url: z3.string().url(),
131
+ __REQUENCE_type: z3.literal("RequenceStream")
132
+ });
133
+ function isStreamObject(data) {
134
+ return streamObjectSchema.safeParse(data).success;
135
+ }
136
+ function toStreamObject(streamInfo) {
137
+ return {
138
+ ...streamInfo,
139
+ __REQUENCE_type: "RequenceStream"
140
+ };
141
+ }
142
+
143
+ // ../helpers/src/utils/claimCheckObject.ts
144
+ import { z as z4 } from "zod/v4";
145
+ var claimCheckObjectSchema = z4.object({
146
+ url: z4.url(),
147
+ size: z4.int().positive(),
148
+ __REQUENCE_type: z4.literal("ClaimCheck")
149
+ });
150
+ function toClaimCheckObject(info) {
151
+ return {
152
+ ...info,
153
+ __REQUENCE_type: "ClaimCheck"
154
+ };
155
+ }
156
+ function isClaimCheckObject(data) {
157
+ return claimCheckObjectSchema.safeParse(data).success;
158
+ }
159
+
160
+ // ../helpers/src/utils/requenceCallback.ts
161
+ import { z as z5 } from "zod/v4";
162
+ var callbackObjectSchema = z5.object({
163
+ sourceId: z5.string(),
164
+ outputName: z5.string().nullable(),
165
+ propertyPath: z5.array(z5.union([z5.string(), z5.int()])),
166
+ callbackId: z5.uuid(),
167
+ __REQUENCE_type: z5.literal("RequenceCallback")
109
168
  });
110
169
  function isCallbackObject(data) {
111
170
  return callbackObjectSchema.safeParse(data).success;
@@ -123,36 +182,206 @@ function createCallback(callback) {
123
182
  });
124
183
  }
125
184
 
126
- // ../helpers/src/files/fileObject.ts
127
- import { z as z3 } from "zod/v4";
128
- var fileObjectSchema = z3.object({
129
- size: z3.int().positive(),
130
- mime: z3.string(),
131
- url: z3.url(),
132
- __REQUENCE_type: z3.literal("RequenceFile")
133
- });
134
- function toFileObject(fileInfo) {
135
- return {
136
- ...fileInfo,
137
- __REQUENCE_type: "RequenceFile"
185
+ // ../helpers/src/utils/amqpHeartbeat.ts
186
+ var DEFAULT_AMQP_HEARTBEAT_SECONDS = 30;
187
+
188
+ // src/createAmqpConnection.ts
189
+ import { connect } from "amqp-connection-manager";
190
+ import { z as z6 } from "zod/v4";
191
+
192
+ // ../files/src/errors.ts
193
+ class RequenceStreamTruncatedError extends Error {
194
+ constructor(message = "stream truncated") {
195
+ super(message);
196
+ this.name = "RequenceStreamTruncatedError";
197
+ }
198
+ }
199
+
200
+ // ../files/src/streamFraming.ts
201
+ var STREAM_PROTOCOL_HEADER = "x-requence-stream-protocol";
202
+ var STREAM_PROTOCOL_FRAMED = "framed";
203
+ var DATA = 0;
204
+ var END = 1;
205
+ var TRUNCATED = 2;
206
+ var HEADER_BYTES = 5;
207
+ var END_FRAME = new Uint8Array([END, 0, 0, 0, 0]);
208
+ function createFrameDecoder() {
209
+ let buffer = new Uint8Array(0);
210
+ let terminal = false;
211
+ return new TransformStream({
212
+ transform(chunk, controller) {
213
+ if (terminal) {
214
+ if (chunk.byteLength > 0) {
215
+ throw new Error("stream protocol error: bytes after terminal frame");
216
+ }
217
+ return;
218
+ }
219
+ if (buffer.byteLength === 0) {
220
+ buffer = chunk;
221
+ } else {
222
+ const merged = new Uint8Array(buffer.byteLength + chunk.byteLength);
223
+ merged.set(buffer, 0);
224
+ merged.set(chunk, buffer.byteLength);
225
+ buffer = merged;
226
+ }
227
+ while (buffer.byteLength >= HEADER_BYTES) {
228
+ const type = buffer[0];
229
+ const length = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getUint32(1, false);
230
+ if (buffer.byteLength < HEADER_BYTES + length) {
231
+ break;
232
+ }
233
+ const payload = buffer.slice(HEADER_BYTES, HEADER_BYTES + length);
234
+ buffer = buffer.subarray(HEADER_BYTES + length);
235
+ switch (type) {
236
+ case DATA: {
237
+ if (payload.byteLength > 0) {
238
+ controller.enqueue(payload);
239
+ }
240
+ break;
241
+ }
242
+ case END: {
243
+ terminal = true;
244
+ if (buffer.byteLength > 0) {
245
+ throw new Error("stream protocol error: bytes after terminal frame");
246
+ }
247
+ controller.terminate();
248
+ return;
249
+ }
250
+ case TRUNCATED: {
251
+ terminal = true;
252
+ controller.error(new RequenceStreamTruncatedError(new TextDecoder().decode(payload) || undefined));
253
+ return;
254
+ }
255
+ default: {
256
+ throw new Error(`stream protocol error: unknown frame type ${type}`);
257
+ }
258
+ }
259
+ }
260
+ },
261
+ flush(controller) {
262
+ if (!terminal) {
263
+ controller.error(new RequenceStreamTruncatedError("connection closed before terminal frame"));
264
+ }
265
+ }
266
+ });
267
+ }
268
+
269
+ // ../files/src/remoteBody.ts
270
+ function remoteBody(url, options = {}) {
271
+ const externalSignal = options.signal;
272
+ const timeoutMs = options.stallTimeoutMs && options.stallTimeoutMs > 0 ? options.stallTimeoutMs : 0;
273
+ const controller = new AbortController;
274
+ let reader = null;
275
+ let timer;
276
+ let onExternalAbort;
277
+ const clearTimer = () => {
278
+ if (timer !== undefined) {
279
+ clearTimeout(timer);
280
+ timer = undefined;
281
+ }
282
+ };
283
+ const cleanup = () => {
284
+ clearTimer();
285
+ if (externalSignal && onExternalAbort) {
286
+ externalSignal.removeEventListener("abort", onExternalAbort);
287
+ }
288
+ };
289
+ if (externalSignal) {
290
+ if (externalSignal.aborted) {
291
+ controller.abort(externalSignal.reason);
292
+ } else {
293
+ onExternalAbort = () => controller.abort(externalSignal.reason);
294
+ externalSignal.addEventListener("abort", onExternalAbort, {
295
+ once: true
296
+ });
297
+ }
298
+ }
299
+ const armTimer = () => {
300
+ if (timeoutMs <= 0) {
301
+ return;
302
+ }
303
+ clearTimer();
304
+ timer = setTimeout(() => {
305
+ controller.abort(new Error(`remote read stalled: no data for ${timeoutMs}ms`));
306
+ }, timeoutMs);
138
307
  };
308
+ return new ReadableStream({
309
+ async start(streamController) {
310
+ let response;
311
+ try {
312
+ response = await fetch(url, {
313
+ signal: controller.signal,
314
+ headers: options.framed ? { [STREAM_PROTOCOL_HEADER]: STREAM_PROTOCOL_FRAMED } : undefined
315
+ });
316
+ } catch (error) {
317
+ cleanup();
318
+ streamController.error(error);
319
+ return;
320
+ }
321
+ if (!response.ok) {
322
+ await response.body?.cancel();
323
+ cleanup();
324
+ streamController.error(new Error(`remote read failed: ${response.status} ${response.statusText}`));
325
+ return;
326
+ }
327
+ if (!response.body) {
328
+ cleanup();
329
+ streamController.error(new Error("remote read response has no body"));
330
+ return;
331
+ }
332
+ const framed = options.framed && response.headers.get(STREAM_PROTOCOL_HEADER) === STREAM_PROTOCOL_FRAMED;
333
+ reader = framed ? response.body.pipeThrough(createFrameDecoder()).getReader() : response.body.getReader();
334
+ },
335
+ async pull(streamController) {
336
+ if (!reader) {
337
+ return;
338
+ }
339
+ armTimer();
340
+ try {
341
+ const { done, value } = await reader.read();
342
+ clearTimer();
343
+ if (done) {
344
+ cleanup();
345
+ streamController.close();
346
+ return;
347
+ }
348
+ streamController.enqueue(value);
349
+ } catch (error) {
350
+ clearTimer();
351
+ cleanup();
352
+ streamController.error(error);
353
+ }
354
+ },
355
+ async cancel(reason) {
356
+ cleanup();
357
+ controller.abort(reason);
358
+ await reader?.cancel(reason);
359
+ }
360
+ });
139
361
  }
140
- function isFileObject(data) {
141
- return fileObjectSchema.safeParse(data).success;
362
+
363
+ // ../files/src/RequenceFile.ts
364
+ function stallTimeoutMs() {
365
+ const raw = typeof process !== "undefined" ? Number(process.env?.REQUENCE_FILE_STALL_TIMEOUT_MS) : Number.NaN;
366
+ return Number.isFinite(raw) && raw > 0 ? raw : 0;
142
367
  }
143
368
 
144
- // ../helpers/src/files/RequenceFile.ts
145
369
  class RequenceFile {
146
370
  #data;
147
371
  #file = null;
372
+ #signal;
148
373
  constructor(blobParts, options) {
149
374
  this.#data = new Blob(blobParts, options);
150
375
  }
151
- static fromFileObject(file) {
376
+ static fromFileObject(file, signal) {
152
377
  const instance = new this([], { type: "x/x" });
153
378
  instance.#file = file;
379
+ instance.#signal = signal;
154
380
  return instance;
155
381
  }
382
+ static canHandle(value) {
383
+ return value instanceof RequenceFile || value instanceof Blob;
384
+ }
156
385
  get fileObject() {
157
386
  return this.#file;
158
387
  }
@@ -168,39 +397,74 @@ class RequenceFile {
168
397
  get subMimeType() {
169
398
  return this.mimeType.split("/")[1];
170
399
  }
400
+ stream() {
401
+ if (!this.#file) {
402
+ return this.#data.stream();
403
+ }
404
+ return remoteBody(this.#file.url, {
405
+ signal: this.#signal,
406
+ stallTimeoutMs: stallTimeoutMs()
407
+ });
408
+ }
409
+ async#bytes() {
410
+ const reader = this.stream().getReader();
411
+ const chunks = [];
412
+ let total = 0;
413
+ for (;; ) {
414
+ const { done, value } = await reader.read();
415
+ if (done) {
416
+ break;
417
+ }
418
+ chunks.push(value);
419
+ total += value.byteLength;
420
+ }
421
+ const out = new Uint8Array(total);
422
+ let offset = 0;
423
+ for (const chunk of chunks) {
424
+ out.set(chunk, offset);
425
+ offset += chunk.byteLength;
426
+ }
427
+ return out;
428
+ }
171
429
  async text() {
172
430
  if (this.#file) {
173
- return fetch(this.#file.url).then((response) => response.text());
431
+ return new TextDecoder().decode(await this.#bytes());
174
432
  }
175
433
  return this.#data.text();
176
434
  }
177
435
  async json() {
178
436
  if (this.#file) {
179
- return fetch(this.#file.url).then((response) => response.json());
437
+ const text = await this.text();
438
+ try {
439
+ return JSON.parse(text);
440
+ } catch (error) {
441
+ throw new Error(`RequenceFile JSON parse failed for ${this.#file.url}`, { cause: error });
442
+ }
180
443
  }
181
444
  return JSON.parse(await this.text());
182
445
  }
183
446
  async blob() {
184
447
  if (this.#file) {
185
- return fetch(this.#file.url).then((response) => response.blob());
448
+ return new Blob([await this.#bytes()], { type: this.#file.mime });
186
449
  }
187
450
  return this.#data;
188
451
  }
189
452
  async arrayBuffer() {
190
453
  if (this.#file) {
191
- return fetch(this.#file.url).then((response) => response.arrayBuffer());
454
+ return (await this.#bytes()).buffer;
192
455
  }
193
456
  return this.#data.arrayBuffer();
194
457
  }
195
458
  toString() {
196
459
  return `RequenceFile<${this.mimeType}>`;
197
460
  }
198
- toJSON() {
199
- return `RequenceFile<${this.mimeType}>`;
200
- }
461
+ }
462
+ // ../files/src/RequenceStream.ts
463
+ function stallTimeoutMs2() {
464
+ const raw = typeof process !== "undefined" ? Number(process.env?.REQUENCE_STREAM_STALL_TIMEOUT_MS) : Number.NaN;
465
+ return Number.isFinite(raw) && raw > 0 ? raw : 0;
201
466
  }
202
467
 
203
- // ../helpers/src/files/RequenceStream.ts
204
468
  class RequenceStream {
205
469
  #data;
206
470
  #stream = null;
@@ -209,13 +473,17 @@ class RequenceStream {
209
473
  this.#data = stream;
210
474
  this.#options = options;
211
475
  }
212
- static fromStreamObject(stream) {
476
+ static fromStreamObject(stream, signal) {
213
477
  const instance = new this(null, {
214
- type: "x/x"
478
+ type: "x/x",
479
+ signal
215
480
  });
216
481
  instance.#stream = stream;
217
482
  return instance;
218
483
  }
484
+ static canHandle(value) {
485
+ return value instanceof RequenceStream || value instanceof Response;
486
+ }
219
487
  get streamObject() {
220
488
  return this.#stream;
221
489
  }
@@ -229,12 +497,14 @@ class RequenceStream {
229
497
  return this.mimeType.split("/")[1];
230
498
  }
231
499
  stream() {
232
- if (this.#stream) {
233
- const { readable, writable } = new TransformStream;
234
- fetch(this.#stream.url).then((response) => response.body?.pipeTo(writable));
235
- return readable;
500
+ if (!this.#stream) {
501
+ return this.#data;
236
502
  }
237
- return this.#data;
503
+ return remoteBody(this.#stream.url, {
504
+ signal: this.#options.signal,
505
+ stallTimeoutMs: stallTimeoutMs2(),
506
+ framed: true
507
+ });
238
508
  }
239
509
  asyncIterable() {
240
510
  const reader = this.stream().getReader();
@@ -248,6 +518,11 @@ class RequenceStream {
248
518
  reader.cancel();
249
519
  reader.releaseLock();
250
520
  return { done: true, value: null };
521
+ },
522
+ async throw() {
523
+ reader.cancel();
524
+ reader.releaseLock();
525
+ return { done: true, value: null };
251
526
  }
252
527
  };
253
528
  }
@@ -256,163 +531,556 @@ class RequenceStream {
256
531
  toString() {
257
532
  return `RequenceStream<${this.mimeType}>`;
258
533
  }
259
- toJSON() {
260
- return `RequenceStream<${this.mimeType}>`;
261
- }
262
- }
263
-
264
- // ../helpers/src/files/streamObject.ts
265
- import { z as z4 } from "zod/v4";
266
- var streamObjectSchema = z4.object({
267
- mime: z4.string(),
268
- url: z4.string().url(),
269
- __REQUENCE_type: z4.literal("RequenceStream")
270
- });
271
- function isStreamObject(data) {
272
- return streamObjectSchema.safeParse(data).success;
273
534
  }
274
- function toStreamObject(streamInfo) {
275
- return {
276
- ...streamInfo,
277
- __REQUENCE_type: "RequenceStream"
278
- };
535
+ // ../files/src/handlers/transport.ts
536
+ async function assertOk(res, url, phase) {
537
+ if (res.ok) {
538
+ return;
539
+ }
540
+ const detail = await res.text().catch(() => "");
541
+ throw new Error(`${phase} failed: ${res.status} ${res.statusText} (${url})${detail ? ` — ${detail}` : ""}`);
279
542
  }
280
543
 
281
- // ../helpers/src/files/mapOutput.ts
282
- async function upload(uploadUrl, body, signal, contentType) {
283
- const uploadResponse = await fetch(uploadUrl, {
544
+ // ../files/src/handlers/fileHandler.ts
545
+ async function upload(ctx, uploadUrl, body, contentType, maxFileSize) {
546
+ const uploadResponse = await ctx.fetch(uploadUrl, {
284
547
  method: "POST",
285
- signal,
286
- headers: contentType ? {
287
- "Content-Type": contentType
288
- } : {},
548
+ signal: ctx.signal,
549
+ headers: {
550
+ ...contentType ? { "Content-Type": contentType } : {},
551
+ ...maxFileSize !== undefined ? { "file-size": String(maxFileSize) } : {}
552
+ },
289
553
  body
290
554
  });
555
+ await assertOk(uploadResponse, uploadUrl, "upload");
291
556
  const data = await uploadResponse.json();
292
- if (!data || typeof data !== "object") {
293
- throw new Error("invalid upload response");
557
+ if (!data || typeof data !== "object" || typeof data.url !== "string" || !data.url || typeof data.mime !== "string" || typeof data.size !== "number") {
558
+ throw new Error(`malformed upload response (${uploadUrl})`);
294
559
  }
295
560
  return toFileObject(data);
296
561
  }
297
- async function stream(streamUrl, stream2, signal, contentType) {
298
- const [testStream, dataStream] = stream2.tee();
299
- const reader = testStream.getReader();
300
- const dataPromise = reader.read().then(({ done: done2 }) => {
301
- if (done2) {
302
- throw new Error("No streaming date received");
562
+ function createRequenceFileHandler() {
563
+ return {
564
+ tag: "RequenceFile",
565
+ canHandle: (value) => RequenceFile.canHandle(value),
566
+ async serialize(value, ctx) {
567
+ if (value instanceof RequenceFile && value.fileObject) {
568
+ return value.fileObject;
569
+ }
570
+ if (!ctx.uploadUrl) {
571
+ ctx.onOffloadSkip?.();
572
+ return null;
573
+ }
574
+ try {
575
+ if (value instanceof RequenceFile) {
576
+ return await upload(ctx, ctx.uploadUrl, await value.blob(), value.mimeType, ctx.maxFileSize);
577
+ }
578
+ return await upload(ctx, ctx.uploadUrl, value, value.type, ctx.maxFileSize);
579
+ } catch (error) {
580
+ if (!(error instanceof Error)) {
581
+ throw error;
582
+ }
583
+ if (ctx.onOffloadFail) {
584
+ ctx.onOffloadFail(error);
585
+ return null;
586
+ }
587
+ throw error;
588
+ }
589
+ },
590
+ isReference: (value) => isFileObject(value),
591
+ deserialize(ref, ctx) {
592
+ return RequenceFile.fromFileObject(ref, ctx.signal);
303
593
  }
304
- reader.cancel();
305
- });
306
- const streamResponse = await fetch(streamUrl, {
594
+ };
595
+ }
596
+ // ../files/src/withRequenceStreams.ts
597
+ import { AsyncLocalStorage } from "node:async_hooks";
598
+ var pendingUploads = new AsyncLocalStorage;
599
+ async function withRequenceStreams(fn) {
600
+ const uploads = [];
601
+ const value = await pendingUploads.run(uploads, fn);
602
+ return { value, done: Promise.all(uploads).then(() => {
603
+ return;
604
+ }) };
605
+ }
606
+ function registerPendingUpload(work) {
607
+ const store = pendingUploads.getStore();
608
+ if (!store) {
609
+ return false;
610
+ }
611
+ store.push(work);
612
+ return true;
613
+ }
614
+
615
+ // ../files/src/handlers/streamHandler.ts
616
+ async function registerAndUpload(ctx, streamUrl, stream, contentType, maxFileSize) {
617
+ const [testStream, dataStream] = stream.tee();
618
+ const reader = testStream.getReader();
619
+ const { done: isEmpty } = await reader.read();
620
+ reader.cancel();
621
+ const streamResponse = await ctx.fetch(streamUrl, {
307
622
  method: "POST",
308
- signal,
309
- headers: contentType ? { "Content-Type": contentType } : {}
623
+ signal: ctx.signal,
624
+ headers: {
625
+ ...contentType ? { "Content-Type": contentType } : {},
626
+ ...maxFileSize !== undefined ? { "file-size": String(maxFileSize) } : {}
627
+ }
310
628
  });
629
+ await assertOk(streamResponse, streamUrl, "stream registration");
311
630
  const data = await streamResponse.json();
312
- if (!data || typeof data !== "object") {
313
- throw new Error("invalid stream response");
631
+ if (!isStreamObject(toStreamObject(data))) {
632
+ throw new Error(`malformed stream registration response (${streamUrl})`);
314
633
  }
315
634
  const { mime, url } = data;
316
- await dataPromise;
317
- const done = fetch(url, {
318
- method: "POST",
319
- signal,
320
- duplex: "half",
321
- body: dataStream
322
- });
323
- return [toStreamObject({ mime, url }), done];
635
+ if (isEmpty) {
636
+ const emptyResponse = await ctx.fetch(url, {
637
+ method: "POST",
638
+ signal: ctx.signal,
639
+ headers: contentType ? { "Content-Type": contentType } : {},
640
+ body: new Uint8Array(0)
641
+ });
642
+ await assertOk(emptyResponse, url, "stream body upload");
643
+ await emptyResponse.body?.cancel();
644
+ return { ref: toStreamObject({ mime, url }) };
645
+ }
646
+ const bodyUpload = (async () => {
647
+ const bodyResponse = await ctx.fetch(url, {
648
+ method: "POST",
649
+ signal: ctx.signal,
650
+ duplex: "half",
651
+ body: dataStream
652
+ });
653
+ await assertOk(bodyResponse, url, "stream body upload");
654
+ await bodyResponse.body?.cancel();
655
+ })();
656
+ return { ref: toStreamObject({ mime, url }), bodyUpload };
324
657
  }
325
- async function mapOutput(params) {
326
- const streamPromises = [];
327
- const mapped = await mapData(params.value, {
328
- async Object(obj) {
329
- if (obj instanceof Blob || obj instanceof RequenceFile) {
330
- if (obj instanceof RequenceFile && obj.fileObject) {
331
- return obj.fileObject;
658
+ function createRequenceStreamHandler() {
659
+ return {
660
+ tag: "RequenceStream",
661
+ canHandle: (value) => RequenceStream.canHandle(value),
662
+ async serialize(value, ctx) {
663
+ if (value instanceof RequenceStream && value.streamObject) {
664
+ return value.streamObject;
665
+ }
666
+ if (!ctx.streamUrl) {
667
+ ctx.onOffloadSkip?.();
668
+ return null;
669
+ }
670
+ const body = value instanceof Response ? value.body ?? new ReadableStream({
671
+ start(controller) {
672
+ controller.close();
332
673
  }
333
- if (params.options.uploadUrl) {
334
- try {
335
- if (obj instanceof Blob) {
336
- return await upload(params.options.uploadUrl, obj, params.signal, obj.type);
337
- }
338
- if (obj instanceof RequenceFile) {
339
- return await upload(params.options.uploadUrl, await obj.blob(), params.signal, obj.mimeType);
340
- }
341
- } catch (error) {
342
- if (!(error instanceof Error)) {
343
- throw error;
344
- }
345
- params.onFail?.(error);
346
- return null;
347
- }
348
- } else {
349
- params.onSkip?.();
350
- return null;
674
+ }) : value.stream();
675
+ const contentType = value instanceof Response ? value.headers.get("Content-Type") : value.mimeType;
676
+ try {
677
+ const { ref, bodyUpload } = await registerAndUpload(ctx, ctx.streamUrl, body, contentType, ctx.maxFileSize);
678
+ if (bodyUpload && !registerPendingUpload(bodyUpload)) {
679
+ await bodyUpload;
351
680
  }
352
- }
353
- if (obj instanceof Response || obj instanceof RequenceStream) {
354
- if (obj instanceof RequenceStream && obj.streamObject) {
355
- return obj.streamObject;
681
+ return ref;
682
+ } catch (error) {
683
+ if (!(error instanceof Error)) {
684
+ throw error;
356
685
  }
357
- if (params.options.streamUrl) {
358
- try {
359
- if (obj instanceof Response && obj.body) {
360
- const [streamObject, streamPromise] = await stream(params.options.streamUrl, obj.body, params.signal, obj.headers.get("Content-Type"));
361
- streamPromises.push(streamPromise);
362
- return streamObject;
363
- }
364
- if (obj instanceof RequenceStream) {
365
- const [streamObject, streamPromise] = await stream(params.options.streamUrl, obj.stream(), params.signal, obj.mimeType);
366
- streamPromises.push(streamPromise);
367
- return streamObject;
368
- }
369
- } catch (error) {
370
- if (!(error instanceof Error)) {
371
- throw error;
372
- }
373
- params.onFail?.(error);
374
- return null;
375
- }
376
- } else {
377
- params.onSkip?.();
686
+ if (ctx.onOffloadFail) {
687
+ ctx.onOffloadFail(error);
378
688
  return null;
379
689
  }
690
+ throw error;
380
691
  }
692
+ },
693
+ isReference: (value) => isStreamObject(value),
694
+ deserialize(ref, ctx) {
695
+ return RequenceStream.fromStreamObject(ref, ctx.signal);
381
696
  }
697
+ };
698
+ }
699
+ // ../files/src/handlers/claimCheckHandler.ts
700
+ import { Buffer as Buffer2 } from "node:buffer";
701
+ var DEFAULT_MAX_PAYLOAD_SIZE = 4 * 1024 * 1024;
702
+ function isRecord2(value) {
703
+ return typeof value === "object" && value !== null && !Array.isArray(value);
704
+ }
705
+ async function offload(ctx, uploadUrl, json) {
706
+ const response = await ctx.fetch(uploadUrl, {
707
+ method: "POST",
708
+ signal: ctx.signal,
709
+ headers: { "Content-Type": "application/json" },
710
+ body: json
382
711
  });
383
- Promise.allSettled(streamPromises).then(() => params.onDone?.());
384
- return mapped;
712
+ await assertOk(response, uploadUrl, "claim-check offload");
713
+ const data = await response.json();
714
+ if (!data || typeof data !== "object" || typeof data.url !== "string" || !data.url || typeof data.size !== "number") {
715
+ throw new Error(`malformed claim-check offload response (${uploadUrl})`);
716
+ }
717
+ return toClaimCheckObject({ url: data.url, size: data.size });
385
718
  }
386
-
387
- // ../helpers/src/utils/resolveRequenceTypes.ts
388
- function resolveRequenceTypes(data, onCallback) {
719
+ function createMessageHandler() {
720
+ return {
721
+ async wrapOutbound(body, ctx) {
722
+ const maxBytes = ctx.maxPayloadSize ?? DEFAULT_MAX_PAYLOAD_SIZE;
723
+ if (maxBytes <= 0 || body === undefined) {
724
+ return body;
725
+ }
726
+ const json = JSON.stringify(body);
727
+ if (json === undefined || Buffer2.byteLength(json) <= maxBytes) {
728
+ return body;
729
+ }
730
+ const { uploadUrl } = ctx;
731
+ if (!uploadUrl) {
732
+ ctx.onOffloadSkip?.();
733
+ return body;
734
+ }
735
+ if (!isRecord2(body)) {
736
+ return offload(ctx, uploadUrl, json);
737
+ }
738
+ const entries = Object.entries(body).map(([key, value]) => {
739
+ const valueJson = JSON.stringify(value);
740
+ return {
741
+ key,
742
+ valueJson,
743
+ size: valueJson === undefined ? 0 : Buffer2.byteLength(valueJson)
744
+ };
745
+ }).sort((a, b) => b.size - a.size);
746
+ const wrapped = { ...body };
747
+ let total = Buffer2.byteLength(json);
748
+ for (const entry of entries) {
749
+ if (total <= maxBytes || entry.valueJson === undefined || entry.size <= 256) {
750
+ break;
751
+ }
752
+ const ref = await offload(ctx, uploadUrl, entry.valueJson);
753
+ wrapped[entry.key] = ref;
754
+ total += Buffer2.byteLength(JSON.stringify(ref)) - entry.size;
755
+ }
756
+ return wrapped;
757
+ }
758
+ };
759
+ }
760
+ function createValueHandler() {
761
+ return {
762
+ tag: "ClaimCheck",
763
+ canHandle: () => false,
764
+ serialize() {
765
+ throw new Error("ClaimCheck egress is the bundled MessageHandler (wrapOutbound); it never reaches the value walk");
766
+ },
767
+ isReference: (value) => isClaimCheckObject(value),
768
+ async deserialize(ref, ctx) {
769
+ const response = await ctx.fetch(ref.url, { signal: ctx.signal });
770
+ await assertOk(response, ref.url, "claim-check fetch");
771
+ const text = await response.text();
772
+ try {
773
+ return JSON.parse(text);
774
+ } catch {
775
+ throw new Error(`malformed claim-check payload (${ref.url})`);
776
+ }
777
+ }
778
+ };
779
+ }
780
+ function createClaimCheckHandler() {
781
+ return {
782
+ valueHandler: createValueHandler(),
783
+ messageHandler: createMessageHandler()
784
+ };
785
+ }
786
+ // ../files/src/sanitizeLogData.ts
787
+ function sanitizeLogData(data) {
389
788
  return mapData(data, {
789
+ Function: () => "[Function]",
790
+ Symbol: (sym) => String(sym),
390
791
  Object(obj) {
391
- if (isFileObject(obj)) {
392
- return RequenceFile.fromFileObject(obj);
792
+ if (RequenceFile.canHandle(obj) || RequenceStream.canHandle(obj)) {
793
+ return;
393
794
  }
394
- if (isStreamObject(obj)) {
395
- return RequenceStream.fromStreamObject(obj);
795
+ const proto = Object.getPrototypeOf(obj);
796
+ if (proto === null || proto === Object.prototype) {
797
+ return;
396
798
  }
397
- if (isCallbackObject(obj)) {
398
- return (arg) => {
399
- onCallback?.({ ...obj, arg });
400
- };
799
+ if (typeof obj.toJSON === "function") {
800
+ return;
401
801
  }
802
+ return String(obj);
402
803
  }
403
804
  });
404
805
  }
806
+ // ../callbacks/src/handler.ts
807
+ function createRequenceCallbackHandler() {
808
+ return {
809
+ tag: "RequenceCallback",
810
+ canHandle: (value) => typeof value === "function",
811
+ serialize(callback, ctx, path) {
812
+ if (!ctx.onCallback) {
813
+ throw new Error(`functions are not serializable on this boundary (no ctx.onCallback) at path "${path.join(".")}"`);
814
+ }
815
+ return {
816
+ ...ctx.onCallback(callback),
817
+ outputName: ctx.outputName ?? null,
818
+ propertyPath: [...path],
819
+ __REQUENCE_type: "RequenceCallback"
820
+ };
821
+ },
822
+ isReference: (value) => isCallbackObject(value),
823
+ deserialize(ref, ctx) {
824
+ return (arg) => {
825
+ ctx.onCallbackInvoke?.({ ...ref, arg });
826
+ };
827
+ }
828
+ };
829
+ }
830
+ // ../transformer/src/errors.ts
831
+ function formatPath(path) {
832
+ if (path.length === 0) {
833
+ return "<root>";
834
+ }
835
+ let out = "";
836
+ for (const segment of path) {
837
+ out += typeof segment === "number" ? `[${segment}]` : out ? `.${segment}` : segment;
838
+ }
839
+ return out;
840
+ }
405
841
 
406
- // src/createAmqpConnection.ts
407
- import { connect } from "amqp-connection-manager";
408
- import { z as z5 } from "zod/v4";
842
+ class TransformError extends Error {
843
+ path;
844
+ detail;
845
+ constructor(detail, path) {
846
+ super(`${detail} at ${formatPath(path)}`);
847
+ this.name = "TransformError";
848
+ this.path = path;
849
+ this.detail = detail;
850
+ }
851
+ }
852
+
853
+ // ../transformer/src/guards.ts
854
+ var REFERENCE_TAG_KEY = "__REQUENCE_type";
855
+ function isPlainObject(value) {
856
+ if (value === null || typeof value !== "object") {
857
+ return false;
858
+ }
859
+ const proto = Object.getPrototypeOf(value);
860
+ return proto === null || proto === Object.prototype;
861
+ }
862
+ function isComplexValue(value) {
863
+ if (value === null) {
864
+ return false;
865
+ }
866
+ const type = typeof value;
867
+ if (type === "object") {
868
+ return !Array.isArray(value) && !isPlainObject(value);
869
+ }
870
+ return type === "function" || type === "symbol" || type === "bigint";
871
+ }
872
+ function hasReferenceTag(value) {
873
+ return isPlainObject(value) && REFERENCE_TAG_KEY in value;
874
+ }
409
875
 
410
- // src/errors.ts
411
- class RequenceConnectionError extends Error {
876
+ // ../transformer/src/walk.ts
877
+ var recurse = { kind: "recurse" };
878
+ var replaceWith = (value) => ({
879
+ kind: "replace",
880
+ value
881
+ });
882
+ var MAX_REPLACE_DEPTH = 100;
883
+ async function walk(root, visit) {
884
+ const go = async (value, path, replaceDepth) => {
885
+ let node = value;
886
+ if (Array.isArray(node)) {
887
+ node = await Promise.all(node.map((item, index) => go(item, [...path, index], 0)));
888
+ } else if (isPlainObject(node)) {
889
+ const entries = await Promise.all(Object.entries(node).map(async ([key, item]) => [key, await go(item, [...path, key], 0)]));
890
+ node = Object.fromEntries(entries);
891
+ }
892
+ const verdict = await visit(node, path);
893
+ if (verdict.kind === "replace") {
894
+ if (replaceDepth >= MAX_REPLACE_DEPTH) {
895
+ throw new TransformError("transform did not reach a fixpoint (a handler keeps producing handleable output)", path);
896
+ }
897
+ return go(verdict.value, path, replaceDepth + 1);
898
+ }
899
+ return node;
900
+ };
901
+ return go(root, [], 0);
902
+ }
903
+
904
+ // ../transformer/src/transform.ts
905
+ function createTransformer() {
906
+ return build([], []);
907
+ }
908
+ function build(valueHandlers, messageHandlers) {
909
+ const transformer = {
910
+ withHandler(handler) {
911
+ const bundle = "tag" in handler ? { valueHandler: handler } : handler;
912
+ if (!bundle.valueHandler && !bundle.messageHandler) {
913
+ throw new Error("withHandler: bundle provides neither a valueHandler nor a messageHandler");
914
+ }
915
+ if (bundle.valueHandler) {
916
+ const { tag } = bundle.valueHandler;
917
+ if (valueHandlers.some((existing) => existing.tag === tag)) {
918
+ throw new Error(`withHandler: a ValueHandler with tag "${tag}" is already composed`);
919
+ }
920
+ }
921
+ return build(bundle.valueHandler ? [...valueHandlers, bundle.valueHandler] : valueHandlers, bundle.messageHandler ? [...messageHandlers, bundle.messageHandler] : messageHandlers);
922
+ },
923
+ async outbound(value, ctx) {
924
+ const seen = new Map;
925
+ const visit = (node, path) => {
926
+ if (!isComplexValue(node)) {
927
+ return recurse;
928
+ }
929
+ const handler = valueHandlers.find((candidate) => candidate.canHandle(node));
930
+ if (!handler) {
931
+ const withToJSON = node;
932
+ if (typeof node === "object" && typeof withToJSON.toJSON === "function") {
933
+ return replaceWith(withToJSON.toJSON());
934
+ }
935
+ const label = node?.constructor?.name ?? (typeof node === "function" ? "function" : typeof node);
936
+ throw new TransformError(`no composed ValueHandler for complex value of type ${label}`, path);
937
+ }
938
+ if (typeof node === "object" && node !== null) {
939
+ const cached = seen.get(node);
940
+ if (cached) {
941
+ return cached.then(replaceWith);
942
+ }
943
+ const pending = Promise.resolve(handler.serialize(node, ctx, path));
944
+ seen.set(node, pending);
945
+ return pending.then(replaceWith);
946
+ }
947
+ return Promise.resolve(handler.serialize(node, ctx, path)).then(replaceWith);
948
+ };
949
+ const valueTransformed = await walk(value, visit);
950
+ let body = valueTransformed;
951
+ for (const [index, handler] of messageHandlers.entries()) {
952
+ const wrapped = await handler.wrapOutbound(body, ctx);
953
+ assertTopLevelKeysPreserved(body, wrapped, index);
954
+ body = wrapped;
955
+ }
956
+ return body;
957
+ },
958
+ async inbound(value, ctx) {
959
+ const visit = (node, path) => {
960
+ if (!isPlainObject(node)) {
961
+ return recurse;
962
+ }
963
+ const handler = valueHandlers.find((candidate) => candidate.isReference(node));
964
+ if (handler) {
965
+ if (handler.passthrough) {
966
+ return recurse;
967
+ }
968
+ return Promise.resolve(handler.deserialize(node, ctx, path)).then(replaceWith);
969
+ }
970
+ if (hasReferenceTag(node)) {
971
+ const tag = node.__REQUENCE_type;
972
+ throw new TransformError(`no composed ValueHandler owns reference tag ${JSON.stringify(tag)}`, path);
973
+ }
974
+ return recurse;
975
+ };
976
+ return walk(value, visit);
977
+ }
978
+ };
979
+ return transformer;
980
+ }
981
+ function assertTopLevelKeysPreserved(body, wrapped, handlerIndex) {
982
+ if (!isPlainObject(body)) {
983
+ return;
984
+ }
985
+ const label = `MessageHandler #${handlerIndex}`;
986
+ if (!isPlainObject(wrapped)) {
987
+ throw new TransformError(`${label} replaced a record body wholesale — wrapOutbound must preserve a record's top-level keys`, []);
988
+ }
989
+ const before = Object.keys(body);
990
+ const after = new Set(Object.keys(wrapped));
991
+ const removed = before.filter((key) => !after.has(key));
992
+ const added = [...after].filter((key) => !before.includes(key));
993
+ if (removed.length > 0 || added.length > 0) {
994
+ throw new TransformError(`${label} changed a record body's top-level keys (removed: [${removed.join(", ")}], added: [${added.join(", ")}]) — wrapOutbound must preserve them`, []);
995
+ }
996
+ }
997
+ // src/transformer.ts
998
+ var transformer = createTransformer().withHandler(createRequenceFileHandler()).withHandler(createRequenceStreamHandler()).withHandler(createRequenceCallbackHandler()).withHandler(createClaimCheckHandler());
999
+ var passthroughHandler = (handler) => ({
1000
+ tag: handler.tag,
1001
+ passthrough: true,
1002
+ canHandle: () => false,
1003
+ serialize() {
1004
+ throw new Error(`passthrough handler "${handler.tag}" is inbound-only`);
1005
+ },
1006
+ isReference: (value) => handler.isReference(value),
1007
+ deserialize(ref) {
1008
+ return ref;
1009
+ }
1010
+ });
1011
+ var passthroughInboundTransformer = createTransformer().withHandler(passthroughHandler(createRequenceFileHandler())).withHandler(passthroughHandler(createRequenceStreamHandler())).withHandler(passthroughHandler(createRequenceCallbackHandler())).withHandler(createClaimCheckHandler());
1012
+
1013
+ // src/boundary.ts
1014
+ function createOutboundBoundary(base) {
1015
+ const warn = base.warn ?? ((message, error) => error === undefined ? console.warn(message) : console.warn(message, error));
1016
+ const ledger = [];
1017
+ const errors = [];
1018
+ const track = (promise) => {
1019
+ ledger.push(promise.then(() => {}, (error) => {
1020
+ errors.push(error instanceof Error ? error : new Error(String(error)));
1021
+ }));
1022
+ };
1023
+ return {
1024
+ track,
1025
+ async send(data, opts = {}) {
1026
+ const ctx = {
1027
+ fetch: base.fetch ?? globalThis.fetch,
1028
+ signal: base.signal,
1029
+ uploadUrl: base.uploadUrl,
1030
+ streamUrl: base.streamUrl,
1031
+ maxPayloadSize: base.maxPayloadSize,
1032
+ maxFileSize: base.maxFileSize,
1033
+ outputName: opts.outputName ?? null,
1034
+ onCallback: opts.onCallback,
1035
+ ...opts.bestEffort ? {
1036
+ onOffloadFail: (error) => warn("offload failed (best-effort log path):", error),
1037
+ onOffloadSkip: () => warn("offload skipped: no upload transport configured")
1038
+ } : {}
1039
+ };
1040
+ if (opts.bestEffort) {
1041
+ try {
1042
+ const { value: value2, done: done2 } = await withRequenceStreams(() => transformer.outbound(sanitizeLogData(data), ctx));
1043
+ ledger.push(done2.then(() => {}, (error) => warn("log stream upload failed:", error)));
1044
+ return value2;
1045
+ } catch (error) {
1046
+ warn("log offload errored:", error);
1047
+ return;
1048
+ }
1049
+ }
1050
+ const { value, done } = await withRequenceStreams(() => transformer.outbound(data, ctx));
1051
+ track(done);
1052
+ return value;
1053
+ },
1054
+ async settle() {
1055
+ for (;; ) {
1056
+ const count = ledger.length;
1057
+ await Promise.all(ledger);
1058
+ if (count === ledger.length) {
1059
+ break;
1060
+ }
1061
+ }
1062
+ if (errors.length > 0) {
1063
+ const failed = errors.splice(0);
1064
+ throw new AggregateError(failed, failed[0].message);
1065
+ }
1066
+ }
1067
+ };
1068
+ }
1069
+ function createInboundBoundary(base = {}) {
1070
+ return (data, opts = {}) => {
1071
+ const timeout = base.timeoutMs && base.timeoutMs > 0 ? AbortSignal.timeout(base.timeoutMs) : undefined;
1072
+ const signal = base.signal && timeout ? AbortSignal.any([base.signal, timeout]) : timeout ?? base.signal;
1073
+ const ctx = {
1074
+ fetch: base.fetch ?? globalThis.fetch,
1075
+ signal,
1076
+ onCallbackInvoke: opts.onCallbackInvoke ?? base.onCallbackInvoke
1077
+ };
1078
+ return (base.transformer ?? transformer).inbound(data, ctx);
1079
+ };
412
1080
  }
413
1081
 
414
1082
  // src/helpers.ts
415
- import { AsyncLocalStorage } from "node:async_hooks";
1083
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
416
1084
  class RetryError extends Error {
417
1085
  delay;
418
1086
  constructor(delay) {
@@ -430,124 +1098,87 @@ var OUTPUT_VALUE = Symbol("output_value");
430
1098
  function isOutputValue(value) {
431
1099
  return value !== null && typeof value === "object" && OUTPUT_VALUE in value;
432
1100
  }
433
- function processData(params) {
434
- return mapOutput({
435
- value: mapData(params.data, {
436
- Function(data, path) {
437
- return {
438
- ...params.onCallback(data),
439
- outputName: params.outputName,
440
- propertyPath: path,
441
- __REQUENCE_type: "RequenceCallback"
442
- };
443
- }
444
- }),
445
- options: params.options,
446
- onDone: params.onDone
447
- });
448
- }
449
- async function unwrapResult(params) {
450
- if (isOutputValue(params.result)) {
451
- return {
452
- value: await processData({
453
- outputName: params.result[OUTPUT_VALUE],
454
- data: params.result.value,
455
- options: params.options,
456
- onDone: params.onDone,
457
- onCallback: params.onCallback
458
- }),
459
- outputName: params.result[OUTPUT_VALUE]
460
- };
1101
+ function unwrapOutputValue(result) {
1102
+ if (isOutputValue(result)) {
1103
+ return { value: result.value, outputName: result[OUTPUT_VALUE] };
461
1104
  }
462
- return {
463
- value: await processData({
464
- outputName: null,
465
- data: params.result,
466
- options: params.options,
467
- onDone: params.onDone,
468
- onCallback: params.onCallback
469
- }),
470
- outputName: null
471
- };
1105
+ return { value: result, outputName: null };
472
1106
  }
473
- function createContextHelper(options) {
1107
+ async function createContextHelper(options) {
474
1108
  const terminatePromise = Promise.withResolvers();
475
- const abortController = new AbortController;
1109
+ const abortController = options.abortController ?? new AbortController;
476
1110
  terminatePromise.promise.then(() => abortController.abort());
477
1111
  const terminated = Object.assign(terminatePromise.promise, {
478
1112
  signal: abortController.signal
479
1113
  });
480
- return [
481
- {
482
- taskId: options.taskId,
483
- input: resolveRequenceTypes(options.input, options.onCallback),
484
- configuration: resolveRequenceTypes(options.configuration, () => {
1114
+ const inbound = createInboundBoundary({
1115
+ signal: abortController.signal,
1116
+ ...options.passthroughByteReferences ? { transformer: passthroughInboundTransformer } : {}
1117
+ });
1118
+ const [input, configuration] = await Promise.all([
1119
+ inbound(options.input, { onCallbackInvoke: options.onCallback }),
1120
+ inbound(options.configuration, {
1121
+ onCallbackInvoke: () => {
485
1122
  throw new Error("configuration may not have callbacks");
486
- }),
487
- toOutput(name, value) {
488
- return {
489
- [OUTPUT_VALUE]: name,
490
- value
491
- };
492
- },
493
- defer: options.onDefer,
494
- debug: {
495
- log(...data) {
496
- options.onLog("log", data);
497
- },
498
- info(...data) {
499
- options.onLog("info", data);
500
- },
501
- warn(...data) {
502
- options.onLog("warn", data);
503
- },
504
- error(...data) {
505
- options.onLog("error", data);
506
- }
507
- },
508
- retry(delay) {
509
- throw new RetryError(delay);
1123
+ }
1124
+ })
1125
+ ]);
1126
+ const context = {
1127
+ taskId: options.taskId,
1128
+ input,
1129
+ configuration,
1130
+ toOutput(name, value) {
1131
+ return {
1132
+ [OUTPUT_VALUE]: name,
1133
+ value
1134
+ };
1135
+ },
1136
+ defer: options.onDefer,
1137
+ debug: {
1138
+ log(...data) {
1139
+ options.onLog("log", data);
510
1140
  },
511
- abort(reason) {
512
- throw new AbortError(reason);
1141
+ info(...data) {
1142
+ options.onLog("info", data);
513
1143
  },
514
- skip() {
515
- throw new SkipError;
1144
+ warn(...data) {
1145
+ options.onLog("warn", data);
516
1146
  },
517
- terminated
518
- },
519
- terminatePromise
520
- ];
521
- }
522
- var handlerStorage = new AsyncLocalStorage;
523
-
524
- // src/mapInput.ts
525
- function mapInput(data) {
526
- return mapData(data, {
527
- Object(obj) {
528
- if (isFileObject(obj)) {
529
- return RequenceFile.fromFileObject(obj);
530
- }
531
- if (isStreamObject(obj)) {
532
- return RequenceStream.fromStreamObject(obj);
1147
+ error(...data) {
1148
+ options.onLog("error", data);
533
1149
  }
534
- }
535
- });
1150
+ },
1151
+ retry(delay) {
1152
+ throw new RetryError(delay);
1153
+ },
1154
+ abort(reason) {
1155
+ throw new AbortError(reason);
1156
+ },
1157
+ skip() {
1158
+ throw new SkipError;
1159
+ },
1160
+ terminated
1161
+ };
1162
+ Object.assign(context, options.sends);
1163
+ return [context, terminatePromise];
536
1164
  }
1165
+ var handlerStorage = new AsyncLocalStorage2;
537
1166
 
538
1167
  // src/createAmqpConnection.ts
539
- var messageKeySchema = z5.string().transform((str) => deobfuscate(str)).pipe(z5.tuple([z5.uuid(), z5.uuid()]).rest(z5.string())).transform((arr) => ({
1168
+ var messageKeySchema = z6.string().transform((str) => deobfuscate(str)).pipe(z6.tuple([z6.uuid(), z6.uuid()]).rest(z6.string())).transform((arr) => ({
540
1169
  taskId: arr[0],
541
1170
  messageId: arr[1],
542
1171
  uploadUrl: arr[2] || undefined,
543
- streamUrl: arr[3] || undefined
1172
+ streamUrl: arr[3] || undefined,
1173
+ maxPayloadSize: arr[4] && Number.isFinite(Number(arr[4])) ? Number(arr[4]) : undefined,
1174
+ maxFileSize: arr[5] && Number.isFinite(Number(arr[5])) ? Number(arr[5]) : undefined
544
1175
  }));
545
- var headerSchema = z5.object({
546
- properties: z5.object({
547
- correlationId: z5.uuid(),
548
- headers: z5.object({
549
- taskId: z5.uuid(),
550
- mode: z5.enum(["LINEAR", "CONTINUOUS"]).default("LINEAR")
1176
+ var headerSchema = z6.object({
1177
+ properties: z6.object({
1178
+ correlationId: z6.uuid(),
1179
+ headers: z6.object({
1180
+ taskId: z6.uuid(),
1181
+ mode: z6.enum(["LINEAR", "CONTINUOUS"]).default("LINEAR")
551
1182
  })
552
1183
  })
553
1184
  }).transform((msg) => ({
@@ -555,62 +1186,100 @@ var headerSchema = z5.object({
555
1186
  taskId: msg.properties.headers.taskId,
556
1187
  mode: msg.properties.headers.mode
557
1188
  }));
558
- var payloadSchema = z5.object({ content: z5.instanceof(Buffer) }).transform((msg) => JSON.parse(msg.content.toString())).pipe(z5.object({
559
- input: z5.unknown(),
560
- configuration: z5.unknown(),
561
- options: z5.object({
562
- uploadUrl: z5.url().optional(),
563
- streamUrl: z5.url().optional()
1189
+ var payloadSchema = z6.object({ content: z6.instanceof(Buffer) }).transform((msg) => JSON.parse(msg.content.toString())).pipe(z6.object({
1190
+ input: z6.unknown(),
1191
+ configuration: z6.unknown(),
1192
+ options: z6.object({
1193
+ uploadUrl: z6.url().optional(),
1194
+ streamUrl: z6.url().optional(),
1195
+ maxPayloadSize: z6.number().optional(),
1196
+ maxFileSize: z6.number().optional()
564
1197
  })
565
1198
  }));
566
- var backchannelMessageSchema = z5.object({
567
- content: z5.instanceof(Buffer).transform((content) => JSON.parse(content.toString())).pipe(z5.discriminatedUnion("type", [
568
- z5.object({
569
- type: z5.literal("stop")
1199
+ var backchannelMessageSchema = z6.object({
1200
+ content: z6.instanceof(Buffer).transform((content) => JSON.parse(content.toString())).pipe(z6.discriminatedUnion("type", [
1201
+ z6.object({
1202
+ type: z6.literal("stop")
570
1203
  }),
571
- z5.object({
572
- type: z5.literal("callback"),
573
- callbackId: z5.uuid(),
574
- arg: z5.any()
1204
+ z6.object({
1205
+ type: z6.literal("callback"),
1206
+ callbackId: z6.uuid(),
1207
+ arg: z6.any()
575
1208
  })
576
1209
  ])),
577
- properties: z5.object({
578
- correlationId: z5.string()
1210
+ properties: z6.object({
1211
+ correlationId: z6.string()
579
1212
  })
580
1213
  }).transform((message) => ({
581
1214
  payload: message.content,
582
1215
  messageId: message.properties.correlationId
583
1216
  }));
584
1217
  var abortSymbol = Symbol();
585
- var connectionOptionsSchema = z5.object({
586
- url: z5.union([
587
- z5.string().regex(/^amqps?:\/\/(.+):(.+)@(.+)$/).transform((str) => new URL(str)),
588
- z5.instanceof(URL).refine((url) => url.protocol.match(/^amqps?:/), "Wrong protocol")
1218
+ var connectionOptionsSchema = z6.object({
1219
+ url: z6.union([
1220
+ z6.string().regex(/^amqps?:\/\/(.+):(.+)@(.+)$/).transform((str) => new URL(str)),
1221
+ z6.instanceof(URL).refine((url) => url.protocol.match(/^amqps?:/), "Wrong protocol")
589
1222
  ]),
590
- version: z5.string(),
591
- devOverlay: z5.string().optional(),
592
- silent: z5.boolean().optional(),
593
- prefetch: z5.number().int().optional(),
594
- connectionTimeout: z5.number().positive().default(3000),
595
- connectionOptions: z5.any().optional()
1223
+ version: z6.string(),
1224
+ devOverlay: z6.string().optional(),
1225
+ silent: z6.boolean().optional(),
1226
+ prefetch: z6.number().int().optional(),
1227
+ connectionTimeout: z6.number().positive().default(3000),
1228
+ heartbeatInterval: z6.number().int().positive().optional(),
1229
+ connectionOptions: z6.any().optional(),
1230
+ maxMessageSize: z6.number().int().positive().default(128 * 1024 * 1024),
1231
+ passthroughByteReferences: z6.boolean().optional()
596
1232
  });
597
1233
  function isMessageHandlerGenerator(handler) {
598
1234
  return handler.constructor.name === "GeneratorFunction" || handler.constructor.name === "AsyncGeneratorFunction";
599
1235
  }
600
1236
  var activeMessages = new Map;
1237
+ function isChannelClosedError(error) {
1238
+ return error instanceof Error && error.name === "IllegalOperationError";
1239
+ }
1240
+ function safeAck(channel, message) {
1241
+ try {
1242
+ channel.ack(message);
1243
+ } catch (error) {
1244
+ if (!isChannelClosedError(error)) {
1245
+ throw error;
1246
+ }
1247
+ }
1248
+ }
1249
+ function safeNack(channel, message) {
1250
+ try {
1251
+ channel.nack(message);
1252
+ } catch (error) {
1253
+ if (!isChannelClosedError(error)) {
1254
+ throw error;
1255
+ }
1256
+ }
1257
+ }
601
1258
  function createConnection({
602
1259
  url,
603
1260
  version,
604
1261
  prefetch = 1,
605
1262
  silent = false,
606
1263
  connectionTimeout,
1264
+ heartbeatInterval = DEFAULT_AMQP_HEARTBEAT_SECONDS,
607
1265
  connectionOptions,
608
- devOverlay = ""
1266
+ devOverlay = "",
1267
+ maxMessageSize,
1268
+ ...rest
609
1269
  }, messageHandler) {
1270
+ const passthroughByteReferences = rest.passthroughByteReferences ?? false;
610
1271
  const baseQueue = `${url.username}@${version}`;
611
1272
  const queue = devOverlay ? `${baseQueue}-dev-overlay-${devOverlay}` : baseQueue;
612
1273
  const exchange = url.username;
613
- const connection = connect(url.toString(), { connectionOptions });
1274
+ const connection = connect(url.toString(), {
1275
+ connectionOptions,
1276
+ heartbeatIntervalInSeconds: heartbeatInterval
1277
+ });
1278
+ connection.on("disconnect", ({ err }) => {
1279
+ if (!silent && err) {
1280
+ console.error("Requence AMQP connection lost:", err.message);
1281
+ }
1282
+ });
614
1283
  const connectedPromise = new Promise((resolve2, reject) => {
615
1284
  const unsubscribe = () => {
616
1285
  clearTimeout(timeout);
@@ -641,6 +1310,7 @@ function createConnection({
641
1310
  const backchannelQueue = `${baseQueue}-backchannel-${connectionId}`;
642
1311
  const generatorTerminators = new Map;
643
1312
  const callbacks = new Map;
1313
+ const backchannelInbound = createInboundBoundary(passthroughByteReferences ? { transformer: passthroughInboundTransformer } : {});
644
1314
  const channelWrapper = connection.createChannel({
645
1315
  async setup(channel) {
646
1316
  if (devOverlay) {
@@ -667,7 +1337,20 @@ function createConnection({
667
1337
  break;
668
1338
  }
669
1339
  case "callback": {
670
- callbacks.get(backchannelMessage.payload.callbackId)?.(backchannelMessage.payload.arg);
1340
+ const entry = callbacks.get(backchannelMessage.payload.callbackId);
1341
+ if (!entry) {
1342
+ break;
1343
+ }
1344
+ let arg;
1345
+ try {
1346
+ arg = await backchannelInbound(backchannelMessage.payload.arg, {
1347
+ onCallbackInvoke: entry.onCallbackInvoke
1348
+ });
1349
+ } catch (error) {
1350
+ console.warn(`dropped callback invocation |${backchannelMessage.payload.callbackId}|: argument rehydration failed`, error instanceof Error ? error.message : error);
1351
+ break;
1352
+ }
1353
+ entry.callback(arg);
671
1354
  break;
672
1355
  }
673
1356
  }
@@ -676,24 +1359,86 @@ function createConnection({
676
1359
  });
677
1360
  }
678
1361
  });
1362
+ channelWrapper.on("error", (err) => {
1363
+ if (!silent) {
1364
+ console.error("Requence AMQP channel error:", err.message);
1365
+ }
1366
+ });
679
1367
  const publish = ({
680
1368
  data,
681
1369
  outputName,
682
1370
  messageId,
683
1371
  priority,
684
1372
  ...headers
685
- }) => channelWrapper.publish(exchange, "", Buffer.from(JSON.stringify(data ?? null)), {
686
- correlationId: messageId,
687
- contentType: "application/json",
688
- persistent: true,
689
- priority,
690
- headers: {
691
- outputName: outputName ?? null,
692
- connectionId,
693
- libVersion: "javascript@0.7.1",
694
- ...headers
1373
+ }) => {
1374
+ const body = Buffer.from(JSON.stringify(data ?? null));
1375
+ if (body.byteLength > maxMessageSize) {
1376
+ return Promise.reject(new PayloadTooLargeError(body.byteLength, maxMessageSize));
695
1377
  }
696
- });
1378
+ return channelWrapper.publish(exchange, "", body, {
1379
+ correlationId: messageId,
1380
+ contentType: "application/json",
1381
+ persistent: true,
1382
+ priority,
1383
+ headers: {
1384
+ outputName: outputName ?? null,
1385
+ connectionId,
1386
+ libVersion: "javascript@0.8.1",
1387
+ ...headers
1388
+ }
1389
+ });
1390
+ };
1391
+ const buildSendApi = (deps) => {
1392
+ const base = {
1393
+ ...deps.epoch === undefined ? {} : { epoch: deps.epoch },
1394
+ ...deps.priority === undefined ? {} : { priority: deps.priority }
1395
+ };
1396
+ return {
1397
+ async sendToOutput(outputName, data, options) {
1398
+ await deps.gate?.();
1399
+ deps.outbound.track(publish({
1400
+ index: deps.nextIndex(),
1401
+ version,
1402
+ messageId: deps.messageId,
1403
+ taskId: deps.taskId,
1404
+ data: await deps.outbound.send(data, {
1405
+ outputName,
1406
+ onCallback: deps.registerCallback
1407
+ }),
1408
+ outputName,
1409
+ ...options?.overwrite ? { overwrite: true } : {},
1410
+ ...base
1411
+ }));
1412
+ },
1413
+ async send(data, options) {
1414
+ await deps.gate?.();
1415
+ deps.outbound.track(publish({
1416
+ index: deps.nextIndex(),
1417
+ version,
1418
+ messageId: deps.messageId,
1419
+ taskId: deps.taskId,
1420
+ data: await deps.outbound.send(data, {
1421
+ outputName: null,
1422
+ onCallback: deps.registerCallback
1423
+ }),
1424
+ ...options?.overwrite ? { overwrite: true } : {},
1425
+ ...base
1426
+ }));
1427
+ },
1428
+ async sendState(state) {
1429
+ await deps.gate?.();
1430
+ deps.outbound.track(publish({
1431
+ index: 0,
1432
+ version,
1433
+ messageId: deps.messageId,
1434
+ taskId: deps.taskId,
1435
+ data: await deps.outbound.send(state, { outputName: null }),
1436
+ state: true,
1437
+ ...base
1438
+ }));
1439
+ }
1440
+ };
1441
+ };
697
1442
  channelWrapper.addSetup(async (channel) => {
698
1443
  channel.consume(queue, async (message) => {
699
1444
  if (!message) {
@@ -702,11 +1447,13 @@ function createConnection({
702
1447
  let publishIndex = 0;
703
1448
  let acked = false;
704
1449
  let terminated = false;
705
- const donePromises = [];
706
1450
  const registeredCallbackIds = new Set;
707
1451
  let resolveActiveMessage = () => {};
708
- const { messageId, taskId, mode } = headerSchema.parse(message);
1452
+ let messageIdForCleanup;
1453
+ const epoch = crypto.randomUUID();
709
1454
  try {
1455
+ const { messageId, taskId, mode } = headerSchema.parse(message);
1456
+ messageIdForCleanup = messageId;
710
1457
  let deferred = false;
711
1458
  let deferredReason = null;
712
1459
  const messageExecution = Promise.withResolvers();
@@ -718,40 +1465,90 @@ function createConnection({
718
1465
  messageExecution.resolve();
719
1466
  };
720
1467
  const payload = payloadSchema.parse(message);
721
- const [extendedContext, terminatePromise] = createContextHelper({
1468
+ const abortController = new AbortController;
1469
+ const registerCallback = (callback) => {
1470
+ const callbackId = crypto.randomUUID();
1471
+ registeredCallbackIds.add(callbackId);
1472
+ callbacks.set(callbackId, {
1473
+ callback,
1474
+ onCallbackInvoke: dispatchInvocation
1475
+ });
1476
+ return { sourceId: connectionId, callbackId };
1477
+ };
1478
+ const outbound = createOutboundBoundary({
1479
+ uploadUrl: payload.options.uploadUrl,
1480
+ streamUrl: payload.options.streamUrl,
1481
+ maxPayloadSize: payload.options.maxPayloadSize,
1482
+ maxFileSize: payload.options.maxFileSize,
1483
+ signal: abortController.signal,
1484
+ warn: (msg, error) => console.warn(`${msg} (task ${taskId})`, error instanceof Error ? error.message : error ?? "")
1485
+ });
1486
+ const dispatchInvocation = (params) => {
1487
+ outbound.track(outbound.send(params.arg, {
1488
+ outputName: params.outputName,
1489
+ onCallback: registerCallback
1490
+ }).then((data) => publish({
1491
+ index: 0,
1492
+ version,
1493
+ taskId,
1494
+ messageId,
1495
+ data,
1496
+ outputName: params.outputName,
1497
+ connectionId: params.sourceId,
1498
+ callbackId: params.callbackId,
1499
+ propertyPath: params.propertyPath,
1500
+ epoch
1501
+ })));
1502
+ };
1503
+ const [extendedContext, terminatePromise] = await createContextHelper({
722
1504
  taskId,
723
- input: mapInput(payload.input),
724
- configuration: mapInput(payload.configuration),
725
- onLog(debugMethod, data) {
726
- publish({
727
- index: publishIndex++,
728
- version,
729
- messageId,
1505
+ input: payload.input,
1506
+ configuration: payload.configuration,
1507
+ abortController,
1508
+ passthroughByteReferences,
1509
+ sends: {
1510
+ ...buildSendApi({
1511
+ outbound,
1512
+ registerCallback,
730
1513
  taskId,
731
- data,
732
- debugMethod,
733
- priority: message.properties.priority,
734
- debug: true
1514
+ messageId,
1515
+ nextIndex: () => publishIndex++,
1516
+ epoch,
1517
+ priority: message.properties.priority
1518
+ }),
1519
+ invokeCallback: (ref, arg) => dispatchInvocation({
1520
+ sourceId: ref.sourceId,
1521
+ callbackId: ref.callbackId,
1522
+ outputName: ref.outputName,
1523
+ propertyPath: ref.propertyPath,
1524
+ arg
1525
+ }),
1526
+ options: payload.options
1527
+ },
1528
+ onLog(debugMethod, data) {
1529
+ outbound.send(data, { bestEffort: true }).then((mapped) => {
1530
+ if (mapped === undefined) {
1531
+ return;
1532
+ }
1533
+ publish({
1534
+ index: publishIndex++,
1535
+ version,
1536
+ messageId,
1537
+ taskId,
1538
+ data: mapped,
1539
+ debugMethod,
1540
+ priority: message.properties.priority,
1541
+ debug: true,
1542
+ epoch
1543
+ });
735
1544
  });
736
1545
  },
737
1546
  onDefer(reason) {
738
1547
  deferred = true;
739
1548
  deferredReason = reason || null;
740
- return obfuscate(taskId, messageId, payload.options.uploadUrl ?? "", payload.options.streamUrl ?? "");
1549
+ return obfuscate(taskId, messageId, payload.options.uploadUrl ?? "", payload.options.streamUrl ?? "", payload.options.maxPayloadSize?.toString() ?? "", payload.options.maxFileSize?.toString() ?? "");
741
1550
  },
742
- onCallback(params) {
743
- publish({
744
- index: 0,
745
- version,
746
- taskId,
747
- messageId,
748
- data: params.arg,
749
- outputName: params.outputName,
750
- connectionId: params.sourceId,
751
- callbackId: params.callbackId,
752
- propertyPath: params.propertyPath
753
- });
754
- }
1551
+ onCallback: dispatchInvocation
755
1552
  });
756
1553
  await publish({
757
1554
  index: publishIndex++,
@@ -759,11 +1556,14 @@ function createConnection({
759
1556
  messageId,
760
1557
  taskId,
761
1558
  priority: message.properties.priority,
762
- begin: true
1559
+ begin: true,
1560
+ epoch
763
1561
  });
764
- if (isMessageHandlerGenerator(messageHandler) && mode === "CONTINUOUS") {
765
- channel.ack(message);
766
- acked = true;
1562
+ if (isMessageHandlerGenerator(messageHandler)) {
1563
+ if (mode === "CONTINUOUS") {
1564
+ safeAck(channel, message);
1565
+ acked = true;
1566
+ }
767
1567
  const generator = messageHandler(extendedContext);
768
1568
  const terminationPromise = Promise.withResolvers();
769
1569
  generatorTerminators.set(messageId, (reason) => {
@@ -797,31 +1597,21 @@ function createConnection({
797
1597
  deferred = false;
798
1598
  console.warn("returning a value in a deferred message resets the deferred status");
799
1599
  }
800
- const donePromise = Promise.withResolvers();
801
- donePromises.push(donePromise.promise);
802
- const { value, outputName } = await unwrapResult({
803
- result,
804
- options: payload.options,
805
- onDone: donePromise.resolve,
806
- onCallback: (callback) => {
807
- const callbackId = crypto.randomUUID();
808
- registeredCallbackIds.add(callbackId);
809
- callbacks.set(callbackId, callback);
810
- return {
811
- sourceId: connectionId,
812
- callbackId
813
- };
814
- }
1600
+ const { value: rawValue, outputName } = unwrapOutputValue(result);
1601
+ const value = await outbound.send(rawValue, {
1602
+ outputName,
1603
+ onCallback: registerCallback
815
1604
  });
816
1605
  if (!done || typeof value !== "undefined") {
817
- publish({
1606
+ await publish({
818
1607
  index: publishIndex++,
819
1608
  version,
820
1609
  messageId,
821
1610
  taskId,
822
1611
  data: value,
823
1612
  priority: message.properties.priority,
824
- outputName
1613
+ outputName,
1614
+ epoch
825
1615
  });
826
1616
  }
827
1617
  if (done) {
@@ -831,12 +1621,9 @@ function createConnection({
831
1621
  });
832
1622
  } else {
833
1623
  const result = await handlerStorage.run(extendedContext, () => messageHandler(extendedContext));
834
- const donePromise = Promise.withResolvers();
835
- donePromises.push(donePromise.promise);
836
- const { value, outputName } = await unwrapResult({
837
- result,
838
- options: payload.options,
839
- onDone: donePromise.resolve,
1624
+ const { value: rawValue, outputName } = unwrapOutputValue(result);
1625
+ const value = await outbound.send(rawValue, {
1626
+ outputName,
840
1627
  onCallback: () => {
841
1628
  throw new Error("callbacks can only be used in generator functions");
842
1629
  }
@@ -846,59 +1633,69 @@ function createConnection({
846
1633
  deferred = false;
847
1634
  }
848
1635
  if (!deferred || value) {
849
- publish({
1636
+ await publish({
850
1637
  index: publishIndex++,
851
1638
  version,
852
1639
  messageId,
853
1640
  taskId,
854
1641
  data: value,
855
1642
  priority: message.properties.priority,
856
- outputName
1643
+ outputName,
1644
+ epoch
857
1645
  });
858
1646
  }
859
1647
  }
860
- await new Promise((resolve2) => {
1648
+ await new Promise((resolve2, reject) => {
861
1649
  setImmediate(async () => {
862
- if (!deferred) {
863
- await Promise.allSettled(donePromises);
864
- }
865
- await publish({
866
- index: publishIndex++,
867
- version,
868
- messageId,
869
- taskId,
870
- data: deferredReason,
871
- priority: message.properties.priority,
872
- deferred,
873
- done: !deferred
874
- });
875
- if (!acked) {
876
- channel.ack(message);
1650
+ try {
1651
+ if (!deferred) {
1652
+ await outbound.settle();
1653
+ }
1654
+ await publish({
1655
+ index: publishIndex++,
1656
+ version,
1657
+ messageId,
1658
+ taskId,
1659
+ data: deferredReason,
1660
+ priority: message.properties.priority,
1661
+ deferred,
1662
+ done: !deferred,
1663
+ epoch
1664
+ });
1665
+ if (!acked) {
1666
+ safeAck(channel, message);
1667
+ }
1668
+ resolve2();
1669
+ } catch (error) {
1670
+ reject(error);
877
1671
  }
878
- resolve2();
879
1672
  });
880
1673
  });
881
1674
  } catch (error) {
882
1675
  if (error instanceof SkipError) {
883
1676
  if (!acked) {
884
- channel.nack(message);
1677
+ safeNack(channel, message);
885
1678
  }
886
1679
  return;
887
1680
  }
888
1681
  if (error instanceof RetryError) {
889
1682
  if (!acked) {
890
- channel.ack(message);
1683
+ safeAck(channel, message);
891
1684
  }
892
1685
  const properties = {
893
1686
  ...message.properties,
894
1687
  expiration: error.delay || 1000
895
1688
  };
896
- channel.publish(`${exchange}-retry`, version, message.content, properties);
1689
+ channelWrapper.publish(`${exchange}-retry`, version, message.content, properties).catch((publishError) => {
1690
+ if (!silent) {
1691
+ console.error("Failed to republish message for retry:", publishError);
1692
+ }
1693
+ });
897
1694
  return;
898
1695
  }
899
1696
  if (error instanceof AbortError && error.message.length > 0) {
900
1697
  if (!acked) {
901
- channelWrapper.ack(message);
1698
+ safeAck(channel, message);
902
1699
  }
903
1700
  channelWrapper.publish(`${exchange}-retry`, "operator", error.message, {
904
1701
  ...message.properties,
@@ -906,15 +1703,19 @@ function createConnection({
906
1703
  headers: {
907
1704
  ...message.properties.headers,
908
1705
  index: publishIndex++,
909
- libVersion: "javascript@0.7.1",
1706
+ libVersion: "javascript@0.8.1",
910
1707
  abort: true
911
1708
  }
1709
+ }).catch((publishError) => {
1710
+ if (!silent) {
1711
+ console.error("Failed to publish abort message:", publishError);
1712
+ }
912
1713
  });
913
1714
  return;
914
1715
  }
915
1716
  if (terminated && error instanceof Error && error.name === "AbortError" && !(error instanceof AbortError)) {
916
1717
  if (!acked) {
917
- channel.ack(message);
1718
+ safeAck(channel, message);
918
1719
  }
919
1720
  return;
920
1721
  }
@@ -924,23 +1725,29 @@ function createConnection({
924
1725
  console.error(error);
925
1726
  }
926
1727
  if (!acked) {
927
- channel.ack(message);
1728
+ safeAck(channel, message);
928
1729
  }
929
- channel.publish(`${exchange}-retry`, "operator", message.content, {
1730
+ channelWrapper.publish(`${exchange}-retry`, "operator", message.content, {
930
1731
  ...message.properties,
931
1732
  headers: {
932
1733
  ...message.properties.headers,
933
1734
  version,
934
1735
  exception: true,
935
1736
  index: publishIndex++,
936
- libVersion: "javascript@0.7.1",
1737
+ libVersion: "javascript@0.8.1",
937
1738
  "error-message": error.message || "error in service handler"
938
1739
  }
1740
+ }).catch((publishError) => {
1741
+ if (!silent) {
1742
+ console.error("Failed to publish exception message:", publishError);
1743
+ }
939
1744
  });
940
1745
  return;
941
1746
  }
942
1747
  } finally {
943
- generatorTerminators.delete(messageId);
1748
+ if (messageIdForCleanup) {
1749
+ generatorTerminators.delete(messageIdForCleanup);
1750
+ }
944
1751
  registeredCallbackIds.forEach((id) => callbacks.delete(id));
945
1752
  resolveActiveMessage();
946
1753
  }
@@ -966,61 +1773,41 @@ function createConnection({
966
1773
  }
967
1774
  };
968
1775
  const registeredCallbackIds = new Set;
969
- const donePromises = [];
1776
+ const outbound = createOutboundBoundary(options);
1777
+ const registerCallback = (callback) => {
1778
+ const callbackId = crypto.randomUUID();
1779
+ registeredCallbackIds.add(callbackId);
1780
+ callbacks.set(callbackId, {
1781
+ callback,
1782
+ onCallbackInvoke: dispatchInvocation
1783
+ });
1784
+ return { sourceId: connectionId, callbackId };
1785
+ };
1786
+ const dispatchInvocation = (params) => {
1787
+ outbound.track(outbound.send(params.arg, {
1788
+ outputName: params.outputName,
1789
+ onCallback: registerCallback
1790
+ }).then((data) => publish({
1791
+ index: 0,
1792
+ version,
1793
+ taskId,
1794
+ messageId,
1795
+ data,
1796
+ outputName: params.outputName,
1797
+ connectionId: params.sourceId,
1798
+ callbackId: params.callbackId,
1799
+ propertyPath: params.propertyPath
1800
+ })));
1801
+ };
970
1802
  const sendApi = {
971
- async sendToOutput(outputName, data) {
972
- await activeMessage();
973
- const donePromise = Promise.withResolvers();
974
- donePromises.push(donePromise.promise);
975
- donePromises.push(publish({
976
- index: publishIndex++,
977
- version,
978
- messageId,
979
- taskId,
980
- data: await processData({
981
- outputName,
982
- data,
983
- options,
984
- onDone: donePromise.resolve,
985
- onCallback: (callback) => {
986
- const callbackId = crypto.randomUUID();
987
- registeredCallbackIds.add(callbackId);
988
- callbacks.set(callbackId, callback);
989
- return {
990
- sourceId: connectionId,
991
- callbackId
992
- };
993
- }
994
- }),
995
- outputName
996
- }));
997
- },
998
- async send(data) {
999
- await activeMessage();
1000
- const donePromise = Promise.withResolvers();
1001
- donePromises.push(donePromise.promise);
1002
- donePromises.push(publish({
1003
- index: publishIndex++,
1004
- version,
1005
- messageId,
1006
- taskId,
1007
- data: await processData({
1008
- outputName: null,
1009
- data,
1010
- options,
1011
- onDone: donePromise.resolve,
1012
- onCallback: (callback) => {
1013
- const callbackId = crypto.randomUUID();
1014
- registeredCallbackIds.add(callbackId);
1015
- callbacks.set(callbackId, callback);
1016
- return {
1017
- sourceId: connectionId,
1018
- callbackId
1019
- };
1020
- }
1021
- })
1022
- }));
1023
- },
1803
+ ...buildSendApi({
1804
+ outbound,
1805
+ registerCallback,
1806
+ taskId,
1807
+ messageId,
1808
+ nextIndex: () => publishIndex++,
1809
+ gate: activeMessage
1810
+ }),
1024
1811
  async abort(error) {
1025
1812
  await activeMessage();
1026
1813
  channelWrapper.publish(`${exchange}-retry`, "operator", error instanceof Error ? error.message : error, {
@@ -1031,7 +1818,7 @@ function createConnection({
1031
1818
  contentType: "text/plain",
1032
1819
  headers: {
1033
1820
  taskId,
1034
- libVersion: "javascript@0.7.1",
1821
+ libVersion: "javascript@0.8.1",
1035
1822
  index: publishIndex++,
1036
1823
  abort: true
1037
1824
  }
@@ -1051,12 +1838,14 @@ function createConnection({
1051
1838
  }
1052
1839
  await new Promise((resolve2) => setImmediate(resolve2));
1053
1840
  await activeMessage();
1054
- while (true) {
1055
- const promiseCount = donePromises.length;
1056
- await Promise.allSettled(donePromises);
1057
- if (promiseCount === donePromises.length) {
1058
- break;
1059
- }
1841
+ try {
1842
+ await outbound.settle();
1843
+ } catch (error) {
1844
+ registeredCallbackIds.forEach((id) => callbacks.delete(id));
1845
+ const first = error instanceof AggregateError && error.errors[0] instanceof Error ? error.errors[0] : error instanceof Error ? error : new Error(String(error));
1846
+ await sendApi.abort(first);
1847
+ activeMessageKeys.delete(messageKey);
1848
+ throw error;
1060
1849
  }
1061
1850
  registeredCallbackIds.forEach((id) => callbacks.delete(id));
1062
1851
  await publish({
@@ -1157,6 +1946,24 @@ function asyncEventEmitter(initial = []) {
1157
1946
  }
1158
1947
 
1159
1948
  // src/index.ts
1949
+ function resolveConnectionOptions(connectionOptions) {
1950
+ const rejectEnv = process.env.REJECT_UNAUTHORIZED;
1951
+ const caEnv = process.env.CA;
1952
+ const caFileEnv = process.env.CA_FILE;
1953
+ const tlsDefaults = {};
1954
+ if (rejectEnv !== undefined) {
1955
+ tlsDefaults.rejectUnauthorized = !/^(false|0|no)$/i.test(rejectEnv.trim());
1956
+ }
1957
+ if (caEnv) {
1958
+ tlsDefaults.ca = caEnv;
1959
+ } else if (caFileEnv) {
1960
+ tlsDefaults.ca = fs.readFileSync(caFileEnv);
1961
+ }
1962
+ if (Object.keys(tlsDefaults).length === 0) {
1963
+ return connectionOptions;
1964
+ }
1965
+ return { ...tlsDefaults, ...connectionOptions };
1966
+ }
1160
1967
  var pkgJson;
1161
1968
  function loadPkgJson() {
1162
1969
  if (!pkgJson) {
@@ -1209,21 +2016,29 @@ function createService(optionsOrVersion, optionalMessageHandler) {
1209
2016
  }
1210
2017
  devOverlay = devParts[1];
1211
2018
  }
2019
+ const envMaxMessageSize = process.env.REQUENCE_MAX_MESSAGE_SIZE ? Number(process.env.REQUENCE_MAX_MESSAGE_SIZE) : undefined;
1212
2020
  return createConnection(connectionOptionsSchema.parse({
1213
2021
  ...options,
2022
+ connectionOptions: resolveConnectionOptions(options.connectionOptions),
2023
+ maxMessageSize: options.maxMessageSize ?? envMaxMessageSize,
1214
2024
  url,
1215
2025
  devOverlay
1216
2026
  }), messageHandler);
1217
2027
  }
1218
2028
  export {
1219
2029
  wrapIterable,
2030
+ reachableFetch,
2031
+ isUnreachableStatus,
1220
2032
  createService,
1221
2033
  createCallback,
1222
2034
  asyncEventEmitter,
2035
+ assertReachable,
2036
+ RequenceUnreachableError,
1223
2037
  RequenceStream,
1224
2038
  RequenceFile,
1225
- RequenceConnectionError
2039
+ RequenceConnectionError,
2040
+ PayloadTooLargeError
1226
2041
  };
1227
2042
 
1228
- //# debugId=DF5C6A6E1370BBD564756E2164756E21
2043
+ //# debugId=06D2FC35693704C864756E2164756E21
1229
2044
  //# sourceMappingURL=index.js.map