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