@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.
- package/CHANGELOG.md +36 -0
- package/README.md +15 -0
- package/build/{chunk-6w7td62p.js → chunk-8r349zge.js} +46 -3
- package/build/chunk-8r349zge.js.map +11 -0
- package/build/cli.js +17 -7
- package/build/cli.js.map +3 -3
- package/build/index.js +1261 -446
- package/build/index.js.map +28 -14
- package/build/types/helpers/src/index.d.ts +8 -2
- package/build/types/helpers/src/index.d.ts.map +1 -1
- package/build/types/helpers/src/jsonschema/validate.d.ts +1 -5
- package/build/types/helpers/src/jsonschema/validate.d.ts.map +1 -1
- package/build/types/helpers/src/jsonschema/zod.d.ts +11 -1
- package/build/types/helpers/src/jsonschema/zod.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/NodeTree.d.ts +450 -144
- package/build/types/helpers/src/protocol/NodeTree.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/command.d.ts +364 -142
- package/build/types/helpers/src/protocol/command.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/configurationScript.d.ts +10 -0
- package/build/types/helpers/src/protocol/configurationScript.d.ts.map +1 -0
- package/build/types/helpers/src/protocol/helpers.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/index.d.ts +4 -0
- package/build/types/helpers/src/protocol/index.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/logicLanguages.d.ts +19 -0
- package/build/types/helpers/src/protocol/logicLanguages.d.ts.map +1 -0
- package/build/types/helpers/src/protocol/loopDetection.d.ts +23 -0
- package/build/types/helpers/src/protocol/loopDetection.d.ts.map +1 -0
- package/build/types/helpers/src/protocol/nodeType.d.ts +73 -27
- package/build/types/helpers/src/protocol/nodeType.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/taskOptions.d.ts +4 -1
- package/build/types/helpers/src/protocol/taskOptions.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/templateNodeTypes.d.ts +36 -20
- package/build/types/helpers/src/protocol/templateNodeTypes.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/treeNodes.d.ts +476 -164
- package/build/types/helpers/src/protocol/treeNodes.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/update.d.ts +22 -22
- package/build/types/helpers/src/protocol/validateTreeStructure.d.ts +22 -0
- package/build/types/helpers/src/protocol/validateTreeStructure.d.ts.map +1 -0
- package/build/types/helpers/src/utils/amqpHeartbeat.d.ts +3 -0
- package/build/types/helpers/src/utils/amqpHeartbeat.d.ts.map +1 -0
- package/build/types/helpers/src/utils/amqpPublishRetry.d.ts +5 -0
- package/build/types/helpers/src/utils/amqpPublishRetry.d.ts.map +1 -0
- package/build/types/helpers/src/utils/claimCheckObject.d.ts +40 -0
- package/build/types/helpers/src/utils/claimCheckObject.d.ts.map +1 -0
- package/build/types/helpers/src/utils/debounce.d.ts.map +1 -1
- package/build/types/helpers/src/{files → utils}/fileObject.d.ts.map +1 -1
- package/build/types/helpers/src/{files → utils}/isValidMimeType.d.ts.map +1 -1
- package/build/types/helpers/src/utils/mapData.d.ts +1 -1
- package/build/types/helpers/src/utils/mapData.d.ts.map +1 -1
- package/build/types/helpers/src/{files → utils}/streamObject.d.ts.map +1 -1
- package/build/types/helpers/src/utils/variableRef.d.ts +19 -0
- package/build/types/helpers/src/utils/variableRef.d.ts.map +1 -0
- package/build/types/helpers/src/utils/variableScriptPatterns.d.ts +125 -0
- package/build/types/helpers/src/utils/variableScriptPatterns.d.ts.map +1 -0
- package/build/types/service/src/boundary.d.ts +75 -0
- package/build/types/service/src/boundary.d.ts.map +1 -0
- package/build/types/service/src/createAmqpConnection.d.ts +21 -4
- package/build/types/service/src/createAmqpConnection.d.ts.map +1 -1
- package/build/types/service/src/errors.d.ts +31 -0
- package/build/types/service/src/errors.d.ts.map +1 -1
- package/build/types/service/src/helpers.d.ts +59 -56
- package/build/types/service/src/helpers.d.ts.map +1 -1
- package/build/types/service/src/index.d.ts +7 -1
- package/build/types/service/src/index.d.ts.map +1 -1
- package/build/types/service/src/transformer.d.ts +16 -0
- package/build/types/service/src/transformer.d.ts.map +1 -0
- package/package.json +6 -3
- package/build/chunk-6w7td62p.js.map +0 -10
- package/build/types/helpers/src/files/RequenceFile.d.ts +0 -40
- package/build/types/helpers/src/files/RequenceFile.d.ts.map +0 -1
- package/build/types/helpers/src/files/RequenceStream.d.ts +0 -32
- package/build/types/helpers/src/files/RequenceStream.d.ts.map +0 -1
- package/build/types/helpers/src/files/index.d.ts +0 -7
- package/build/types/helpers/src/files/index.d.ts.map +0 -1
- package/build/types/helpers/src/files/mapOutput.d.ts +0 -10
- package/build/types/helpers/src/files/mapOutput.d.ts.map +0 -1
- package/build/types/helpers/src/files/types.d.ts +0 -4
- package/build/types/helpers/src/files/types.d.ts.map +0 -1
- package/build/types/helpers/src/utils/createObjectProxy.d.ts +0 -2
- package/build/types/helpers/src/utils/createObjectProxy.d.ts.map +0 -1
- package/build/types/helpers/src/utils/resolveRequenceTypes.d.ts +0 -8
- package/build/types/helpers/src/utils/resolveRequenceTypes.d.ts.map +0 -1
- package/build/types/service/src/mapInput.d.ts +0 -2
- package/build/types/service/src/mapInput.d.ts.map +0 -1
- /package/build/types/helpers/src/{files → utils}/fileObject.d.ts +0 -0
- /package/build/types/helpers/src/{files → utils}/isValidMimeType.d.ts +0 -0
- /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
|
-
|
|
4
|
-
|
|
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
|
-
|
|
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?.(
|
|
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/
|
|
108
|
+
// ../helpers/src/utils/fileObject.ts
|
|
102
109
|
import { z as z2 } from "zod/v4";
|
|
103
|
-
var
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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/
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
141
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
199
|
-
|
|
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
|
-
|
|
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.#
|
|
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
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
// ../
|
|
282
|
-
async function upload(uploadUrl, body,
|
|
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:
|
|
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(
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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:
|
|
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
|
|
313
|
-
throw new Error(
|
|
631
|
+
if (!isStreamObject(toStreamObject(data))) {
|
|
632
|
+
throw new Error(`malformed stream registration response (${streamUrl})`);
|
|
314
633
|
}
|
|
315
634
|
const { mime, url } = data;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
|
|
354
|
-
if (
|
|
355
|
-
|
|
681
|
+
return ref;
|
|
682
|
+
} catch (error) {
|
|
683
|
+
if (!(error instanceof Error)) {
|
|
684
|
+
throw error;
|
|
356
685
|
}
|
|
357
|
-
if (
|
|
358
|
-
|
|
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
|
-
|
|
384
|
-
|
|
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
|
-
|
|
388
|
-
|
|
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 (
|
|
392
|
-
return
|
|
792
|
+
if (RequenceFile.canHandle(obj) || RequenceStream.canHandle(obj)) {
|
|
793
|
+
return;
|
|
393
794
|
}
|
|
394
|
-
|
|
395
|
-
|
|
795
|
+
const proto = Object.getPrototypeOf(obj);
|
|
796
|
+
if (proto === null || proto === Object.prototype) {
|
|
797
|
+
return;
|
|
396
798
|
}
|
|
397
|
-
if (
|
|
398
|
-
return
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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/
|
|
411
|
-
|
|
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
|
|
434
|
-
|
|
435
|
-
value:
|
|
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
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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
|
-
|
|
512
|
-
|
|
1141
|
+
info(...data) {
|
|
1142
|
+
options.onLog("info", data);
|
|
513
1143
|
},
|
|
514
|
-
|
|
515
|
-
|
|
1144
|
+
warn(...data) {
|
|
1145
|
+
options.onLog("warn", data);
|
|
516
1146
|
},
|
|
517
|
-
|
|
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 =
|
|
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 =
|
|
546
|
-
properties:
|
|
547
|
-
correlationId:
|
|
548
|
-
headers:
|
|
549
|
-
taskId:
|
|
550
|
-
mode:
|
|
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 =
|
|
559
|
-
input:
|
|
560
|
-
configuration:
|
|
561
|
-
options:
|
|
562
|
-
uploadUrl:
|
|
563
|
-
streamUrl:
|
|
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 =
|
|
567
|
-
content:
|
|
568
|
-
|
|
569
|
-
type:
|
|
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
|
-
|
|
572
|
-
type:
|
|
573
|
-
callbackId:
|
|
574
|
-
arg:
|
|
1204
|
+
z6.object({
|
|
1205
|
+
type: z6.literal("callback"),
|
|
1206
|
+
callbackId: z6.uuid(),
|
|
1207
|
+
arg: z6.any()
|
|
575
1208
|
})
|
|
576
1209
|
])),
|
|
577
|
-
properties:
|
|
578
|
-
correlationId:
|
|
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 =
|
|
586
|
-
url:
|
|
587
|
-
|
|
588
|
-
|
|
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:
|
|
591
|
-
devOverlay:
|
|
592
|
-
silent:
|
|
593
|
-
prefetch:
|
|
594
|
-
connectionTimeout:
|
|
595
|
-
|
|
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(), {
|
|
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)
|
|
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
|
-
}) =>
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
724
|
-
configuration:
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
1505
|
+
input: payload.input,
|
|
1506
|
+
configuration: payload.configuration,
|
|
1507
|
+
abortController,
|
|
1508
|
+
passthroughByteReferences,
|
|
1509
|
+
sends: {
|
|
1510
|
+
...buildSendApi({
|
|
1511
|
+
outbound,
|
|
1512
|
+
registerCallback,
|
|
730
1513
|
taskId,
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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
|
|
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)
|
|
765
|
-
|
|
766
|
-
|
|
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
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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
|
|
835
|
-
|
|
836
|
-
|
|
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
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
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
|
|
1677
|
+
safeNack(channel, message);
|
|
885
1678
|
}
|
|
886
1679
|
return;
|
|
887
1680
|
}
|
|
888
1681
|
if (error instanceof RetryError) {
|
|
889
1682
|
if (!acked) {
|
|
890
|
-
channel
|
|
1683
|
+
safeAck(channel, message);
|
|
891
1684
|
}
|
|
892
1685
|
const properties = {
|
|
893
1686
|
...message.properties,
|
|
894
1687
|
expiration: error.delay || 1000
|
|
895
1688
|
};
|
|
896
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
1728
|
+
safeAck(channel, message);
|
|
928
1729
|
}
|
|
929
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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.
|
|
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
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
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=
|
|
2043
|
+
//# debugId=06D2FC35693704C864756E2164756E21
|
|
1229
2044
|
//# sourceMappingURL=index.js.map
|