@requence/task 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +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 +1057 -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 +450 -144
- package/build/types/helpers/src/protocol/NodeTree.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/command.d.ts +364 -142
- package/build/types/helpers/src/protocol/command.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/configurationScript.d.ts +10 -0
- package/build/types/helpers/src/protocol/configurationScript.d.ts.map +1 -0
- package/build/types/helpers/src/protocol/helpers.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/index.d.ts +4 -0
- package/build/types/helpers/src/protocol/index.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/logicLanguages.d.ts +19 -0
- package/build/types/helpers/src/protocol/logicLanguages.d.ts.map +1 -0
- package/build/types/helpers/src/protocol/loopDetection.d.ts +23 -0
- package/build/types/helpers/src/protocol/loopDetection.d.ts.map +1 -0
- package/build/types/helpers/src/protocol/nodeType.d.ts +73 -27
- package/build/types/helpers/src/protocol/nodeType.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/taskOptions.d.ts +4 -1
- package/build/types/helpers/src/protocol/taskOptions.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/templateNodeTypes.d.ts +36 -20
- package/build/types/helpers/src/protocol/templateNodeTypes.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/treeNodes.d.ts +476 -164
- package/build/types/helpers/src/protocol/treeNodes.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/update.d.ts +22 -22
- package/build/types/helpers/src/protocol/validateTreeStructure.d.ts +22 -0
- package/build/types/helpers/src/protocol/validateTreeStructure.d.ts.map +1 -0
- package/build/types/helpers/src/utils/amqpHeartbeat.d.ts +3 -0
- package/build/types/helpers/src/utils/amqpHeartbeat.d.ts.map +1 -0
- package/build/types/helpers/src/utils/amqpPublishRetry.d.ts +5 -0
- package/build/types/helpers/src/utils/amqpPublishRetry.d.ts.map +1 -0
- package/build/types/helpers/src/utils/claimCheckObject.d.ts +40 -0
- package/build/types/helpers/src/utils/claimCheckObject.d.ts.map +1 -0
- package/build/types/helpers/src/utils/debounce.d.ts.map +1 -1
- package/build/types/helpers/src/{files → utils}/fileObject.d.ts.map +1 -1
- package/build/types/helpers/src/{files → utils}/isValidMimeType.d.ts.map +1 -1
- package/build/types/helpers/src/utils/mapData.d.ts +1 -1
- package/build/types/helpers/src/utils/mapData.d.ts.map +1 -1
- package/build/types/helpers/src/{files → utils}/streamObject.d.ts.map +1 -1
- package/build/types/helpers/src/utils/variableRef.d.ts +19 -0
- package/build/types/helpers/src/utils/variableRef.d.ts.map +1 -0
- package/build/types/helpers/src/utils/variableScriptPatterns.d.ts +125 -0
- package/build/types/helpers/src/utils/variableScriptPatterns.d.ts.map +1 -0
- package/build/types/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,287 @@ 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
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
} else {
|
|
435
|
-
params.onSkip?.();
|
|
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();
|
|
628
|
+
}
|
|
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 createMessageHandler() {
|
|
675
|
+
return {
|
|
676
|
+
async wrapOutbound(body, ctx) {
|
|
677
|
+
const maxBytes = ctx.maxPayloadSize ?? DEFAULT_MAX_PAYLOAD_SIZE;
|
|
678
|
+
if (maxBytes <= 0 || body === undefined) {
|
|
679
|
+
return body;
|
|
680
|
+
}
|
|
681
|
+
const json = JSON.stringify(body);
|
|
682
|
+
if (json === undefined || Buffer.byteLength(json) <= maxBytes) {
|
|
683
|
+
return body;
|
|
451
684
|
}
|
|
452
|
-
|
|
453
|
-
|
|
685
|
+
const { uploadUrl } = ctx;
|
|
686
|
+
if (!uploadUrl) {
|
|
687
|
+
ctx.onOffloadSkip?.();
|
|
688
|
+
return body;
|
|
454
689
|
}
|
|
455
|
-
if (
|
|
456
|
-
return (
|
|
457
|
-
|
|
690
|
+
if (!isRecord(body)) {
|
|
691
|
+
return offload(ctx, uploadUrl, json);
|
|
692
|
+
}
|
|
693
|
+
const entries = Object.entries(body).map(([key, value]) => {
|
|
694
|
+
const valueJson = JSON.stringify(value);
|
|
695
|
+
return {
|
|
696
|
+
key,
|
|
697
|
+
valueJson,
|
|
698
|
+
size: valueJson === undefined ? 0 : Buffer.byteLength(valueJson)
|
|
458
699
|
};
|
|
700
|
+
}).sort((a, b) => b.size - a.size);
|
|
701
|
+
const wrapped = { ...body };
|
|
702
|
+
let total = Buffer.byteLength(json);
|
|
703
|
+
for (const entry of entries) {
|
|
704
|
+
if (total <= maxBytes || entry.valueJson === undefined || entry.size <= 256) {
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
const ref = await offload(ctx, uploadUrl, entry.valueJson);
|
|
708
|
+
wrapped[entry.key] = ref;
|
|
709
|
+
total += Buffer.byteLength(JSON.stringify(ref)) - entry.size;
|
|
459
710
|
}
|
|
711
|
+
return wrapped;
|
|
460
712
|
}
|
|
461
|
-
}
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function createValueHandler() {
|
|
716
|
+
return {
|
|
717
|
+
tag: "ClaimCheck",
|
|
718
|
+
canHandle: () => false,
|
|
719
|
+
serialize() {
|
|
720
|
+
throw new Error("ClaimCheck egress is the bundled MessageHandler (wrapOutbound); it never reaches the value walk");
|
|
721
|
+
},
|
|
722
|
+
isReference: (value) => isClaimCheckObject(value),
|
|
723
|
+
async deserialize(ref, ctx) {
|
|
724
|
+
const response = await ctx.fetch(ref.url, { signal: ctx.signal });
|
|
725
|
+
await assertOk(response, ref.url, "claim-check fetch");
|
|
726
|
+
const text = await response.text();
|
|
727
|
+
try {
|
|
728
|
+
return JSON.parse(text);
|
|
729
|
+
} catch {
|
|
730
|
+
throw new Error(`malformed claim-check payload (${ref.url})`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
function createClaimCheckHandler() {
|
|
736
|
+
return {
|
|
737
|
+
valueHandler: createValueHandler(),
|
|
738
|
+
messageHandler: createMessageHandler()
|
|
739
|
+
};
|
|
462
740
|
}
|
|
463
|
-
|
|
464
741
|
// src/createTask.ts
|
|
465
742
|
import chalk from "chalk";
|
|
466
743
|
import { createEventSource } from "eventsource-client";
|
|
@@ -500,7 +777,7 @@ class TaskAbortError extends Error {
|
|
|
500
777
|
async function abortTask(options) {
|
|
501
778
|
const { apiBaseUrl, token } = getAccessToken(options.accessToken);
|
|
502
779
|
const abortUrl = `${apiBaseUrl}/task/abort/${options.taskId}`;
|
|
503
|
-
const response = await
|
|
780
|
+
const response = await reachableFetch(abortUrl, {
|
|
504
781
|
method: "POST",
|
|
505
782
|
body: options.reason ?? "",
|
|
506
783
|
headers: {
|
|
@@ -515,7 +792,7 @@ async function abortTask(options) {
|
|
|
515
792
|
// src/ackTask.ts
|
|
516
793
|
async function ackTask(options) {
|
|
517
794
|
const { apiBaseUrl, token } = getAccessToken(options.accessToken);
|
|
518
|
-
const response = await
|
|
795
|
+
const response = await reachableFetch(`${apiBaseUrl}/task/ack/${options.taskId}`, {
|
|
519
796
|
method: "POST",
|
|
520
797
|
headers: {
|
|
521
798
|
Authorization: `Bearer ${token}`
|
|
@@ -526,6 +803,214 @@ async function ackTask(options) {
|
|
|
526
803
|
}
|
|
527
804
|
}
|
|
528
805
|
|
|
806
|
+
// ../callbacks/src/handler.ts
|
|
807
|
+
function createRequenceCallbackHandler() {
|
|
808
|
+
return {
|
|
809
|
+
tag: "RequenceCallback",
|
|
810
|
+
canHandle: (value) => typeof value === "function",
|
|
811
|
+
serialize(callback, ctx, path) {
|
|
812
|
+
if (!ctx.onCallback) {
|
|
813
|
+
throw new Error(`functions are not serializable on this boundary (no ctx.onCallback) at path "${path.join(".")}"`);
|
|
814
|
+
}
|
|
815
|
+
return {
|
|
816
|
+
...ctx.onCallback(callback),
|
|
817
|
+
outputName: ctx.outputName ?? null,
|
|
818
|
+
propertyPath: [...path],
|
|
819
|
+
__REQUENCE_type: "RequenceCallback"
|
|
820
|
+
};
|
|
821
|
+
},
|
|
822
|
+
isReference: (value) => isCallbackObject(value),
|
|
823
|
+
deserialize(ref, ctx) {
|
|
824
|
+
return (arg) => {
|
|
825
|
+
ctx.onCallbackInvoke?.({ ...ref, arg });
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
// ../transformer/src/errors.ts
|
|
831
|
+
function formatPath(path) {
|
|
832
|
+
if (path.length === 0) {
|
|
833
|
+
return "<root>";
|
|
834
|
+
}
|
|
835
|
+
let out = "";
|
|
836
|
+
for (const segment of path) {
|
|
837
|
+
out += typeof segment === "number" ? `[${segment}]` : out ? `.${segment}` : segment;
|
|
838
|
+
}
|
|
839
|
+
return out;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
class TransformError extends Error {
|
|
843
|
+
path;
|
|
844
|
+
detail;
|
|
845
|
+
constructor(detail, path) {
|
|
846
|
+
super(`${detail} at ${formatPath(path)}`);
|
|
847
|
+
this.name = "TransformError";
|
|
848
|
+
this.path = path;
|
|
849
|
+
this.detail = detail;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// ../transformer/src/guards.ts
|
|
854
|
+
var REFERENCE_TAG_KEY = "__REQUENCE_type";
|
|
855
|
+
function isPlainObject(value) {
|
|
856
|
+
if (value === null || typeof value !== "object") {
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
const proto = Object.getPrototypeOf(value);
|
|
860
|
+
return proto === null || proto === Object.prototype;
|
|
861
|
+
}
|
|
862
|
+
function isComplexValue(value) {
|
|
863
|
+
if (value === null) {
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
const type = typeof value;
|
|
867
|
+
if (type === "object") {
|
|
868
|
+
return !Array.isArray(value) && !isPlainObject(value);
|
|
869
|
+
}
|
|
870
|
+
return type === "function" || type === "symbol" || type === "bigint";
|
|
871
|
+
}
|
|
872
|
+
function hasReferenceTag(value) {
|
|
873
|
+
return isPlainObject(value) && REFERENCE_TAG_KEY in value;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// ../transformer/src/walk.ts
|
|
877
|
+
var recurse = { kind: "recurse" };
|
|
878
|
+
var replaceWith = (value) => ({
|
|
879
|
+
kind: "replace",
|
|
880
|
+
value
|
|
881
|
+
});
|
|
882
|
+
var MAX_REPLACE_DEPTH = 100;
|
|
883
|
+
async function walk(root, visit) {
|
|
884
|
+
const go = async (value, path, replaceDepth) => {
|
|
885
|
+
let node = value;
|
|
886
|
+
if (Array.isArray(node)) {
|
|
887
|
+
node = await Promise.all(node.map((item, index) => go(item, [...path, index], 0)));
|
|
888
|
+
} else if (isPlainObject(node)) {
|
|
889
|
+
const entries = await Promise.all(Object.entries(node).map(async ([key, item]) => [key, await go(item, [...path, key], 0)]));
|
|
890
|
+
node = Object.fromEntries(entries);
|
|
891
|
+
}
|
|
892
|
+
const verdict = await visit(node, path);
|
|
893
|
+
if (verdict.kind === "replace") {
|
|
894
|
+
if (replaceDepth >= MAX_REPLACE_DEPTH) {
|
|
895
|
+
throw new TransformError("transform did not reach a fixpoint (a handler keeps producing handleable output)", path);
|
|
896
|
+
}
|
|
897
|
+
return go(verdict.value, path, replaceDepth + 1);
|
|
898
|
+
}
|
|
899
|
+
return node;
|
|
900
|
+
};
|
|
901
|
+
return go(root, [], 0);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// ../transformer/src/transform.ts
|
|
905
|
+
function createTransformer() {
|
|
906
|
+
return build([], []);
|
|
907
|
+
}
|
|
908
|
+
function build(valueHandlers, messageHandlers) {
|
|
909
|
+
const transformer = {
|
|
910
|
+
withHandler(handler) {
|
|
911
|
+
const bundle = "tag" in handler ? { valueHandler: handler } : handler;
|
|
912
|
+
if (!bundle.valueHandler && !bundle.messageHandler) {
|
|
913
|
+
throw new Error("withHandler: bundle provides neither a valueHandler nor a messageHandler");
|
|
914
|
+
}
|
|
915
|
+
if (bundle.valueHandler) {
|
|
916
|
+
const { tag } = bundle.valueHandler;
|
|
917
|
+
if (valueHandlers.some((existing) => existing.tag === tag)) {
|
|
918
|
+
throw new Error(`withHandler: a ValueHandler with tag "${tag}" is already composed`);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return build(bundle.valueHandler ? [...valueHandlers, bundle.valueHandler] : valueHandlers, bundle.messageHandler ? [...messageHandlers, bundle.messageHandler] : messageHandlers);
|
|
922
|
+
},
|
|
923
|
+
async outbound(value, ctx) {
|
|
924
|
+
const seen = new Map;
|
|
925
|
+
const visit = (node, path) => {
|
|
926
|
+
if (!isComplexValue(node)) {
|
|
927
|
+
return recurse;
|
|
928
|
+
}
|
|
929
|
+
const handler = valueHandlers.find((candidate) => candidate.canHandle(node));
|
|
930
|
+
if (!handler) {
|
|
931
|
+
const withToJSON = node;
|
|
932
|
+
if (typeof node === "object" && typeof withToJSON.toJSON === "function") {
|
|
933
|
+
return replaceWith(withToJSON.toJSON());
|
|
934
|
+
}
|
|
935
|
+
const label = node?.constructor?.name ?? (typeof node === "function" ? "function" : typeof node);
|
|
936
|
+
throw new TransformError(`no composed ValueHandler for complex value of type ${label}`, path);
|
|
937
|
+
}
|
|
938
|
+
if (typeof node === "object" && node !== null) {
|
|
939
|
+
const cached = seen.get(node);
|
|
940
|
+
if (cached) {
|
|
941
|
+
return cached.then(replaceWith);
|
|
942
|
+
}
|
|
943
|
+
const pending = Promise.resolve(handler.serialize(node, ctx, path));
|
|
944
|
+
seen.set(node, pending);
|
|
945
|
+
return pending.then(replaceWith);
|
|
946
|
+
}
|
|
947
|
+
return Promise.resolve(handler.serialize(node, ctx, path)).then(replaceWith);
|
|
948
|
+
};
|
|
949
|
+
const valueTransformed = await walk(value, visit);
|
|
950
|
+
let body = valueTransformed;
|
|
951
|
+
for (const [index, handler] of messageHandlers.entries()) {
|
|
952
|
+
const wrapped = await handler.wrapOutbound(body, ctx);
|
|
953
|
+
assertTopLevelKeysPreserved(body, wrapped, index);
|
|
954
|
+
body = wrapped;
|
|
955
|
+
}
|
|
956
|
+
return body;
|
|
957
|
+
},
|
|
958
|
+
async inbound(value, ctx) {
|
|
959
|
+
const visit = (node, path) => {
|
|
960
|
+
if (!isPlainObject(node)) {
|
|
961
|
+
return recurse;
|
|
962
|
+
}
|
|
963
|
+
const handler = valueHandlers.find((candidate) => candidate.isReference(node));
|
|
964
|
+
if (handler) {
|
|
965
|
+
if (handler.passthrough) {
|
|
966
|
+
return recurse;
|
|
967
|
+
}
|
|
968
|
+
return Promise.resolve(handler.deserialize(node, ctx, path)).then(replaceWith);
|
|
969
|
+
}
|
|
970
|
+
if (hasReferenceTag(node)) {
|
|
971
|
+
const tag = node.__REQUENCE_type;
|
|
972
|
+
throw new TransformError(`no composed ValueHandler owns reference tag ${JSON.stringify(tag)}`, path);
|
|
973
|
+
}
|
|
974
|
+
return recurse;
|
|
975
|
+
};
|
|
976
|
+
return walk(value, visit);
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
return transformer;
|
|
980
|
+
}
|
|
981
|
+
function assertTopLevelKeysPreserved(body, wrapped, handlerIndex) {
|
|
982
|
+
if (!isPlainObject(body)) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
const label = `MessageHandler #${handlerIndex}`;
|
|
986
|
+
if (!isPlainObject(wrapped)) {
|
|
987
|
+
throw new TransformError(`${label} replaced a record body wholesale — wrapOutbound must preserve a record's top-level keys`, []);
|
|
988
|
+
}
|
|
989
|
+
const before = Object.keys(body);
|
|
990
|
+
const after = new Set(Object.keys(wrapped));
|
|
991
|
+
const removed = before.filter((key) => !after.has(key));
|
|
992
|
+
const added = [...after].filter((key) => !before.includes(key));
|
|
993
|
+
if (removed.length > 0 || added.length > 0) {
|
|
994
|
+
throw new TransformError(`${label} changed a record body's top-level keys (removed: [${removed.join(", ")}], added: [${added.join(", ")}]) — wrapOutbound must preserve them`, []);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
// src/ingress.ts
|
|
998
|
+
var transformer = createTransformer().withHandler(createRequenceFileHandler()).withHandler(createRequenceStreamHandler()).withHandler(createRequenceCallbackHandler()).withHandler(createClaimCheckHandler());
|
|
999
|
+
var inbound = (data, opts = {}) => transformer.inbound(data, {
|
|
1000
|
+
fetch: globalThis.fetch,
|
|
1001
|
+
onCallbackInvoke: opts.onCallbackInvoke
|
|
1002
|
+
});
|
|
1003
|
+
var forbidCallbacks = {
|
|
1004
|
+
onCallbackInvoke: () => {
|
|
1005
|
+
throw new Error("input may not have callbacks");
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
var observeOnlyCallbacks = {
|
|
1009
|
+
onCallbackInvoke: () => {
|
|
1010
|
+
throw new Error("callbacks in watched data cannot be invoked from a task client");
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
|
|
529
1014
|
// src/protectTask.ts
|
|
530
1015
|
class TaskProtectError extends Error {
|
|
531
1016
|
taskId;
|
|
@@ -537,7 +1022,7 @@ class TaskProtectError extends Error {
|
|
|
537
1022
|
async function protectTask(options) {
|
|
538
1023
|
const { apiBaseUrl, token } = getAccessToken(options.accessToken);
|
|
539
1024
|
const protectUrl = `${apiBaseUrl}/task/protect/${options.taskId}`;
|
|
540
|
-
const response = await
|
|
1025
|
+
const response = await reachableFetch(protectUrl, {
|
|
541
1026
|
method: "POST",
|
|
542
1027
|
headers: {
|
|
543
1028
|
Authorization: `Bearer ${token}`
|
|
@@ -670,6 +1155,7 @@ function createTask(options, onUpdate) {
|
|
|
670
1155
|
let since = null;
|
|
671
1156
|
let lastPosition = null;
|
|
672
1157
|
let lastResponse;
|
|
1158
|
+
let processing = Promise.resolve();
|
|
673
1159
|
const customFetch = async (url, init) => {
|
|
674
1160
|
const response = await fetch(url, init);
|
|
675
1161
|
lastResponse = response;
|
|
@@ -695,8 +1181,13 @@ function createTask(options, onUpdate) {
|
|
|
695
1181
|
}
|
|
696
1182
|
},
|
|
697
1183
|
async onDisconnect() {
|
|
698
|
-
if (lastResponse
|
|
1184
|
+
if (lastResponse?.status === 200) {
|
|
699
1185
|
eventSource.close();
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
if (lastResponse && isUnreachableStatus(lastResponse.status)) {
|
|
1189
|
+
eventSource.close();
|
|
1190
|
+
resultPromiseWithResolvers.reject(new RequenceUnreachableError(lastResponse.status));
|
|
700
1191
|
}
|
|
701
1192
|
},
|
|
702
1193
|
onMessage({ id, event, data }) {
|
|
@@ -710,147 +1201,200 @@ function createTask(options, onUpdate) {
|
|
|
710
1201
|
return;
|
|
711
1202
|
}
|
|
712
1203
|
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;
|
|
1204
|
+
processing = processing.then(() => applyUpdate(update)).catch((error) => {
|
|
1205
|
+
eventSource.close();
|
|
1206
|
+
resultPromiseWithResolvers.reject(new TaskError(error instanceof Error ? error.message : String(error), options.taskTemplate, payload.taskId));
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
async function applyUpdate(update) {
|
|
1211
|
+
switch (update.type) {
|
|
1212
|
+
case "taskStart": {
|
|
1213
|
+
taskStorage.input = await inbound(update.input, forbidCallbacks);
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
case "nodeUpdate": {
|
|
1217
|
+
if (update.node.alias) {
|
|
1218
|
+
taskStorage.data[update.node.alias] = await inbound(update.data, observeOnlyCallbacks);
|
|
742
1219
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
taskId: payload.taskId,
|
|
749
|
-
accessToken: options.accessToken
|
|
750
|
-
}).catch(() => {});
|
|
751
|
-
}
|
|
752
|
-
break;
|
|
1220
|
+
break;
|
|
1221
|
+
}
|
|
1222
|
+
case "nodeError": {
|
|
1223
|
+
if (update.node.alias) {
|
|
1224
|
+
taskStorage.errors[update.node.alias] = update.error;
|
|
753
1225
|
}
|
|
1226
|
+
break;
|
|
754
1227
|
}
|
|
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
|
-
});
|
|
1228
|
+
case "taskEnd": {
|
|
1229
|
+
taskStorage.result = await inbound(update.result, observeOnlyCallbacks);
|
|
1230
|
+
eventSource.close();
|
|
1231
|
+
if (update.requireAck) {
|
|
1232
|
+
ackTask({
|
|
1233
|
+
taskId: payload.taskId,
|
|
1234
|
+
accessToken: options.accessToken
|
|
1235
|
+
}).catch(() => {});
|
|
1236
|
+
}
|
|
1237
|
+
break;
|
|
775
1238
|
}
|
|
776
|
-
|
|
777
|
-
|
|
1239
|
+
case "taskError":
|
|
1240
|
+
case "taskAborted": {
|
|
1241
|
+
eventSource.close();
|
|
1242
|
+
if (update.requireAck) {
|
|
1243
|
+
ackTask({
|
|
1244
|
+
taskId: payload.taskId,
|
|
1245
|
+
accessToken: options.accessToken
|
|
1246
|
+
}).catch(() => {});
|
|
1247
|
+
}
|
|
1248
|
+
break;
|
|
778
1249
|
}
|
|
779
|
-
taskUpdateHandlers.forEach((handler) => handler(contextUpdate));
|
|
780
1250
|
}
|
|
781
|
-
|
|
1251
|
+
const context = {
|
|
1252
|
+
taskId: update.taskId,
|
|
1253
|
+
input: taskStorage.input,
|
|
1254
|
+
getNodeData(alias) {
|
|
1255
|
+
return taskStorage.data[alias] ?? null;
|
|
1256
|
+
},
|
|
1257
|
+
getNodeError(alias) {
|
|
1258
|
+
return taskStorage.errors[alias] ?? null;
|
|
1259
|
+
},
|
|
1260
|
+
result: taskStorage.result
|
|
1261
|
+
};
|
|
1262
|
+
const contextUpdate = {
|
|
1263
|
+
...update,
|
|
1264
|
+
context
|
|
1265
|
+
};
|
|
1266
|
+
if (contextUpdate.type === "taskEnd") {
|
|
1267
|
+
resultPromiseWithResolvers.resolve({
|
|
1268
|
+
...context,
|
|
1269
|
+
taskUrl: payload.urls?.show ?? ""
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
if (contextUpdate.type === "taskError" || contextUpdate.type === "taskAborted") {
|
|
1273
|
+
resultPromiseWithResolvers.reject(new TaskError(contextUpdate.reason ?? (contextUpdate.type === "taskError" ? "Task failed" : "Task aborted"), options.taskTemplate, payload.taskId));
|
|
1274
|
+
}
|
|
1275
|
+
taskUpdateHandlers.forEach((handler) => handler(contextUpdate));
|
|
1276
|
+
}
|
|
782
1277
|
};
|
|
783
1278
|
const taskIdPromiseWithResolvers = Promise.withResolvers();
|
|
1279
|
+
const preparedTaskIdPromiseWithResolvers = Promise.withResolvers();
|
|
1280
|
+
preparedTaskIdPromiseWithResolvers.promise.catch(() => {});
|
|
784
1281
|
const taskUrlPromiseWithResolvers = Promise.withResolvers();
|
|
785
1282
|
const resultPromiseWithResolvers = Promise.withResolvers();
|
|
786
|
-
const finalizedPromiseWithResolvers = Promise.withResolvers();
|
|
787
|
-
finalizedPromiseWithResolvers.promise.catch(() => {});
|
|
788
1283
|
let rejectTaskIdPromise = false;
|
|
789
1284
|
let rejectTaskUrlPromise = false;
|
|
790
1285
|
(async () => {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1286
|
+
try {
|
|
1287
|
+
const prepareResponse = await reachableFetch(prepareUrl, {
|
|
1288
|
+
method: "POST",
|
|
1289
|
+
headers: {
|
|
1290
|
+
Authorization: `Bearer ${token}`
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
if (!prepareResponse.ok) {
|
|
1294
|
+
const error = new TaskPrepareError(await prepareResponse.text(), options.taskTemplate);
|
|
1295
|
+
preparedTaskIdPromiseWithResolvers.reject(error);
|
|
1296
|
+
if (rejectTaskIdPromise) {
|
|
1297
|
+
taskIdPromiseWithResolvers.reject(error);
|
|
1298
|
+
}
|
|
1299
|
+
if (rejectTaskUrlPromise) {
|
|
1300
|
+
taskUrlPromiseWithResolvers.reject(error);
|
|
1301
|
+
}
|
|
1302
|
+
if (isMonitoring) {
|
|
1303
|
+
resultPromiseWithResolvers.reject(error);
|
|
1304
|
+
}
|
|
1305
|
+
return;
|
|
795
1306
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
finalizedPromiseWithResolvers.reject(error);
|
|
800
|
-
if (rejectTaskIdPromise) {
|
|
801
|
-
taskIdPromiseWithResolvers.reject(error);
|
|
1307
|
+
const prepareData = await prepareResponse.json();
|
|
1308
|
+
if (prepareData.branch !== "live" && !options.suppressBranchWarning) {
|
|
1309
|
+
console.warn(chalk.hex("#eab308")("task is executed in", chalk.bold(prepareData.branch), "branch"));
|
|
802
1310
|
}
|
|
803
|
-
|
|
804
|
-
|
|
1311
|
+
preparedTaskIdPromiseWithResolvers.resolve(prepareData.taskId);
|
|
1312
|
+
const streamDone = Promise.withResolvers();
|
|
1313
|
+
streamDone.promise.catch(() => {});
|
|
1314
|
+
let mappedParams;
|
|
1315
|
+
try {
|
|
1316
|
+
const { value, done } = await withRequenceStreams(() => transformer.outbound({
|
|
1317
|
+
name: options.name,
|
|
1318
|
+
input: options.input,
|
|
1319
|
+
priority,
|
|
1320
|
+
requireAck: options.requireAck ?? false
|
|
1321
|
+
}, {
|
|
1322
|
+
fetch: globalThis.fetch,
|
|
1323
|
+
uploadUrl: prepareData.fileUrls?.uploadUrl,
|
|
1324
|
+
streamUrl: prepareData.fileUrls?.streamUrl,
|
|
1325
|
+
maxPayloadSize: prepareData.limits?.maxPayloadSize,
|
|
1326
|
+
maxFileSize: prepareData.limits?.maxFileSize
|
|
1327
|
+
}));
|
|
1328
|
+
mappedParams = value;
|
|
1329
|
+
done.then(() => streamDone.resolve(), (error) => streamDone.reject(error instanceof Error ? error : new Error(String(error))));
|
|
1330
|
+
} catch (error) {
|
|
1331
|
+
const taskError = new TaskError(error instanceof Error ? error.message : String(error), options.taskTemplate, prepareData.taskId);
|
|
1332
|
+
if (rejectTaskIdPromise) {
|
|
1333
|
+
taskIdPromiseWithResolvers.reject(taskError);
|
|
1334
|
+
}
|
|
1335
|
+
if (rejectTaskUrlPromise) {
|
|
1336
|
+
taskUrlPromiseWithResolvers.reject(taskError);
|
|
1337
|
+
}
|
|
1338
|
+
if (isMonitoring) {
|
|
1339
|
+
resultPromiseWithResolvers.reject(taskError);
|
|
1340
|
+
}
|
|
1341
|
+
return;
|
|
805
1342
|
}
|
|
806
|
-
|
|
807
|
-
|
|
1343
|
+
const finalizeResponse = await reachableFetch(prepareData.finalizeUrl, {
|
|
1344
|
+
method: "POST",
|
|
1345
|
+
body: JSON.stringify(mappedParams),
|
|
1346
|
+
headers: {
|
|
1347
|
+
Authorization: `Bearer ${token}`,
|
|
1348
|
+
"Content-Type": "application/json"
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
if (!finalizeResponse.ok) {
|
|
1352
|
+
const error = new TaskError(await finalizeResponse.text(), options.taskTemplate, prepareData.taskId);
|
|
1353
|
+
if (rejectTaskIdPromise) {
|
|
1354
|
+
taskIdPromiseWithResolvers.reject(error);
|
|
1355
|
+
}
|
|
1356
|
+
if (rejectTaskUrlPromise) {
|
|
1357
|
+
taskUrlPromiseWithResolvers.reject(error);
|
|
1358
|
+
}
|
|
1359
|
+
if (isMonitoring) {
|
|
1360
|
+
resultPromiseWithResolvers.reject(error);
|
|
1361
|
+
}
|
|
1362
|
+
return;
|
|
808
1363
|
}
|
|
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
|
|
1364
|
+
try {
|
|
1365
|
+
await streamDone.promise;
|
|
1366
|
+
} catch (error) {
|
|
1367
|
+
const taskError = new TaskError(error instanceof Error ? error.message : String(error), options.taskTemplate, prepareData.taskId);
|
|
1368
|
+
if (rejectTaskIdPromise) {
|
|
1369
|
+
taskIdPromiseWithResolvers.reject(taskError);
|
|
1370
|
+
}
|
|
1371
|
+
if (rejectTaskUrlPromise) {
|
|
1372
|
+
taskUrlPromiseWithResolvers.reject(taskError);
|
|
1373
|
+
}
|
|
1374
|
+
if (isMonitoring) {
|
|
1375
|
+
resultPromiseWithResolvers.reject(taskError);
|
|
1376
|
+
}
|
|
1377
|
+
return;
|
|
826
1378
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1379
|
+
const payload = await finalizeResponse.json();
|
|
1380
|
+
taskIdPromiseWithResolvers.resolve(prepareData.taskId);
|
|
1381
|
+
taskUrlPromiseWithResolvers.resolve(payload.urls?.show ?? null);
|
|
1382
|
+
payloadPromiseWithResolvers.resolve(payload);
|
|
1383
|
+
if (onUpdate) {
|
|
1384
|
+
taskUpdateHandlers.add(onUpdate);
|
|
1385
|
+
startMonitoring();
|
|
1386
|
+
}
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
preparedTaskIdPromiseWithResolvers.reject(error);
|
|
1389
|
+
if (rejectTaskIdPromise) {
|
|
1390
|
+
taskIdPromiseWithResolvers.reject(error);
|
|
834
1391
|
}
|
|
835
|
-
});
|
|
836
|
-
if (!finalizeResponse.ok) {
|
|
837
|
-
const error = new TaskError(await finalizeResponse.text(), options.taskTemplate, prepareData.taskId);
|
|
838
|
-
finalizedPromiseWithResolvers.reject(error);
|
|
839
1392
|
if (rejectTaskUrlPromise) {
|
|
840
1393
|
taskUrlPromiseWithResolvers.reject(error);
|
|
841
1394
|
}
|
|
842
1395
|
if (isMonitoring) {
|
|
843
1396
|
resultPromiseWithResolvers.reject(error);
|
|
844
1397
|
}
|
|
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
1398
|
}
|
|
855
1399
|
})();
|
|
856
1400
|
const asyncIterable = callbackToAsyncIterable((push, _fail, done) => {
|
|
@@ -889,7 +1433,7 @@ function createTask(options, onUpdate) {
|
|
|
889
1433
|
return taskUrlPromiseWithResolvers.promise;
|
|
890
1434
|
},
|
|
891
1435
|
async abort(reason) {
|
|
892
|
-
const taskId = await
|
|
1436
|
+
const taskId = await preparedTaskIdPromiseWithResolvers.promise;
|
|
893
1437
|
await abortTask({
|
|
894
1438
|
taskId,
|
|
895
1439
|
accessToken: options.accessToken,
|
|
@@ -897,14 +1441,11 @@ function createTask(options, onUpdate) {
|
|
|
897
1441
|
});
|
|
898
1442
|
},
|
|
899
1443
|
async protect() {
|
|
900
|
-
const taskId = await
|
|
1444
|
+
const taskId = await preparedTaskIdPromiseWithResolvers.promise;
|
|
901
1445
|
await protectTask({
|
|
902
1446
|
taskId,
|
|
903
1447
|
accessToken: options.accessToken
|
|
904
1448
|
});
|
|
905
|
-
},
|
|
906
|
-
async finalized() {
|
|
907
|
-
return finalizedPromiseWithResolvers.promise;
|
|
908
1449
|
}
|
|
909
1450
|
};
|
|
910
1451
|
return Object.defineProperties(asyncIterable, Object.getOwnPropertyDescriptors(methods));
|
|
@@ -921,6 +1462,7 @@ function watchTasks(options) {
|
|
|
921
1462
|
let startDate = options.since;
|
|
922
1463
|
let lastPosition = null;
|
|
923
1464
|
let lastResponse;
|
|
1465
|
+
let processing = Promise.resolve();
|
|
924
1466
|
const customFetch = async (url, init) => {
|
|
925
1467
|
const response = await fetch(url, init);
|
|
926
1468
|
lastResponse = response;
|
|
@@ -952,6 +1494,9 @@ function watchTasks(options) {
|
|
|
952
1494
|
},
|
|
953
1495
|
async onDisconnect() {
|
|
954
1496
|
if (lastResponse) {
|
|
1497
|
+
if (isUnreachableStatus(lastResponse.status)) {
|
|
1498
|
+
options.onUnreachable?.(new RequenceUnreachableError(lastResponse.status));
|
|
1499
|
+
}
|
|
955
1500
|
options.onError?.(lastResponse.status, lastResponse.statusText);
|
|
956
1501
|
}
|
|
957
1502
|
},
|
|
@@ -965,82 +1510,85 @@ function watchTasks(options) {
|
|
|
965
1510
|
throw new Error("invalid update");
|
|
966
1511
|
}
|
|
967
1512
|
const update = updateResult.data;
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1513
|
+
processing = processing.then(() => applyUpdate(update, id)).catch(() => {
|
|
1514
|
+
eventSource.close();
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
async function applyUpdate(update, updateId) {
|
|
1519
|
+
if (!taskStorage.has(update.taskId)) {
|
|
1520
|
+
taskStorage.set(update.taskId, {
|
|
1521
|
+
input: null,
|
|
1522
|
+
data: {},
|
|
1523
|
+
errors: {},
|
|
1524
|
+
result: null,
|
|
1525
|
+
incomplete: true,
|
|
1526
|
+
rootTaskId: null
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
const storageEntry = taskStorage.get(update.taskId);
|
|
1530
|
+
switch (update.type) {
|
|
1531
|
+
case "taskStart": {
|
|
1532
|
+
storageEntry.input = await inbound(update.input, forbidCallbacks);
|
|
1533
|
+
storageEntry.incomplete = false;
|
|
1534
|
+
storageEntry.rootTaskId = update.rootTaskId;
|
|
1535
|
+
break;
|
|
977
1536
|
}
|
|
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;
|
|
1537
|
+
case "nodeUpdate": {
|
|
1538
|
+
if (update.node.alias) {
|
|
1539
|
+
storageEntry.data[update.node.alias] = await inbound(update.data, observeOnlyCallbacks);
|
|
993
1540
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1541
|
+
break;
|
|
1542
|
+
}
|
|
1543
|
+
case "nodeError": {
|
|
1544
|
+
if (update.node.alias) {
|
|
1545
|
+
storageEntry.errors[update.node.alias] = update.error;
|
|
999
1546
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1547
|
+
break;
|
|
1548
|
+
}
|
|
1549
|
+
case "taskEnd": {
|
|
1550
|
+
storageEntry.result = await inbound(update.result, observeOnlyCallbacks);
|
|
1551
|
+
taskStorage.delete(update.taskId);
|
|
1552
|
+
if (update.requireAck) {
|
|
1553
|
+
ackTask({
|
|
1554
|
+
taskId: update.taskId,
|
|
1555
|
+
accessToken: options.accessToken
|
|
1556
|
+
}).catch(() => {});
|
|
1010
1557
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1558
|
+
break;
|
|
1559
|
+
}
|
|
1560
|
+
case "taskError":
|
|
1561
|
+
case "taskAborted": {
|
|
1562
|
+
taskStorage.delete(update.taskId);
|
|
1563
|
+
if (update.requireAck) {
|
|
1564
|
+
ackTask({
|
|
1565
|
+
taskId: update.taskId,
|
|
1566
|
+
accessToken: options.accessToken
|
|
1567
|
+
}).catch(() => {});
|
|
1021
1568
|
}
|
|
1569
|
+
break;
|
|
1022
1570
|
}
|
|
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
1571
|
}
|
|
1043
|
-
|
|
1572
|
+
const context = {
|
|
1573
|
+
taskId: update.taskId,
|
|
1574
|
+
input: storageEntry.input,
|
|
1575
|
+
getNodeData(alias) {
|
|
1576
|
+
return storageEntry.data[alias] ?? null;
|
|
1577
|
+
},
|
|
1578
|
+
getNodeError(alias) {
|
|
1579
|
+
return storageEntry.errors[alias] ?? null;
|
|
1580
|
+
},
|
|
1581
|
+
result: storageEntry.result
|
|
1582
|
+
};
|
|
1583
|
+
const contextUpdate = {
|
|
1584
|
+
...update,
|
|
1585
|
+
context,
|
|
1586
|
+
updateId,
|
|
1587
|
+
incomplete: storageEntry.incomplete,
|
|
1588
|
+
rootTaskId: storageEntry.rootTaskId
|
|
1589
|
+
};
|
|
1590
|
+
taskUpdateHandlers.forEach((handler) => handler(contextUpdate));
|
|
1591
|
+
}
|
|
1044
1592
|
const asyncIterable = callbackToAsyncIterable((push) => {
|
|
1045
1593
|
taskUpdateHandlers.add(push);
|
|
1046
1594
|
return () => {
|
|
@@ -1076,7 +1624,7 @@ var taskSchema = z6.object({
|
|
|
1076
1624
|
async function getTask(taskIdOrOptions) {
|
|
1077
1625
|
const taskId = typeof taskIdOrOptions === "string" ? taskIdOrOptions : taskIdOrOptions.taskId;
|
|
1078
1626
|
const { apiBaseUrl, token } = getAccessToken(typeof taskIdOrOptions === "string" ? undefined : taskIdOrOptions.accessToken);
|
|
1079
|
-
const response = await
|
|
1627
|
+
const response = await reachableFetch(new URL(`${apiBaseUrl}/task/${taskId}`), {
|
|
1080
1628
|
headers: {
|
|
1081
1629
|
Authorization: `Bearer ${token}`
|
|
1082
1630
|
}
|
|
@@ -1085,18 +1633,24 @@ async function getTask(taskIdOrOptions) {
|
|
|
1085
1633
|
throw new Error("Task not found");
|
|
1086
1634
|
}
|
|
1087
1635
|
const taskData = taskSchema.parse(await response.json());
|
|
1636
|
+
const [input, result, nodesData] = await Promise.all([
|
|
1637
|
+
inbound(taskData.input, forbidCallbacks),
|
|
1638
|
+
inbound(taskData.result, observeOnlyCallbacks),
|
|
1639
|
+
Promise.all(taskData.nodesData.map(async ({ alias, data }) => ({
|
|
1640
|
+
alias,
|
|
1641
|
+
data: await inbound(data, observeOnlyCallbacks)
|
|
1642
|
+
})))
|
|
1643
|
+
]);
|
|
1088
1644
|
const context = {
|
|
1089
1645
|
taskId,
|
|
1090
|
-
input
|
|
1091
|
-
throw new Error("input may not have callbacks");
|
|
1092
|
-
}),
|
|
1646
|
+
input,
|
|
1093
1647
|
getNodeData(alias) {
|
|
1094
|
-
return
|
|
1648
|
+
return nodesData.find((d) => d.alias === alias)?.data ?? null;
|
|
1095
1649
|
},
|
|
1096
1650
|
getNodeError(alias) {
|
|
1097
1651
|
return taskData.nodesError.find((d) => d.alias === alias)?.error ?? null;
|
|
1098
1652
|
},
|
|
1099
|
-
result
|
|
1653
|
+
result
|
|
1100
1654
|
};
|
|
1101
1655
|
return {
|
|
1102
1656
|
status: taskData.status,
|
|
@@ -1126,9 +1680,10 @@ export {
|
|
|
1126
1680
|
createTask,
|
|
1127
1681
|
abortTask,
|
|
1128
1682
|
TaskError,
|
|
1683
|
+
RequenceUnreachableError,
|
|
1129
1684
|
RequenceStream,
|
|
1130
1685
|
RequenceFile
|
|
1131
1686
|
};
|
|
1132
1687
|
|
|
1133
|
-
//# debugId=
|
|
1688
|
+
//# debugId=D8638BB13B29F67364756E2164756E21
|
|
1134
1689
|
//# sourceMappingURL=index.js.map
|