@requence/task 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 +39 -0
- package/README.md +5 -5
- package/build/{chunk-b4h2we9a.js → chunk-f7g9gsa0.js} +33 -3
- package/build/chunk-f7g9gsa0.js.map +11 -0
- package/build/cli.js +18 -8
- package/build/cli.js.map +3 -3
- package/build/index.js +1062 -502
- package/build/index.js.map +27 -16
- 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/task/src/abortTask.d.ts.map +1 -1
- package/build/types/task/src/ackTask.d.ts.map +1 -1
- package/build/types/task/src/createTask.d.ts +0 -1
- package/build/types/task/src/createTask.d.ts.map +1 -1
- package/build/types/task/src/errors.d.ts +27 -0
- package/build/types/task/src/errors.d.ts.map +1 -0
- package/build/types/task/src/getTask.d.ts +4 -4
- package/build/types/task/src/getTask.d.ts.map +1 -1
- package/build/types/task/src/index.d.ts +2 -1
- package/build/types/task/src/index.d.ts.map +1 -1
- package/build/types/task/src/ingress.d.ts +26 -0
- package/build/types/task/src/ingress.d.ts.map +1 -0
- package/build/types/task/src/protectTask.d.ts.map +1 -1
- package/build/types/task/src/recreateTask.d.ts +1 -1
- package/build/types/task/src/recreateTask.d.ts.map +1 -1
- package/build/types/task/src/types.d.ts +10 -10
- package/build/types/task/src/utils/getAccessToken.d.ts.map +1 -1
- package/build/types/task/src/watchTasks.d.ts +2 -0
- package/build/types/task/src/watchTasks.d.ts.map +1 -1
- package/package.json +7 -3
- package/build/chunk-b4h2we9a.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/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,216 +1,203 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
RequenceUnreachableError,
|
|
3
|
+
deobfuscate,
|
|
4
|
+
isUnreachableStatus,
|
|
5
|
+
reachableFetch
|
|
6
|
+
} from "./chunk-f7g9gsa0.js";
|
|
4
7
|
|
|
5
|
-
// ../
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
pushValue({ error });
|
|
32
|
-
}
|
|
33
|
-
}, () => {
|
|
34
|
-
if (!done) {
|
|
35
|
-
pushValue({ done: true });
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
return {
|
|
39
|
-
async next() {
|
|
40
|
-
if (done) {
|
|
41
|
-
return { value: undefined, done: true };
|
|
42
|
-
}
|
|
43
|
-
const value = await pullValue();
|
|
44
|
-
if (value.done) {
|
|
45
|
-
done = true;
|
|
46
|
-
return { value: undefined, done: true };
|
|
8
|
+
// ../files/src/errors.ts
|
|
9
|
+
class RequenceStreamTruncatedError extends Error {
|
|
10
|
+
constructor(message = "stream truncated") {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "RequenceStreamTruncatedError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ../files/src/streamFraming.ts
|
|
17
|
+
var STREAM_PROTOCOL_HEADER = "x-requence-stream-protocol";
|
|
18
|
+
var STREAM_PROTOCOL_FRAMED = "framed";
|
|
19
|
+
var DATA = 0;
|
|
20
|
+
var END = 1;
|
|
21
|
+
var TRUNCATED = 2;
|
|
22
|
+
var HEADER_BYTES = 5;
|
|
23
|
+
var END_FRAME = new Uint8Array([END, 0, 0, 0, 0]);
|
|
24
|
+
function createFrameDecoder() {
|
|
25
|
+
let buffer = new Uint8Array(0);
|
|
26
|
+
let terminal = false;
|
|
27
|
+
return new TransformStream({
|
|
28
|
+
transform(chunk, controller) {
|
|
29
|
+
if (terminal) {
|
|
30
|
+
if (chunk.byteLength > 0) {
|
|
31
|
+
throw new Error("stream protocol error: bytes after terminal frame");
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
47
34
|
}
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
if (buffer.byteLength === 0) {
|
|
36
|
+
buffer = chunk;
|
|
37
|
+
} else {
|
|
38
|
+
const merged = new Uint8Array(buffer.byteLength + chunk.byteLength);
|
|
39
|
+
merged.set(buffer, 0);
|
|
40
|
+
merged.set(chunk, buffer.byteLength);
|
|
41
|
+
buffer = merged;
|
|
51
42
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (typeof cleanup === "function") {
|
|
58
|
-
cleanup();
|
|
43
|
+
while (buffer.byteLength >= HEADER_BYTES) {
|
|
44
|
+
const type = buffer[0];
|
|
45
|
+
const length = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getUint32(1, false);
|
|
46
|
+
if (buffer.byteLength < HEADER_BYTES + length) {
|
|
47
|
+
break;
|
|
59
48
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
const payload = buffer.slice(HEADER_BYTES, HEADER_BYTES + length);
|
|
50
|
+
buffer = buffer.subarray(HEADER_BYTES + length);
|
|
51
|
+
switch (type) {
|
|
52
|
+
case DATA: {
|
|
53
|
+
if (payload.byteLength > 0) {
|
|
54
|
+
controller.enqueue(payload);
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case END: {
|
|
59
|
+
terminal = true;
|
|
60
|
+
if (buffer.byteLength > 0) {
|
|
61
|
+
throw new Error("stream protocol error: bytes after terminal frame");
|
|
62
|
+
}
|
|
63
|
+
controller.terminate();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
case TRUNCATED: {
|
|
67
|
+
terminal = true;
|
|
68
|
+
controller.error(new RequenceStreamTruncatedError(new TextDecoder().decode(payload) || undefined));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
default: {
|
|
72
|
+
throw new Error(`stream protocol error: unknown frame type ${type}`);
|
|
73
|
+
}
|
|
63
74
|
}
|
|
64
75
|
}
|
|
65
|
-
|
|
76
|
+
},
|
|
77
|
+
flush(controller) {
|
|
78
|
+
if (!terminal) {
|
|
79
|
+
controller.error(new RequenceStreamTruncatedError("connection closed before terminal frame"));
|
|
80
|
+
}
|
|
66
81
|
}
|
|
67
|
-
};
|
|
82
|
+
});
|
|
68
83
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
|
|
85
|
+
// ../files/src/remoteBody.ts
|
|
86
|
+
function remoteBody(url, options = {}) {
|
|
87
|
+
const externalSignal = options.signal;
|
|
88
|
+
const timeoutMs = options.stallTimeoutMs && options.stallTimeoutMs > 0 ? options.stallTimeoutMs : 0;
|
|
89
|
+
const controller = new AbortController;
|
|
90
|
+
let reader = null;
|
|
91
|
+
let timer;
|
|
92
|
+
let onExternalAbort;
|
|
93
|
+
const clearTimer = () => {
|
|
94
|
+
if (timer !== undefined) {
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
timer = undefined;
|
|
75
97
|
}
|
|
76
98
|
};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
const cleanup = () => {
|
|
100
|
+
clearTimer();
|
|
101
|
+
if (externalSignal && onExternalAbort) {
|
|
102
|
+
externalSignal.removeEventListener("abort", onExternalAbort);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
if (externalSignal) {
|
|
106
|
+
if (externalSignal.aborted) {
|
|
107
|
+
controller.abort(externalSignal.reason);
|
|
108
|
+
} else {
|
|
109
|
+
onExternalAbort = () => controller.abort(externalSignal.reason);
|
|
110
|
+
externalSignal.addEventListener("abort", onExternalAbort, {
|
|
111
|
+
once: true
|
|
112
|
+
});
|
|
113
|
+
}
|
|
91
114
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return resolve(value, (resolvedValue) => typeof resolvedValue === "undefined" ? fallback : resolvedValue);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
class AbortMapData extends Error {
|
|
99
|
-
}
|
|
100
|
-
function mapData(data, visitors) {
|
|
101
|
-
let aborted = false;
|
|
102
|
-
const traverseData = (data2, path) => {
|
|
103
|
-
if (aborted) {
|
|
104
|
-
return data2;
|
|
115
|
+
const armTimer = () => {
|
|
116
|
+
if (timeoutMs <= 0) {
|
|
117
|
+
return;
|
|
105
118
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
clearTimer();
|
|
120
|
+
timer = setTimeout(() => {
|
|
121
|
+
controller.abort(new Error(`remote read stalled: no data for ${timeoutMs}ms`));
|
|
122
|
+
}, timeoutMs);
|
|
123
|
+
};
|
|
124
|
+
return new ReadableStream({
|
|
125
|
+
async start(streamController) {
|
|
126
|
+
let response;
|
|
127
|
+
try {
|
|
128
|
+
response = await fetch(url, {
|
|
129
|
+
signal: controller.signal,
|
|
130
|
+
headers: options.framed ? { [STREAM_PROTOCOL_HEADER]: STREAM_PROTOCOL_FRAMED } : undefined
|
|
117
131
|
});
|
|
132
|
+
} catch (error) {
|
|
133
|
+
cleanup();
|
|
134
|
+
streamController.error(error);
|
|
135
|
+
return;
|
|
118
136
|
}
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return
|
|
124
|
-
}
|
|
125
|
-
if (typeof data2 === "string") {
|
|
126
|
-
return notUndefined(visitors.String?.(data2, path), data2);
|
|
127
|
-
}
|
|
128
|
-
if (typeof data2 === "number") {
|
|
129
|
-
return notUndefined(visitors.Number?.(data2, path), data2);
|
|
130
|
-
}
|
|
131
|
-
if (typeof data2 === "symbol") {
|
|
132
|
-
return notUndefined(visitors.Symbol?.(data2, path), data2);
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
await response.body?.cancel();
|
|
139
|
+
cleanup();
|
|
140
|
+
streamController.error(new Error(`remote read failed: ${response.status} ${response.statusText}`));
|
|
141
|
+
return;
|
|
133
142
|
}
|
|
134
|
-
if (
|
|
135
|
-
|
|
143
|
+
if (!response.body) {
|
|
144
|
+
cleanup();
|
|
145
|
+
streamController.error(new Error("remote read response has no body"));
|
|
146
|
+
return;
|
|
136
147
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const entries = Object.entries(nextData).map(([key, value]) => [
|
|
144
|
-
key,
|
|
145
|
-
traverseData(value, [...path, key])
|
|
146
|
-
]);
|
|
147
|
-
if (entries.some(([, value]) => value instanceof Promise)) {
|
|
148
|
-
return Promise.all(entries.map(([key, value]) => Promise.resolve().then(() => value).then((resolvedValue) => [key, resolvedValue]))).then((entries2) => Object.fromEntries(entries2));
|
|
149
|
-
}
|
|
150
|
-
return Object.fromEntries(entries);
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
if (typeof data2 === "object" && data2) {
|
|
154
|
-
return notUndefined(visitors.Object?.(data2, path), data2);
|
|
148
|
+
const framed = options.framed && response.headers.get(STREAM_PROTOCOL_HEADER) === STREAM_PROTOCOL_FRAMED;
|
|
149
|
+
reader = framed ? response.body.pipeThrough(createFrameDecoder()).getReader() : response.body.getReader();
|
|
150
|
+
},
|
|
151
|
+
async pull(streamController) {
|
|
152
|
+
if (!reader) {
|
|
153
|
+
return;
|
|
155
154
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
armTimer();
|
|
156
|
+
try {
|
|
157
|
+
const { done, value } = await reader.read();
|
|
158
|
+
clearTimer();
|
|
159
|
+
if (done) {
|
|
160
|
+
cleanup();
|
|
161
|
+
streamController.close();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
streamController.enqueue(value);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
clearTimer();
|
|
167
|
+
cleanup();
|
|
168
|
+
streamController.error(error);
|
|
161
169
|
}
|
|
162
|
-
|
|
170
|
+
},
|
|
171
|
+
async cancel(reason) {
|
|
172
|
+
cleanup();
|
|
173
|
+
controller.abort(reason);
|
|
174
|
+
await reader?.cancel(reason);
|
|
163
175
|
}
|
|
164
|
-
};
|
|
165
|
-
return traverseData(data, []);
|
|
166
|
-
}
|
|
167
|
-
mapData.abort = () => {
|
|
168
|
-
throw new AbortMapData;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// ../helpers/src/utils/requenceCallback.ts
|
|
172
|
-
import { z as z2 } from "zod/v4";
|
|
173
|
-
var callbackObjectSchema = z2.object({
|
|
174
|
-
sourceId: z2.string(),
|
|
175
|
-
outputName: z2.string().nullable(),
|
|
176
|
-
propertyPath: z2.array(z2.union([z2.string(), z2.int()])),
|
|
177
|
-
callbackId: z2.uuid(),
|
|
178
|
-
__REQUENCE_type: z2.literal("RequenceCallback")
|
|
179
|
-
});
|
|
180
|
-
function isCallbackObject(data) {
|
|
181
|
-
return callbackObjectSchema.safeParse(data).success;
|
|
176
|
+
});
|
|
182
177
|
}
|
|
183
178
|
|
|
184
|
-
// ../
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
mime: z3.string(),
|
|
189
|
-
url: z3.url(),
|
|
190
|
-
__REQUENCE_type: z3.literal("RequenceFile")
|
|
191
|
-
});
|
|
192
|
-
function toFileObject(fileInfo) {
|
|
193
|
-
return {
|
|
194
|
-
...fileInfo,
|
|
195
|
-
__REQUENCE_type: "RequenceFile"
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
function isFileObject(data) {
|
|
199
|
-
return fileObjectSchema.safeParse(data).success;
|
|
179
|
+
// ../files/src/RequenceFile.ts
|
|
180
|
+
function stallTimeoutMs() {
|
|
181
|
+
const raw = typeof process !== "undefined" ? Number(process.env?.REQUENCE_FILE_STALL_TIMEOUT_MS) : Number.NaN;
|
|
182
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 0;
|
|
200
183
|
}
|
|
201
184
|
|
|
202
|
-
// ../helpers/src/files/RequenceFile.ts
|
|
203
185
|
class RequenceFile {
|
|
204
186
|
#data;
|
|
205
187
|
#file = null;
|
|
188
|
+
#signal;
|
|
206
189
|
constructor(blobParts, options) {
|
|
207
190
|
this.#data = new Blob(blobParts, options);
|
|
208
191
|
}
|
|
209
|
-
static fromFileObject(file) {
|
|
192
|
+
static fromFileObject(file, signal) {
|
|
210
193
|
const instance = new this([], { type: "x/x" });
|
|
211
194
|
instance.#file = file;
|
|
195
|
+
instance.#signal = signal;
|
|
212
196
|
return instance;
|
|
213
197
|
}
|
|
198
|
+
static canHandle(value) {
|
|
199
|
+
return value instanceof RequenceFile || value instanceof Blob;
|
|
200
|
+
}
|
|
214
201
|
get fileObject() {
|
|
215
202
|
return this.#file;
|
|
216
203
|
}
|
|
@@ -226,39 +213,74 @@ class RequenceFile {
|
|
|
226
213
|
get subMimeType() {
|
|
227
214
|
return this.mimeType.split("/")[1];
|
|
228
215
|
}
|
|
216
|
+
stream() {
|
|
217
|
+
if (!this.#file) {
|
|
218
|
+
return this.#data.stream();
|
|
219
|
+
}
|
|
220
|
+
return remoteBody(this.#file.url, {
|
|
221
|
+
signal: this.#signal,
|
|
222
|
+
stallTimeoutMs: stallTimeoutMs()
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
async#bytes() {
|
|
226
|
+
const reader = this.stream().getReader();
|
|
227
|
+
const chunks = [];
|
|
228
|
+
let total = 0;
|
|
229
|
+
for (;; ) {
|
|
230
|
+
const { done, value } = await reader.read();
|
|
231
|
+
if (done) {
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
chunks.push(value);
|
|
235
|
+
total += value.byteLength;
|
|
236
|
+
}
|
|
237
|
+
const out = new Uint8Array(total);
|
|
238
|
+
let offset = 0;
|
|
239
|
+
for (const chunk of chunks) {
|
|
240
|
+
out.set(chunk, offset);
|
|
241
|
+
offset += chunk.byteLength;
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
229
245
|
async text() {
|
|
230
246
|
if (this.#file) {
|
|
231
|
-
return
|
|
247
|
+
return new TextDecoder().decode(await this.#bytes());
|
|
232
248
|
}
|
|
233
249
|
return this.#data.text();
|
|
234
250
|
}
|
|
235
251
|
async json() {
|
|
236
252
|
if (this.#file) {
|
|
237
|
-
|
|
253
|
+
const text = await this.text();
|
|
254
|
+
try {
|
|
255
|
+
return JSON.parse(text);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
throw new Error(`RequenceFile JSON parse failed for ${this.#file.url}`, { cause: error });
|
|
258
|
+
}
|
|
238
259
|
}
|
|
239
260
|
return JSON.parse(await this.text());
|
|
240
261
|
}
|
|
241
262
|
async blob() {
|
|
242
263
|
if (this.#file) {
|
|
243
|
-
return
|
|
264
|
+
return new Blob([await this.#bytes()], { type: this.#file.mime });
|
|
244
265
|
}
|
|
245
266
|
return this.#data;
|
|
246
267
|
}
|
|
247
268
|
async arrayBuffer() {
|
|
248
269
|
if (this.#file) {
|
|
249
|
-
return
|
|
270
|
+
return (await this.#bytes()).buffer;
|
|
250
271
|
}
|
|
251
272
|
return this.#data.arrayBuffer();
|
|
252
273
|
}
|
|
253
274
|
toString() {
|
|
254
275
|
return `RequenceFile<${this.mimeType}>`;
|
|
255
276
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
277
|
+
}
|
|
278
|
+
// ../files/src/RequenceStream.ts
|
|
279
|
+
function stallTimeoutMs2() {
|
|
280
|
+
const raw = typeof process !== "undefined" ? Number(process.env?.REQUENCE_STREAM_STALL_TIMEOUT_MS) : Number.NaN;
|
|
281
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 0;
|
|
259
282
|
}
|
|
260
283
|
|
|
261
|
-
// ../helpers/src/files/RequenceStream.ts
|
|
262
284
|
class RequenceStream {
|
|
263
285
|
#data;
|
|
264
286
|
#stream = null;
|
|
@@ -267,13 +289,17 @@ class RequenceStream {
|
|
|
267
289
|
this.#data = stream;
|
|
268
290
|
this.#options = options;
|
|
269
291
|
}
|
|
270
|
-
static fromStreamObject(stream) {
|
|
292
|
+
static fromStreamObject(stream, signal) {
|
|
271
293
|
const instance = new this(null, {
|
|
272
|
-
type: "x/x"
|
|
294
|
+
type: "x/x",
|
|
295
|
+
signal
|
|
273
296
|
});
|
|
274
297
|
instance.#stream = stream;
|
|
275
298
|
return instance;
|
|
276
299
|
}
|
|
300
|
+
static canHandle(value) {
|
|
301
|
+
return value instanceof RequenceStream || value instanceof Response;
|
|
302
|
+
}
|
|
277
303
|
get streamObject() {
|
|
278
304
|
return this.#stream;
|
|
279
305
|
}
|
|
@@ -287,12 +313,14 @@ class RequenceStream {
|
|
|
287
313
|
return this.mimeType.split("/")[1];
|
|
288
314
|
}
|
|
289
315
|
stream() {
|
|
290
|
-
if (this.#stream) {
|
|
291
|
-
|
|
292
|
-
fetch(this.#stream.url).then((response) => response.body?.pipeTo(writable));
|
|
293
|
-
return readable;
|
|
316
|
+
if (!this.#stream) {
|
|
317
|
+
return this.#data;
|
|
294
318
|
}
|
|
295
|
-
return this.#
|
|
319
|
+
return remoteBody(this.#stream.url, {
|
|
320
|
+
signal: this.#options.signal,
|
|
321
|
+
stallTimeoutMs: stallTimeoutMs2(),
|
|
322
|
+
framed: true
|
|
323
|
+
});
|
|
296
324
|
}
|
|
297
325
|
asyncIterable() {
|
|
298
326
|
const reader = this.stream().getReader();
|
|
@@ -306,6 +334,11 @@ class RequenceStream {
|
|
|
306
334
|
reader.cancel();
|
|
307
335
|
reader.releaseLock();
|
|
308
336
|
return { done: true, value: null };
|
|
337
|
+
},
|
|
338
|
+
async throw() {
|
|
339
|
+
reader.cancel();
|
|
340
|
+
reader.releaseLock();
|
|
341
|
+
return { done: true, value: null };
|
|
309
342
|
}
|
|
310
343
|
};
|
|
311
344
|
}
|
|
@@ -314,17 +347,105 @@ class RequenceStream {
|
|
|
314
347
|
toString() {
|
|
315
348
|
return `RequenceStream<${this.mimeType}>`;
|
|
316
349
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
350
|
+
}
|
|
351
|
+
// ../helpers/src/utils/callbackToAsyncIterator.ts
|
|
352
|
+
function callbackToAsyncIterator(subscribe) {
|
|
353
|
+
const pullQueue = [];
|
|
354
|
+
const pushQueue = [];
|
|
355
|
+
let done = false;
|
|
356
|
+
const pushValue = (value) => {
|
|
357
|
+
if (pullQueue.length !== 0) {
|
|
358
|
+
const resolver = pullQueue.shift();
|
|
359
|
+
resolver(value);
|
|
360
|
+
} else {
|
|
361
|
+
pushQueue.push(value);
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
const pullValue = () => new Promise((resolve) => {
|
|
365
|
+
if (pushQueue.length !== 0) {
|
|
366
|
+
resolve(pushQueue.shift());
|
|
367
|
+
} else {
|
|
368
|
+
pullQueue.push(resolve);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
const cleanup = subscribe((value) => {
|
|
372
|
+
if (!done) {
|
|
373
|
+
pushValue({ value });
|
|
374
|
+
}
|
|
375
|
+
}, (error) => {
|
|
376
|
+
if (!done) {
|
|
377
|
+
pushValue({ error });
|
|
378
|
+
}
|
|
379
|
+
}, () => {
|
|
380
|
+
if (!done) {
|
|
381
|
+
pushValue({ done: true });
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
return {
|
|
385
|
+
async next() {
|
|
386
|
+
if (done) {
|
|
387
|
+
return { value: undefined, done: true };
|
|
388
|
+
}
|
|
389
|
+
const value = await pullValue();
|
|
390
|
+
if (value.done) {
|
|
391
|
+
done = true;
|
|
392
|
+
return { value: undefined, done: true };
|
|
393
|
+
}
|
|
394
|
+
if (value.error) {
|
|
395
|
+
done = true;
|
|
396
|
+
throw value.error;
|
|
397
|
+
}
|
|
398
|
+
return { value: value.value, done: false };
|
|
399
|
+
},
|
|
400
|
+
async return() {
|
|
401
|
+
if (!done) {
|
|
402
|
+
done = true;
|
|
403
|
+
if (typeof cleanup === "function") {
|
|
404
|
+
cleanup();
|
|
405
|
+
}
|
|
406
|
+
while (pullQueue.length > 0) {
|
|
407
|
+
const resolver = pullQueue.shift();
|
|
408
|
+
resolver({ done: true });
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return { value: undefined, done: true };
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
function callbackToAsyncIterable(...args) {
|
|
416
|
+
let iterator;
|
|
417
|
+
return {
|
|
418
|
+
[Symbol.asyncIterator]() {
|
|
419
|
+
iterator ??= callbackToAsyncIterator(...args);
|
|
420
|
+
return iterator;
|
|
421
|
+
}
|
|
422
|
+
};
|
|
320
423
|
}
|
|
321
424
|
|
|
322
|
-
// ../helpers/src/
|
|
323
|
-
import { z
|
|
324
|
-
var
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
425
|
+
// ../helpers/src/utils/fileObject.ts
|
|
426
|
+
import { z } from "zod/v4";
|
|
427
|
+
var fileObjectSchema = z.object({
|
|
428
|
+
size: z.int().positive(),
|
|
429
|
+
mime: z.string(),
|
|
430
|
+
url: z.url(),
|
|
431
|
+
__REQUENCE_type: z.literal("RequenceFile")
|
|
432
|
+
});
|
|
433
|
+
function toFileObject(fileInfo) {
|
|
434
|
+
return {
|
|
435
|
+
...fileInfo,
|
|
436
|
+
__REQUENCE_type: "RequenceFile"
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function isFileObject(data) {
|
|
440
|
+
return fileObjectSchema.safeParse(data).success;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// ../helpers/src/utils/streamObject.ts
|
|
444
|
+
import { z as z2 } from "zod/v4";
|
|
445
|
+
var streamObjectSchema = z2.object({
|
|
446
|
+
mime: z2.string(),
|
|
447
|
+
url: z2.string().url(),
|
|
448
|
+
__REQUENCE_type: z2.literal("RequenceStream")
|
|
328
449
|
});
|
|
329
450
|
function isStreamObject(data) {
|
|
330
451
|
return streamObjectSchema.safeParse(data).success;
|
|
@@ -336,131 +457,292 @@ function toStreamObject(streamInfo) {
|
|
|
336
457
|
};
|
|
337
458
|
}
|
|
338
459
|
|
|
339
|
-
// ../helpers/src/
|
|
340
|
-
|
|
341
|
-
|
|
460
|
+
// ../helpers/src/utils/claimCheckObject.ts
|
|
461
|
+
import { z as z3 } from "zod/v4";
|
|
462
|
+
var claimCheckObjectSchema = z3.object({
|
|
463
|
+
url: z3.url(),
|
|
464
|
+
size: z3.int().positive(),
|
|
465
|
+
__REQUENCE_type: z3.literal("ClaimCheck")
|
|
466
|
+
});
|
|
467
|
+
function toClaimCheckObject(info) {
|
|
468
|
+
return {
|
|
469
|
+
...info,
|
|
470
|
+
__REQUENCE_type: "ClaimCheck"
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function isClaimCheckObject(data) {
|
|
474
|
+
return claimCheckObjectSchema.safeParse(data).success;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// ../helpers/src/utils/requenceCallback.ts
|
|
478
|
+
import { z as z4 } from "zod/v4";
|
|
479
|
+
var callbackObjectSchema = z4.object({
|
|
480
|
+
sourceId: z4.string(),
|
|
481
|
+
outputName: z4.string().nullable(),
|
|
482
|
+
propertyPath: z4.array(z4.union([z4.string(), z4.int()])),
|
|
483
|
+
callbackId: z4.uuid(),
|
|
484
|
+
__REQUENCE_type: z4.literal("RequenceCallback")
|
|
485
|
+
});
|
|
486
|
+
function isCallbackObject(data) {
|
|
487
|
+
return callbackObjectSchema.safeParse(data).success;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// ../files/src/handlers/transport.ts
|
|
491
|
+
async function assertOk(res, url, phase) {
|
|
492
|
+
if (res.ok) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
const detail = await res.text().catch(() => "");
|
|
496
|
+
throw new Error(`${phase} failed: ${res.status} ${res.statusText} (${url})${detail ? ` — ${detail}` : ""}`);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ../files/src/handlers/fileHandler.ts
|
|
500
|
+
async function upload(ctx, uploadUrl, body, contentType, maxFileSize) {
|
|
501
|
+
const uploadResponse = await ctx.fetch(uploadUrl, {
|
|
342
502
|
method: "POST",
|
|
343
|
-
signal,
|
|
344
|
-
headers:
|
|
345
|
-
"Content-Type": contentType
|
|
346
|
-
|
|
503
|
+
signal: ctx.signal,
|
|
504
|
+
headers: {
|
|
505
|
+
...contentType ? { "Content-Type": contentType } : {},
|
|
506
|
+
...maxFileSize !== undefined ? { "file-size": String(maxFileSize) } : {}
|
|
507
|
+
},
|
|
347
508
|
body
|
|
348
509
|
});
|
|
510
|
+
await assertOk(uploadResponse, uploadUrl, "upload");
|
|
349
511
|
const data = await uploadResponse.json();
|
|
350
|
-
if (!data || typeof data !== "object") {
|
|
351
|
-
throw new Error(
|
|
512
|
+
if (!data || typeof data !== "object" || typeof data.url !== "string" || !data.url || typeof data.mime !== "string" || typeof data.size !== "number") {
|
|
513
|
+
throw new Error(`malformed upload response (${uploadUrl})`);
|
|
352
514
|
}
|
|
353
515
|
return toFileObject(data);
|
|
354
516
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
517
|
+
function createRequenceFileHandler() {
|
|
518
|
+
return {
|
|
519
|
+
tag: "RequenceFile",
|
|
520
|
+
canHandle: (value) => RequenceFile.canHandle(value),
|
|
521
|
+
async serialize(value, ctx) {
|
|
522
|
+
if (value instanceof RequenceFile && value.fileObject) {
|
|
523
|
+
return value.fileObject;
|
|
524
|
+
}
|
|
525
|
+
if (!ctx.uploadUrl) {
|
|
526
|
+
ctx.onOffloadSkip?.();
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
if (value instanceof RequenceFile) {
|
|
531
|
+
return await upload(ctx, ctx.uploadUrl, await value.blob(), value.mimeType, ctx.maxFileSize);
|
|
532
|
+
}
|
|
533
|
+
return await upload(ctx, ctx.uploadUrl, value, value.type, ctx.maxFileSize);
|
|
534
|
+
} catch (error) {
|
|
535
|
+
if (!(error instanceof Error)) {
|
|
536
|
+
throw error;
|
|
537
|
+
}
|
|
538
|
+
if (ctx.onOffloadFail) {
|
|
539
|
+
ctx.onOffloadFail(error);
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
throw error;
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
isReference: (value) => isFileObject(value),
|
|
546
|
+
deserialize(ref, ctx) {
|
|
547
|
+
return RequenceFile.fromFileObject(ref, ctx.signal);
|
|
361
548
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
// ../files/src/withRequenceStreams.ts
|
|
552
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
553
|
+
var pendingUploads = new AsyncLocalStorage;
|
|
554
|
+
async function withRequenceStreams(fn) {
|
|
555
|
+
const uploads = [];
|
|
556
|
+
const value = await pendingUploads.run(uploads, fn);
|
|
557
|
+
return { value, done: Promise.all(uploads).then(() => {
|
|
558
|
+
return;
|
|
559
|
+
}) };
|
|
560
|
+
}
|
|
561
|
+
function registerPendingUpload(work) {
|
|
562
|
+
const store = pendingUploads.getStore();
|
|
563
|
+
if (!store) {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
store.push(work);
|
|
567
|
+
return true;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// ../files/src/handlers/streamHandler.ts
|
|
571
|
+
async function registerAndUpload(ctx, streamUrl, stream, contentType, maxFileSize) {
|
|
572
|
+
const [testStream, dataStream] = stream.tee();
|
|
573
|
+
const reader = testStream.getReader();
|
|
574
|
+
const { done: isEmpty } = await reader.read();
|
|
575
|
+
reader.cancel();
|
|
576
|
+
const streamResponse = await ctx.fetch(streamUrl, {
|
|
365
577
|
method: "POST",
|
|
366
|
-
signal,
|
|
367
|
-
headers:
|
|
578
|
+
signal: ctx.signal,
|
|
579
|
+
headers: {
|
|
580
|
+
...contentType ? { "Content-Type": contentType } : {},
|
|
581
|
+
...maxFileSize !== undefined ? { "file-size": String(maxFileSize) } : {}
|
|
582
|
+
}
|
|
368
583
|
});
|
|
584
|
+
await assertOk(streamResponse, streamUrl, "stream registration");
|
|
369
585
|
const data = await streamResponse.json();
|
|
370
|
-
if (!data
|
|
371
|
-
throw new Error(
|
|
586
|
+
if (!isStreamObject(toStreamObject(data))) {
|
|
587
|
+
throw new Error(`malformed stream registration response (${streamUrl})`);
|
|
372
588
|
}
|
|
373
589
|
const { mime, url } = data;
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
590
|
+
if (isEmpty) {
|
|
591
|
+
const emptyResponse = await ctx.fetch(url, {
|
|
592
|
+
method: "POST",
|
|
593
|
+
signal: ctx.signal,
|
|
594
|
+
headers: contentType ? { "Content-Type": contentType } : {},
|
|
595
|
+
body: new Uint8Array(0)
|
|
596
|
+
});
|
|
597
|
+
await assertOk(emptyResponse, url, "stream body upload");
|
|
598
|
+
await emptyResponse.body?.cancel();
|
|
599
|
+
return { ref: toStreamObject({ mime, url }) };
|
|
600
|
+
}
|
|
601
|
+
const bodyUpload = (async () => {
|
|
602
|
+
const bodyResponse = await ctx.fetch(url, {
|
|
603
|
+
method: "POST",
|
|
604
|
+
signal: ctx.signal,
|
|
605
|
+
duplex: "half",
|
|
606
|
+
body: dataStream
|
|
607
|
+
});
|
|
608
|
+
await assertOk(bodyResponse, url, "stream body upload");
|
|
609
|
+
await bodyResponse.body?.cancel();
|
|
610
|
+
})();
|
|
611
|
+
return { ref: toStreamObject({ mime, url }), bodyUpload };
|
|
382
612
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
if (params.options.uploadUrl) {
|
|
392
|
-
try {
|
|
393
|
-
if (obj instanceof Blob) {
|
|
394
|
-
return await upload(params.options.uploadUrl, obj, params.signal, obj.type);
|
|
395
|
-
}
|
|
396
|
-
if (obj instanceof RequenceFile) {
|
|
397
|
-
return await upload(params.options.uploadUrl, await obj.blob(), params.signal, obj.mimeType);
|
|
398
|
-
}
|
|
399
|
-
} catch (error) {
|
|
400
|
-
if (!(error instanceof Error)) {
|
|
401
|
-
throw error;
|
|
402
|
-
}
|
|
403
|
-
params.onFail?.(error);
|
|
404
|
-
return null;
|
|
405
|
-
}
|
|
406
|
-
} else {
|
|
407
|
-
params.onSkip?.();
|
|
408
|
-
return null;
|
|
409
|
-
}
|
|
613
|
+
function createRequenceStreamHandler() {
|
|
614
|
+
return {
|
|
615
|
+
tag: "RequenceStream",
|
|
616
|
+
canHandle: (value) => RequenceStream.canHandle(value),
|
|
617
|
+
async serialize(value, ctx) {
|
|
618
|
+
if (value instanceof RequenceStream && value.streamObject) {
|
|
619
|
+
return value.streamObject;
|
|
410
620
|
}
|
|
411
|
-
if (
|
|
412
|
-
|
|
413
|
-
|
|
621
|
+
if (!ctx.streamUrl) {
|
|
622
|
+
ctx.onOffloadSkip?.();
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
const body = value instanceof Response ? value.body ?? new ReadableStream({
|
|
626
|
+
start(controller) {
|
|
627
|
+
controller.close();
|
|
414
628
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
throw error;
|
|
430
|
-
}
|
|
431
|
-
params.onFail?.(error);
|
|
432
|
-
return null;
|
|
433
|
-
}
|
|
434
|
-
} else {
|
|
435
|
-
params.onSkip?.();
|
|
629
|
+
}) : value.stream();
|
|
630
|
+
const contentType = value instanceof Response ? value.headers.get("Content-Type") : value.mimeType;
|
|
631
|
+
try {
|
|
632
|
+
const { ref, bodyUpload } = await registerAndUpload(ctx, ctx.streamUrl, body, contentType, ctx.maxFileSize);
|
|
633
|
+
if (bodyUpload && !registerPendingUpload(bodyUpload)) {
|
|
634
|
+
await bodyUpload;
|
|
635
|
+
}
|
|
636
|
+
return ref;
|
|
637
|
+
} catch (error) {
|
|
638
|
+
if (!(error instanceof Error)) {
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
641
|
+
if (ctx.onOffloadFail) {
|
|
642
|
+
ctx.onOffloadFail(error);
|
|
436
643
|
return null;
|
|
437
644
|
}
|
|
645
|
+
throw error;
|
|
438
646
|
}
|
|
647
|
+
},
|
|
648
|
+
isReference: (value) => isStreamObject(value),
|
|
649
|
+
deserialize(ref, ctx) {
|
|
650
|
+
return RequenceStream.fromStreamObject(ref, ctx.signal);
|
|
439
651
|
}
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
// ../files/src/handlers/claimCheckHandler.ts
|
|
655
|
+
import { Buffer } from "node:buffer";
|
|
656
|
+
var DEFAULT_MAX_PAYLOAD_SIZE = 4 * 1024 * 1024;
|
|
657
|
+
function isRecord(value) {
|
|
658
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
659
|
+
}
|
|
660
|
+
async function offload(ctx, uploadUrl, json) {
|
|
661
|
+
const response = await ctx.fetch(uploadUrl, {
|
|
662
|
+
method: "POST",
|
|
663
|
+
signal: ctx.signal,
|
|
664
|
+
headers: { "Content-Type": "application/json" },
|
|
665
|
+
body: json
|
|
440
666
|
});
|
|
441
|
-
|
|
442
|
-
|
|
667
|
+
await assertOk(response, uploadUrl, "claim-check offload");
|
|
668
|
+
const data = await response.json();
|
|
669
|
+
if (!data || typeof data !== "object" || typeof data.url !== "string" || !data.url || typeof data.size !== "number") {
|
|
670
|
+
throw new Error(`malformed claim-check offload response (${uploadUrl})`);
|
|
671
|
+
}
|
|
672
|
+
return toClaimCheckObject({ url: data.url, size: data.size });
|
|
443
673
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
674
|
+
function jsonByteLength(value) {
|
|
675
|
+
const json = JSON.stringify(value);
|
|
676
|
+
return json === undefined ? 0 : Buffer.byteLength(json);
|
|
677
|
+
}
|
|
678
|
+
function createMessageHandler() {
|
|
679
|
+
return {
|
|
680
|
+
async wrapOutbound(body, ctx) {
|
|
681
|
+
const maxBytes = ctx.maxPayloadSize ?? DEFAULT_MAX_PAYLOAD_SIZE;
|
|
682
|
+
if (maxBytes <= 0 || body === undefined) {
|
|
683
|
+
return body;
|
|
451
684
|
}
|
|
452
|
-
|
|
453
|
-
|
|
685
|
+
const measure = ctx.measure ?? jsonByteLength;
|
|
686
|
+
if (measure(body) <= maxBytes) {
|
|
687
|
+
return body;
|
|
454
688
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
689
|
+
const { uploadUrl } = ctx;
|
|
690
|
+
if (!uploadUrl) {
|
|
691
|
+
ctx.onOffloadSkip?.();
|
|
692
|
+
return body;
|
|
693
|
+
}
|
|
694
|
+
if (!isRecord(body)) {
|
|
695
|
+
const json = JSON.stringify(body);
|
|
696
|
+
if (json === undefined) {
|
|
697
|
+
return body;
|
|
698
|
+
}
|
|
699
|
+
return offload(ctx, uploadUrl, json);
|
|
700
|
+
}
|
|
701
|
+
const entries = Object.entries(body).map(([key, value]) => ({
|
|
702
|
+
key,
|
|
703
|
+
valueJson: JSON.stringify(value),
|
|
704
|
+
size: measure(value)
|
|
705
|
+
})).sort((a, b) => b.size - a.size);
|
|
706
|
+
const wrapped = { ...body };
|
|
707
|
+
let total = measure(body);
|
|
708
|
+
for (const entry of entries) {
|
|
709
|
+
if (total <= maxBytes || entry.valueJson === undefined || entry.size <= 256) {
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
const ref = await offload(ctx, uploadUrl, entry.valueJson);
|
|
713
|
+
wrapped[entry.key] = ref;
|
|
714
|
+
total += measure(ref) - entry.size;
|
|
459
715
|
}
|
|
716
|
+
return wrapped;
|
|
460
717
|
}
|
|
461
|
-
}
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function createValueHandler() {
|
|
721
|
+
return {
|
|
722
|
+
tag: "ClaimCheck",
|
|
723
|
+
canHandle: () => false,
|
|
724
|
+
serialize() {
|
|
725
|
+
throw new Error("ClaimCheck egress is the bundled MessageHandler (wrapOutbound); it never reaches the value walk");
|
|
726
|
+
},
|
|
727
|
+
isReference: (value) => isClaimCheckObject(value),
|
|
728
|
+
async deserialize(ref, ctx) {
|
|
729
|
+
const response = await ctx.fetch(ref.url, { signal: ctx.signal });
|
|
730
|
+
await assertOk(response, ref.url, "claim-check fetch");
|
|
731
|
+
const text = await response.text();
|
|
732
|
+
try {
|
|
733
|
+
return JSON.parse(text);
|
|
734
|
+
} catch {
|
|
735
|
+
throw new Error(`malformed claim-check payload (${ref.url})`);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function createClaimCheckHandler() {
|
|
741
|
+
return {
|
|
742
|
+
valueHandler: createValueHandler(),
|
|
743
|
+
messageHandler: createMessageHandler()
|
|
744
|
+
};
|
|
462
745
|
}
|
|
463
|
-
|
|
464
746
|
// src/createTask.ts
|
|
465
747
|
import chalk from "chalk";
|
|
466
748
|
import { createEventSource } from "eventsource-client";
|
|
@@ -500,7 +782,7 @@ class TaskAbortError extends Error {
|
|
|
500
782
|
async function abortTask(options) {
|
|
501
783
|
const { apiBaseUrl, token } = getAccessToken(options.accessToken);
|
|
502
784
|
const abortUrl = `${apiBaseUrl}/task/abort/${options.taskId}`;
|
|
503
|
-
const response = await
|
|
785
|
+
const response = await reachableFetch(abortUrl, {
|
|
504
786
|
method: "POST",
|
|
505
787
|
body: options.reason ?? "",
|
|
506
788
|
headers: {
|
|
@@ -515,7 +797,7 @@ async function abortTask(options) {
|
|
|
515
797
|
// src/ackTask.ts
|
|
516
798
|
async function ackTask(options) {
|
|
517
799
|
const { apiBaseUrl, token } = getAccessToken(options.accessToken);
|
|
518
|
-
const response = await
|
|
800
|
+
const response = await reachableFetch(`${apiBaseUrl}/task/ack/${options.taskId}`, {
|
|
519
801
|
method: "POST",
|
|
520
802
|
headers: {
|
|
521
803
|
Authorization: `Bearer ${token}`
|
|
@@ -526,6 +808,214 @@ async function ackTask(options) {
|
|
|
526
808
|
}
|
|
527
809
|
}
|
|
528
810
|
|
|
811
|
+
// ../callbacks/src/handler.ts
|
|
812
|
+
function createRequenceCallbackHandler() {
|
|
813
|
+
return {
|
|
814
|
+
tag: "RequenceCallback",
|
|
815
|
+
canHandle: (value) => typeof value === "function",
|
|
816
|
+
serialize(callback, ctx, path) {
|
|
817
|
+
if (!ctx.onCallback) {
|
|
818
|
+
throw new Error(`functions are not serializable on this boundary (no ctx.onCallback) at path "${path.join(".")}"`);
|
|
819
|
+
}
|
|
820
|
+
return {
|
|
821
|
+
...ctx.onCallback(callback),
|
|
822
|
+
outputName: ctx.outputName ?? null,
|
|
823
|
+
propertyPath: [...path],
|
|
824
|
+
__REQUENCE_type: "RequenceCallback"
|
|
825
|
+
};
|
|
826
|
+
},
|
|
827
|
+
isReference: (value) => isCallbackObject(value),
|
|
828
|
+
deserialize(ref, ctx) {
|
|
829
|
+
return (arg) => {
|
|
830
|
+
ctx.onCallbackInvoke?.({ ...ref, arg });
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
// ../transformer/src/errors.ts
|
|
836
|
+
function formatPath(path) {
|
|
837
|
+
if (path.length === 0) {
|
|
838
|
+
return "<root>";
|
|
839
|
+
}
|
|
840
|
+
let out = "";
|
|
841
|
+
for (const segment of path) {
|
|
842
|
+
out += typeof segment === "number" ? `[${segment}]` : out ? `.${segment}` : segment;
|
|
843
|
+
}
|
|
844
|
+
return out;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
class TransformError extends Error {
|
|
848
|
+
path;
|
|
849
|
+
detail;
|
|
850
|
+
constructor(detail, path) {
|
|
851
|
+
super(`${detail} at ${formatPath(path)}`);
|
|
852
|
+
this.name = "TransformError";
|
|
853
|
+
this.path = path;
|
|
854
|
+
this.detail = detail;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// ../transformer/src/guards.ts
|
|
859
|
+
var REFERENCE_TAG_KEY = "__REQUENCE_type";
|
|
860
|
+
function isPlainObject(value) {
|
|
861
|
+
if (value === null || typeof value !== "object") {
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
const proto = Object.getPrototypeOf(value);
|
|
865
|
+
return proto === null || proto === Object.prototype;
|
|
866
|
+
}
|
|
867
|
+
function isComplexValue(value) {
|
|
868
|
+
if (value === null) {
|
|
869
|
+
return false;
|
|
870
|
+
}
|
|
871
|
+
const type = typeof value;
|
|
872
|
+
if (type === "object") {
|
|
873
|
+
return !Array.isArray(value) && !isPlainObject(value);
|
|
874
|
+
}
|
|
875
|
+
return type === "function" || type === "symbol" || type === "bigint";
|
|
876
|
+
}
|
|
877
|
+
function hasReferenceTag(value) {
|
|
878
|
+
return isPlainObject(value) && REFERENCE_TAG_KEY in value;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// ../transformer/src/walk.ts
|
|
882
|
+
var recurse = { kind: "recurse" };
|
|
883
|
+
var replaceWith = (value) => ({
|
|
884
|
+
kind: "replace",
|
|
885
|
+
value
|
|
886
|
+
});
|
|
887
|
+
var MAX_REPLACE_DEPTH = 100;
|
|
888
|
+
async function walk(root, visit) {
|
|
889
|
+
const go = async (value, path, replaceDepth) => {
|
|
890
|
+
let node = value;
|
|
891
|
+
if (Array.isArray(node)) {
|
|
892
|
+
node = await Promise.all(node.map((item, index) => go(item, [...path, index], 0)));
|
|
893
|
+
} else if (isPlainObject(node)) {
|
|
894
|
+
const entries = await Promise.all(Object.entries(node).map(async ([key, item]) => [key, await go(item, [...path, key], 0)]));
|
|
895
|
+
node = Object.fromEntries(entries);
|
|
896
|
+
}
|
|
897
|
+
const verdict = await visit(node, path);
|
|
898
|
+
if (verdict.kind === "replace") {
|
|
899
|
+
if (replaceDepth >= MAX_REPLACE_DEPTH) {
|
|
900
|
+
throw new TransformError("transform did not reach a fixpoint (a handler keeps producing handleable output)", path);
|
|
901
|
+
}
|
|
902
|
+
return go(verdict.value, path, replaceDepth + 1);
|
|
903
|
+
}
|
|
904
|
+
return node;
|
|
905
|
+
};
|
|
906
|
+
return go(root, [], 0);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// ../transformer/src/transform.ts
|
|
910
|
+
function createTransformer() {
|
|
911
|
+
return build([], []);
|
|
912
|
+
}
|
|
913
|
+
function build(valueHandlers, messageHandlers) {
|
|
914
|
+
const transformer = {
|
|
915
|
+
withHandler(handler) {
|
|
916
|
+
const bundle = "tag" in handler ? { valueHandler: handler } : handler;
|
|
917
|
+
if (!bundle.valueHandler && !bundle.messageHandler) {
|
|
918
|
+
throw new Error("withHandler: bundle provides neither a valueHandler nor a messageHandler");
|
|
919
|
+
}
|
|
920
|
+
if (bundle.valueHandler) {
|
|
921
|
+
const { tag } = bundle.valueHandler;
|
|
922
|
+
if (valueHandlers.some((existing) => existing.tag === tag)) {
|
|
923
|
+
throw new Error(`withHandler: a ValueHandler with tag "${tag}" is already composed`);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return build(bundle.valueHandler ? [...valueHandlers, bundle.valueHandler] : valueHandlers, bundle.messageHandler ? [...messageHandlers, bundle.messageHandler] : messageHandlers);
|
|
927
|
+
},
|
|
928
|
+
async outbound(value, ctx) {
|
|
929
|
+
const seen = new Map;
|
|
930
|
+
const visit = (node, path) => {
|
|
931
|
+
if (!isComplexValue(node)) {
|
|
932
|
+
return recurse;
|
|
933
|
+
}
|
|
934
|
+
const handler = valueHandlers.find((candidate) => candidate.canHandle(node));
|
|
935
|
+
if (!handler) {
|
|
936
|
+
const withToJSON = node;
|
|
937
|
+
if (typeof node === "object" && typeof withToJSON.toJSON === "function") {
|
|
938
|
+
return replaceWith(withToJSON.toJSON());
|
|
939
|
+
}
|
|
940
|
+
const label = node?.constructor?.name ?? (typeof node === "function" ? "function" : typeof node);
|
|
941
|
+
throw new TransformError(`no composed ValueHandler for complex value of type ${label}`, path);
|
|
942
|
+
}
|
|
943
|
+
if (typeof node === "object" && node !== null) {
|
|
944
|
+
const cached = seen.get(node);
|
|
945
|
+
if (cached) {
|
|
946
|
+
return cached.then(replaceWith);
|
|
947
|
+
}
|
|
948
|
+
const pending = Promise.resolve(handler.serialize(node, ctx, path));
|
|
949
|
+
seen.set(node, pending);
|
|
950
|
+
return pending.then(replaceWith);
|
|
951
|
+
}
|
|
952
|
+
return Promise.resolve(handler.serialize(node, ctx, path)).then(replaceWith);
|
|
953
|
+
};
|
|
954
|
+
const valueTransformed = await walk(value, visit);
|
|
955
|
+
let body = valueTransformed;
|
|
956
|
+
for (const [index, handler] of messageHandlers.entries()) {
|
|
957
|
+
const wrapped = await handler.wrapOutbound(body, ctx);
|
|
958
|
+
assertTopLevelKeysPreserved(body, wrapped, index);
|
|
959
|
+
body = wrapped;
|
|
960
|
+
}
|
|
961
|
+
return body;
|
|
962
|
+
},
|
|
963
|
+
async inbound(value, ctx) {
|
|
964
|
+
const visit = (node, path) => {
|
|
965
|
+
if (!isPlainObject(node)) {
|
|
966
|
+
return recurse;
|
|
967
|
+
}
|
|
968
|
+
const handler = valueHandlers.find((candidate) => candidate.isReference(node));
|
|
969
|
+
if (handler) {
|
|
970
|
+
if (handler.passthrough) {
|
|
971
|
+
return recurse;
|
|
972
|
+
}
|
|
973
|
+
return Promise.resolve(handler.deserialize(node, ctx, path)).then(replaceWith);
|
|
974
|
+
}
|
|
975
|
+
if (hasReferenceTag(node)) {
|
|
976
|
+
const tag = node.__REQUENCE_type;
|
|
977
|
+
throw new TransformError(`no composed ValueHandler owns reference tag ${JSON.stringify(tag)}`, path);
|
|
978
|
+
}
|
|
979
|
+
return recurse;
|
|
980
|
+
};
|
|
981
|
+
return walk(value, visit);
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
return transformer;
|
|
985
|
+
}
|
|
986
|
+
function assertTopLevelKeysPreserved(body, wrapped, handlerIndex) {
|
|
987
|
+
if (!isPlainObject(body)) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
const label = `MessageHandler #${handlerIndex}`;
|
|
991
|
+
if (!isPlainObject(wrapped)) {
|
|
992
|
+
throw new TransformError(`${label} replaced a record body wholesale — wrapOutbound must preserve a record's top-level keys`, []);
|
|
993
|
+
}
|
|
994
|
+
const before = Object.keys(body);
|
|
995
|
+
const after = new Set(Object.keys(wrapped));
|
|
996
|
+
const removed = before.filter((key) => !after.has(key));
|
|
997
|
+
const added = [...after].filter((key) => !before.includes(key));
|
|
998
|
+
if (removed.length > 0 || added.length > 0) {
|
|
999
|
+
throw new TransformError(`${label} changed a record body's top-level keys (removed: [${removed.join(", ")}], added: [${added.join(", ")}]) — wrapOutbound must preserve them`, []);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
// src/ingress.ts
|
|
1003
|
+
var transformer = createTransformer().withHandler(createRequenceFileHandler()).withHandler(createRequenceStreamHandler()).withHandler(createRequenceCallbackHandler()).withHandler(createClaimCheckHandler());
|
|
1004
|
+
var inbound = (data, opts = {}) => transformer.inbound(data, {
|
|
1005
|
+
fetch: globalThis.fetch,
|
|
1006
|
+
onCallbackInvoke: opts.onCallbackInvoke
|
|
1007
|
+
});
|
|
1008
|
+
var forbidCallbacks = {
|
|
1009
|
+
onCallbackInvoke: () => {
|
|
1010
|
+
throw new Error("input may not have callbacks");
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
var observeOnlyCallbacks = {
|
|
1014
|
+
onCallbackInvoke: () => {
|
|
1015
|
+
throw new Error("callbacks in watched data cannot be invoked from a task client");
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
|
|
529
1019
|
// src/protectTask.ts
|
|
530
1020
|
class TaskProtectError extends Error {
|
|
531
1021
|
taskId;
|
|
@@ -537,7 +1027,7 @@ class TaskProtectError extends Error {
|
|
|
537
1027
|
async function protectTask(options) {
|
|
538
1028
|
const { apiBaseUrl, token } = getAccessToken(options.accessToken);
|
|
539
1029
|
const protectUrl = `${apiBaseUrl}/task/protect/${options.taskId}`;
|
|
540
|
-
const response = await
|
|
1030
|
+
const response = await reachableFetch(protectUrl, {
|
|
541
1031
|
method: "POST",
|
|
542
1032
|
headers: {
|
|
543
1033
|
Authorization: `Bearer ${token}`
|
|
@@ -670,6 +1160,7 @@ function createTask(options, onUpdate) {
|
|
|
670
1160
|
let since = null;
|
|
671
1161
|
let lastPosition = null;
|
|
672
1162
|
let lastResponse;
|
|
1163
|
+
let processing = Promise.resolve();
|
|
673
1164
|
const customFetch = async (url, init) => {
|
|
674
1165
|
const response = await fetch(url, init);
|
|
675
1166
|
lastResponse = response;
|
|
@@ -695,8 +1186,13 @@ function createTask(options, onUpdate) {
|
|
|
695
1186
|
}
|
|
696
1187
|
},
|
|
697
1188
|
async onDisconnect() {
|
|
698
|
-
if (lastResponse
|
|
1189
|
+
if (lastResponse?.status === 200) {
|
|
699
1190
|
eventSource.close();
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
if (lastResponse && isUnreachableStatus(lastResponse.status)) {
|
|
1194
|
+
eventSource.close();
|
|
1195
|
+
resultPromiseWithResolvers.reject(new RequenceUnreachableError(lastResponse.status));
|
|
700
1196
|
}
|
|
701
1197
|
},
|
|
702
1198
|
onMessage({ id, event, data }) {
|
|
@@ -710,147 +1206,200 @@ function createTask(options, onUpdate) {
|
|
|
710
1206
|
return;
|
|
711
1207
|
}
|
|
712
1208
|
const update = updateResult.data;
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
taskStorage.errors[update.node.alias] = update.error;
|
|
729
|
-
}
|
|
730
|
-
break;
|
|
731
|
-
}
|
|
732
|
-
case "taskEnd": {
|
|
733
|
-
taskStorage.result = resolveRequenceTypes(update.result);
|
|
734
|
-
eventSource.close();
|
|
735
|
-
if (update.requireAck) {
|
|
736
|
-
ackTask({
|
|
737
|
-
taskId: payload.taskId,
|
|
738
|
-
accessToken: options.accessToken
|
|
739
|
-
}).catch(() => {});
|
|
740
|
-
}
|
|
741
|
-
break;
|
|
1209
|
+
processing = processing.then(() => applyUpdate(update)).catch((error) => {
|
|
1210
|
+
eventSource.close();
|
|
1211
|
+
resultPromiseWithResolvers.reject(new TaskError(error instanceof Error ? error.message : String(error), options.taskTemplate, payload.taskId));
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1215
|
+
async function applyUpdate(update) {
|
|
1216
|
+
switch (update.type) {
|
|
1217
|
+
case "taskStart": {
|
|
1218
|
+
taskStorage.input = await inbound(update.input, forbidCallbacks);
|
|
1219
|
+
break;
|
|
1220
|
+
}
|
|
1221
|
+
case "nodeUpdate": {
|
|
1222
|
+
if (update.node.alias) {
|
|
1223
|
+
taskStorage.data[update.node.alias] = await inbound(update.data, observeOnlyCallbacks);
|
|
742
1224
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
taskId: payload.taskId,
|
|
749
|
-
accessToken: options.accessToken
|
|
750
|
-
}).catch(() => {});
|
|
751
|
-
}
|
|
752
|
-
break;
|
|
1225
|
+
break;
|
|
1226
|
+
}
|
|
1227
|
+
case "nodeError": {
|
|
1228
|
+
if (update.node.alias) {
|
|
1229
|
+
taskStorage.errors[update.node.alias] = update.error;
|
|
753
1230
|
}
|
|
1231
|
+
break;
|
|
754
1232
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
};
|
|
766
|
-
const contextUpdate = {
|
|
767
|
-
...update,
|
|
768
|
-
context
|
|
769
|
-
};
|
|
770
|
-
if (contextUpdate.type === "taskEnd") {
|
|
771
|
-
resultPromiseWithResolvers.resolve({
|
|
772
|
-
...context,
|
|
773
|
-
taskUrl: payload.urls?.show ?? ""
|
|
774
|
-
});
|
|
1233
|
+
case "taskEnd": {
|
|
1234
|
+
taskStorage.result = await inbound(update.result, observeOnlyCallbacks);
|
|
1235
|
+
eventSource.close();
|
|
1236
|
+
if (update.requireAck) {
|
|
1237
|
+
ackTask({
|
|
1238
|
+
taskId: payload.taskId,
|
|
1239
|
+
accessToken: options.accessToken
|
|
1240
|
+
}).catch(() => {});
|
|
1241
|
+
}
|
|
1242
|
+
break;
|
|
775
1243
|
}
|
|
776
|
-
|
|
777
|
-
|
|
1244
|
+
case "taskError":
|
|
1245
|
+
case "taskAborted": {
|
|
1246
|
+
eventSource.close();
|
|
1247
|
+
if (update.requireAck) {
|
|
1248
|
+
ackTask({
|
|
1249
|
+
taskId: payload.taskId,
|
|
1250
|
+
accessToken: options.accessToken
|
|
1251
|
+
}).catch(() => {});
|
|
1252
|
+
}
|
|
1253
|
+
break;
|
|
778
1254
|
}
|
|
779
|
-
taskUpdateHandlers.forEach((handler) => handler(contextUpdate));
|
|
780
1255
|
}
|
|
781
|
-
|
|
1256
|
+
const context = {
|
|
1257
|
+
taskId: update.taskId,
|
|
1258
|
+
input: taskStorage.input,
|
|
1259
|
+
getNodeData(alias) {
|
|
1260
|
+
return taskStorage.data[alias] ?? null;
|
|
1261
|
+
},
|
|
1262
|
+
getNodeError(alias) {
|
|
1263
|
+
return taskStorage.errors[alias] ?? null;
|
|
1264
|
+
},
|
|
1265
|
+
result: taskStorage.result
|
|
1266
|
+
};
|
|
1267
|
+
const contextUpdate = {
|
|
1268
|
+
...update,
|
|
1269
|
+
context
|
|
1270
|
+
};
|
|
1271
|
+
if (contextUpdate.type === "taskEnd") {
|
|
1272
|
+
resultPromiseWithResolvers.resolve({
|
|
1273
|
+
...context,
|
|
1274
|
+
taskUrl: payload.urls?.show ?? ""
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
if (contextUpdate.type === "taskError" || contextUpdate.type === "taskAborted") {
|
|
1278
|
+
resultPromiseWithResolvers.reject(new TaskError(contextUpdate.reason ?? (contextUpdate.type === "taskError" ? "Task failed" : "Task aborted"), options.taskTemplate, payload.taskId));
|
|
1279
|
+
}
|
|
1280
|
+
taskUpdateHandlers.forEach((handler) => handler(contextUpdate));
|
|
1281
|
+
}
|
|
782
1282
|
};
|
|
783
1283
|
const taskIdPromiseWithResolvers = Promise.withResolvers();
|
|
1284
|
+
const preparedTaskIdPromiseWithResolvers = Promise.withResolvers();
|
|
1285
|
+
preparedTaskIdPromiseWithResolvers.promise.catch(() => {});
|
|
784
1286
|
const taskUrlPromiseWithResolvers = Promise.withResolvers();
|
|
785
1287
|
const resultPromiseWithResolvers = Promise.withResolvers();
|
|
786
|
-
const finalizedPromiseWithResolvers = Promise.withResolvers();
|
|
787
|
-
finalizedPromiseWithResolvers.promise.catch(() => {});
|
|
788
1288
|
let rejectTaskIdPromise = false;
|
|
789
1289
|
let rejectTaskUrlPromise = false;
|
|
790
1290
|
(async () => {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1291
|
+
try {
|
|
1292
|
+
const prepareResponse = await reachableFetch(prepareUrl, {
|
|
1293
|
+
method: "POST",
|
|
1294
|
+
headers: {
|
|
1295
|
+
Authorization: `Bearer ${token}`
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1298
|
+
if (!prepareResponse.ok) {
|
|
1299
|
+
const error = new TaskPrepareError(await prepareResponse.text(), options.taskTemplate);
|
|
1300
|
+
preparedTaskIdPromiseWithResolvers.reject(error);
|
|
1301
|
+
if (rejectTaskIdPromise) {
|
|
1302
|
+
taskIdPromiseWithResolvers.reject(error);
|
|
1303
|
+
}
|
|
1304
|
+
if (rejectTaskUrlPromise) {
|
|
1305
|
+
taskUrlPromiseWithResolvers.reject(error);
|
|
1306
|
+
}
|
|
1307
|
+
if (isMonitoring) {
|
|
1308
|
+
resultPromiseWithResolvers.reject(error);
|
|
1309
|
+
}
|
|
1310
|
+
return;
|
|
795
1311
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
finalizedPromiseWithResolvers.reject(error);
|
|
800
|
-
if (rejectTaskIdPromise) {
|
|
801
|
-
taskIdPromiseWithResolvers.reject(error);
|
|
1312
|
+
const prepareData = await prepareResponse.json();
|
|
1313
|
+
if (prepareData.branch !== "live" && !options.suppressBranchWarning) {
|
|
1314
|
+
console.warn(chalk.hex("#eab308")("task is executed in", chalk.bold(prepareData.branch), "branch"));
|
|
802
1315
|
}
|
|
803
|
-
|
|
804
|
-
|
|
1316
|
+
preparedTaskIdPromiseWithResolvers.resolve(prepareData.taskId);
|
|
1317
|
+
const streamDone = Promise.withResolvers();
|
|
1318
|
+
streamDone.promise.catch(() => {});
|
|
1319
|
+
let mappedParams;
|
|
1320
|
+
try {
|
|
1321
|
+
const { value, done } = await withRequenceStreams(() => transformer.outbound({
|
|
1322
|
+
name: options.name,
|
|
1323
|
+
input: options.input,
|
|
1324
|
+
priority,
|
|
1325
|
+
requireAck: options.requireAck ?? false
|
|
1326
|
+
}, {
|
|
1327
|
+
fetch: globalThis.fetch,
|
|
1328
|
+
uploadUrl: prepareData.fileUrls?.uploadUrl,
|
|
1329
|
+
streamUrl: prepareData.fileUrls?.streamUrl,
|
|
1330
|
+
maxPayloadSize: prepareData.limits?.maxPayloadSize,
|
|
1331
|
+
maxFileSize: prepareData.limits?.maxFileSize
|
|
1332
|
+
}));
|
|
1333
|
+
mappedParams = value;
|
|
1334
|
+
done.then(() => streamDone.resolve(), (error) => streamDone.reject(error instanceof Error ? error : new Error(String(error))));
|
|
1335
|
+
} catch (error) {
|
|
1336
|
+
const taskError = new TaskError(error instanceof Error ? error.message : String(error), options.taskTemplate, prepareData.taskId);
|
|
1337
|
+
if (rejectTaskIdPromise) {
|
|
1338
|
+
taskIdPromiseWithResolvers.reject(taskError);
|
|
1339
|
+
}
|
|
1340
|
+
if (rejectTaskUrlPromise) {
|
|
1341
|
+
taskUrlPromiseWithResolvers.reject(taskError);
|
|
1342
|
+
}
|
|
1343
|
+
if (isMonitoring) {
|
|
1344
|
+
resultPromiseWithResolvers.reject(taskError);
|
|
1345
|
+
}
|
|
1346
|
+
return;
|
|
805
1347
|
}
|
|
806
|
-
|
|
807
|
-
|
|
1348
|
+
const finalizeResponse = await reachableFetch(prepareData.finalizeUrl, {
|
|
1349
|
+
method: "POST",
|
|
1350
|
+
body: JSON.stringify(mappedParams),
|
|
1351
|
+
headers: {
|
|
1352
|
+
Authorization: `Bearer ${token}`,
|
|
1353
|
+
"Content-Type": "application/json"
|
|
1354
|
+
}
|
|
1355
|
+
});
|
|
1356
|
+
if (!finalizeResponse.ok) {
|
|
1357
|
+
const error = new TaskError(await finalizeResponse.text(), options.taskTemplate, prepareData.taskId);
|
|
1358
|
+
if (rejectTaskIdPromise) {
|
|
1359
|
+
taskIdPromiseWithResolvers.reject(error);
|
|
1360
|
+
}
|
|
1361
|
+
if (rejectTaskUrlPromise) {
|
|
1362
|
+
taskUrlPromiseWithResolvers.reject(error);
|
|
1363
|
+
}
|
|
1364
|
+
if (isMonitoring) {
|
|
1365
|
+
resultPromiseWithResolvers.reject(error);
|
|
1366
|
+
}
|
|
1367
|
+
return;
|
|
808
1368
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
options: {
|
|
824
|
-
uploadUrl: prepareData.fileUrls?.uploadUrl,
|
|
825
|
-
streamUrl: prepareData.fileUrls?.streamUrl
|
|
1369
|
+
try {
|
|
1370
|
+
await streamDone.promise;
|
|
1371
|
+
} catch (error) {
|
|
1372
|
+
const taskError = new TaskError(error instanceof Error ? error.message : String(error), options.taskTemplate, prepareData.taskId);
|
|
1373
|
+
if (rejectTaskIdPromise) {
|
|
1374
|
+
taskIdPromiseWithResolvers.reject(taskError);
|
|
1375
|
+
}
|
|
1376
|
+
if (rejectTaskUrlPromise) {
|
|
1377
|
+
taskUrlPromiseWithResolvers.reject(taskError);
|
|
1378
|
+
}
|
|
1379
|
+
if (isMonitoring) {
|
|
1380
|
+
resultPromiseWithResolvers.reject(taskError);
|
|
1381
|
+
}
|
|
1382
|
+
return;
|
|
826
1383
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1384
|
+
const payload = await finalizeResponse.json();
|
|
1385
|
+
taskIdPromiseWithResolvers.resolve(prepareData.taskId);
|
|
1386
|
+
taskUrlPromiseWithResolvers.resolve(payload.urls?.show ?? null);
|
|
1387
|
+
payloadPromiseWithResolvers.resolve(payload);
|
|
1388
|
+
if (onUpdate) {
|
|
1389
|
+
taskUpdateHandlers.add(onUpdate);
|
|
1390
|
+
startMonitoring();
|
|
1391
|
+
}
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
preparedTaskIdPromiseWithResolvers.reject(error);
|
|
1394
|
+
if (rejectTaskIdPromise) {
|
|
1395
|
+
taskIdPromiseWithResolvers.reject(error);
|
|
834
1396
|
}
|
|
835
|
-
});
|
|
836
|
-
if (!finalizeResponse.ok) {
|
|
837
|
-
const error = new TaskError(await finalizeResponse.text(), options.taskTemplate, prepareData.taskId);
|
|
838
|
-
finalizedPromiseWithResolvers.reject(error);
|
|
839
1397
|
if (rejectTaskUrlPromise) {
|
|
840
1398
|
taskUrlPromiseWithResolvers.reject(error);
|
|
841
1399
|
}
|
|
842
1400
|
if (isMonitoring) {
|
|
843
1401
|
resultPromiseWithResolvers.reject(error);
|
|
844
1402
|
}
|
|
845
|
-
return;
|
|
846
|
-
}
|
|
847
|
-
const payload = await finalizeResponse.json();
|
|
848
|
-
finalizedPromiseWithResolvers.resolve(prepareData.taskId);
|
|
849
|
-
taskUrlPromiseWithResolvers.resolve(payload.urls?.show ?? null);
|
|
850
|
-
payloadPromiseWithResolvers.resolve(payload);
|
|
851
|
-
if (onUpdate) {
|
|
852
|
-
taskUpdateHandlers.add(onUpdate);
|
|
853
|
-
startMonitoring();
|
|
854
1403
|
}
|
|
855
1404
|
})();
|
|
856
1405
|
const asyncIterable = callbackToAsyncIterable((push, _fail, done) => {
|
|
@@ -889,7 +1438,7 @@ function createTask(options, onUpdate) {
|
|
|
889
1438
|
return taskUrlPromiseWithResolvers.promise;
|
|
890
1439
|
},
|
|
891
1440
|
async abort(reason) {
|
|
892
|
-
const taskId = await
|
|
1441
|
+
const taskId = await preparedTaskIdPromiseWithResolvers.promise;
|
|
893
1442
|
await abortTask({
|
|
894
1443
|
taskId,
|
|
895
1444
|
accessToken: options.accessToken,
|
|
@@ -897,14 +1446,11 @@ function createTask(options, onUpdate) {
|
|
|
897
1446
|
});
|
|
898
1447
|
},
|
|
899
1448
|
async protect() {
|
|
900
|
-
const taskId = await
|
|
1449
|
+
const taskId = await preparedTaskIdPromiseWithResolvers.promise;
|
|
901
1450
|
await protectTask({
|
|
902
1451
|
taskId,
|
|
903
1452
|
accessToken: options.accessToken
|
|
904
1453
|
});
|
|
905
|
-
},
|
|
906
|
-
async finalized() {
|
|
907
|
-
return finalizedPromiseWithResolvers.promise;
|
|
908
1454
|
}
|
|
909
1455
|
};
|
|
910
1456
|
return Object.defineProperties(asyncIterable, Object.getOwnPropertyDescriptors(methods));
|
|
@@ -921,6 +1467,7 @@ function watchTasks(options) {
|
|
|
921
1467
|
let startDate = options.since;
|
|
922
1468
|
let lastPosition = null;
|
|
923
1469
|
let lastResponse;
|
|
1470
|
+
let processing = Promise.resolve();
|
|
924
1471
|
const customFetch = async (url, init) => {
|
|
925
1472
|
const response = await fetch(url, init);
|
|
926
1473
|
lastResponse = response;
|
|
@@ -952,6 +1499,9 @@ function watchTasks(options) {
|
|
|
952
1499
|
},
|
|
953
1500
|
async onDisconnect() {
|
|
954
1501
|
if (lastResponse) {
|
|
1502
|
+
if (isUnreachableStatus(lastResponse.status)) {
|
|
1503
|
+
options.onUnreachable?.(new RequenceUnreachableError(lastResponse.status));
|
|
1504
|
+
}
|
|
955
1505
|
options.onError?.(lastResponse.status, lastResponse.statusText);
|
|
956
1506
|
}
|
|
957
1507
|
},
|
|
@@ -965,82 +1515,85 @@ function watchTasks(options) {
|
|
|
965
1515
|
throw new Error("invalid update");
|
|
966
1516
|
}
|
|
967
1517
|
const update = updateResult.data;
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1518
|
+
processing = processing.then(() => applyUpdate(update, id)).catch(() => {
|
|
1519
|
+
eventSource.close();
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
async function applyUpdate(update, updateId) {
|
|
1524
|
+
if (!taskStorage.has(update.taskId)) {
|
|
1525
|
+
taskStorage.set(update.taskId, {
|
|
1526
|
+
input: null,
|
|
1527
|
+
data: {},
|
|
1528
|
+
errors: {},
|
|
1529
|
+
result: null,
|
|
1530
|
+
incomplete: true,
|
|
1531
|
+
rootTaskId: null
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
const storageEntry = taskStorage.get(update.taskId);
|
|
1535
|
+
switch (update.type) {
|
|
1536
|
+
case "taskStart": {
|
|
1537
|
+
storageEntry.input = await inbound(update.input, forbidCallbacks);
|
|
1538
|
+
storageEntry.incomplete = false;
|
|
1539
|
+
storageEntry.rootTaskId = update.rootTaskId;
|
|
1540
|
+
break;
|
|
977
1541
|
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
storageEntry.input = resolveRequenceTypes(update.input, () => {
|
|
982
|
-
throw new Error("input may not have callbacks");
|
|
983
|
-
});
|
|
984
|
-
storageEntry.incomplete = false;
|
|
985
|
-
storageEntry.rootTaskId = update.rootTaskId;
|
|
986
|
-
break;
|
|
987
|
-
}
|
|
988
|
-
case "nodeUpdate": {
|
|
989
|
-
if (update.node.alias) {
|
|
990
|
-
storageEntry.data[update.node.alias] = resolveRequenceTypes(update.data);
|
|
991
|
-
}
|
|
992
|
-
break;
|
|
1542
|
+
case "nodeUpdate": {
|
|
1543
|
+
if (update.node.alias) {
|
|
1544
|
+
storageEntry.data[update.node.alias] = await inbound(update.data, observeOnlyCallbacks);
|
|
993
1545
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1546
|
+
break;
|
|
1547
|
+
}
|
|
1548
|
+
case "nodeError": {
|
|
1549
|
+
if (update.node.alias) {
|
|
1550
|
+
storageEntry.errors[update.node.alias] = update.error;
|
|
999
1551
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1552
|
+
break;
|
|
1553
|
+
}
|
|
1554
|
+
case "taskEnd": {
|
|
1555
|
+
storageEntry.result = await inbound(update.result, observeOnlyCallbacks);
|
|
1556
|
+
taskStorage.delete(update.taskId);
|
|
1557
|
+
if (update.requireAck) {
|
|
1558
|
+
ackTask({
|
|
1559
|
+
taskId: update.taskId,
|
|
1560
|
+
accessToken: options.accessToken
|
|
1561
|
+
}).catch(() => {});
|
|
1010
1562
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1563
|
+
break;
|
|
1564
|
+
}
|
|
1565
|
+
case "taskError":
|
|
1566
|
+
case "taskAborted": {
|
|
1567
|
+
taskStorage.delete(update.taskId);
|
|
1568
|
+
if (update.requireAck) {
|
|
1569
|
+
ackTask({
|
|
1570
|
+
taskId: update.taskId,
|
|
1571
|
+
accessToken: options.accessToken
|
|
1572
|
+
}).catch(() => {});
|
|
1021
1573
|
}
|
|
1574
|
+
break;
|
|
1022
1575
|
}
|
|
1023
|
-
const context = {
|
|
1024
|
-
taskId: update.taskId,
|
|
1025
|
-
input: storageEntry.input,
|
|
1026
|
-
getNodeData(alias) {
|
|
1027
|
-
return storageEntry.data[alias] ?? null;
|
|
1028
|
-
},
|
|
1029
|
-
getNodeError(alias) {
|
|
1030
|
-
return storageEntry.errors[alias] ?? null;
|
|
1031
|
-
},
|
|
1032
|
-
result: storageEntry.result
|
|
1033
|
-
};
|
|
1034
|
-
const contextUpdate = {
|
|
1035
|
-
...update,
|
|
1036
|
-
context,
|
|
1037
|
-
updateId: id,
|
|
1038
|
-
incomplete: storageEntry.incomplete,
|
|
1039
|
-
rootTaskId: storageEntry.rootTaskId
|
|
1040
|
-
};
|
|
1041
|
-
taskUpdateHandlers.forEach((handler) => handler(contextUpdate));
|
|
1042
1576
|
}
|
|
1043
|
-
|
|
1577
|
+
const context = {
|
|
1578
|
+
taskId: update.taskId,
|
|
1579
|
+
input: storageEntry.input,
|
|
1580
|
+
getNodeData(alias) {
|
|
1581
|
+
return storageEntry.data[alias] ?? null;
|
|
1582
|
+
},
|
|
1583
|
+
getNodeError(alias) {
|
|
1584
|
+
return storageEntry.errors[alias] ?? null;
|
|
1585
|
+
},
|
|
1586
|
+
result: storageEntry.result
|
|
1587
|
+
};
|
|
1588
|
+
const contextUpdate = {
|
|
1589
|
+
...update,
|
|
1590
|
+
context,
|
|
1591
|
+
updateId,
|
|
1592
|
+
incomplete: storageEntry.incomplete,
|
|
1593
|
+
rootTaskId: storageEntry.rootTaskId
|
|
1594
|
+
};
|
|
1595
|
+
taskUpdateHandlers.forEach((handler) => handler(contextUpdate));
|
|
1596
|
+
}
|
|
1044
1597
|
const asyncIterable = callbackToAsyncIterable((push) => {
|
|
1045
1598
|
taskUpdateHandlers.add(push);
|
|
1046
1599
|
return () => {
|
|
@@ -1076,7 +1629,7 @@ var taskSchema = z6.object({
|
|
|
1076
1629
|
async function getTask(taskIdOrOptions) {
|
|
1077
1630
|
const taskId = typeof taskIdOrOptions === "string" ? taskIdOrOptions : taskIdOrOptions.taskId;
|
|
1078
1631
|
const { apiBaseUrl, token } = getAccessToken(typeof taskIdOrOptions === "string" ? undefined : taskIdOrOptions.accessToken);
|
|
1079
|
-
const response = await
|
|
1632
|
+
const response = await reachableFetch(new URL(`${apiBaseUrl}/task/${taskId}`), {
|
|
1080
1633
|
headers: {
|
|
1081
1634
|
Authorization: `Bearer ${token}`
|
|
1082
1635
|
}
|
|
@@ -1085,18 +1638,24 @@ async function getTask(taskIdOrOptions) {
|
|
|
1085
1638
|
throw new Error("Task not found");
|
|
1086
1639
|
}
|
|
1087
1640
|
const taskData = taskSchema.parse(await response.json());
|
|
1641
|
+
const [input, result, nodesData] = await Promise.all([
|
|
1642
|
+
inbound(taskData.input, forbidCallbacks),
|
|
1643
|
+
inbound(taskData.result, observeOnlyCallbacks),
|
|
1644
|
+
Promise.all(taskData.nodesData.map(async ({ alias, data }) => ({
|
|
1645
|
+
alias,
|
|
1646
|
+
data: await inbound(data, observeOnlyCallbacks)
|
|
1647
|
+
})))
|
|
1648
|
+
]);
|
|
1088
1649
|
const context = {
|
|
1089
1650
|
taskId,
|
|
1090
|
-
input
|
|
1091
|
-
throw new Error("input may not have callbacks");
|
|
1092
|
-
}),
|
|
1651
|
+
input,
|
|
1093
1652
|
getNodeData(alias) {
|
|
1094
|
-
return
|
|
1653
|
+
return nodesData.find((d) => d.alias === alias)?.data ?? null;
|
|
1095
1654
|
},
|
|
1096
1655
|
getNodeError(alias) {
|
|
1097
1656
|
return taskData.nodesError.find((d) => d.alias === alias)?.error ?? null;
|
|
1098
1657
|
},
|
|
1099
|
-
result
|
|
1658
|
+
result
|
|
1100
1659
|
};
|
|
1101
1660
|
return {
|
|
1102
1661
|
status: taskData.status,
|
|
@@ -1126,9 +1685,10 @@ export {
|
|
|
1126
1685
|
createTask,
|
|
1127
1686
|
abortTask,
|
|
1128
1687
|
TaskError,
|
|
1688
|
+
RequenceUnreachableError,
|
|
1129
1689
|
RequenceStream,
|
|
1130
1690
|
RequenceFile
|
|
1131
1691
|
};
|
|
1132
1692
|
|
|
1133
|
-
//# debugId=
|
|
1693
|
+
//# debugId=F96A579BA4EB8E1D64756E2164756E21
|
|
1134
1694
|
//# sourceMappingURL=index.js.map
|