deepline 0.1.243 → 0.1.245
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/README.md +1 -1
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +5 -25
- package/dist/bundling-sources/sdk/src/release.ts +25 -26
- package/dist/bundling-sources/sdk/src/types.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/backend.ts +2 -21
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +5 -6
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +6 -13
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +9 -26
- package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +1 -2
- package/dist/bundling-sources/shared_libs/play-runtime/map-row-identity.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +191 -29
- package/dist/bundling-sources/shared_libs/play-runtime/play-latency-trace.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/providers.ts +1 -36
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +2 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/index.ts +0 -7
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +1 -12
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +2 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +5 -15
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +6 -21
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +3 -4
- package/dist/bundling-sources/shared_libs/plays/artifact-kind-guard.ts +16 -29
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +4 -8
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +21 -712
- package/dist/bundling-sources/shared_libs/plays/bundling/limits.ts +1 -18
- package/dist/cli/index.js +28 -71
- package/dist/cli/index.mjs +28 -71
- package/dist/{compiler-manifest-CYcwzSOJ.d.ts → compiler-manifest-DlE7dnRm.d.mts} +2 -8
- package/dist/{compiler-manifest-CYcwzSOJ.d.mts → compiler-manifest-DlE7dnRm.d.ts} +2 -8
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +23 -22
- package/dist/index.mjs +23 -22
- package/dist/plays/bundle-play-file.d.mts +7 -22
- package/dist/plays/bundle-play-file.d.ts +7 -22
- package/dist/plays/bundle-play-file.mjs +26 -614
- package/package.json +2 -2
- package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +0 -4504
- package/dist/bundling-sources/apps/play-runner-workers/src/dedup-do.ts +0 -1386
- package/dist/bundling-sources/apps/play-runner-workers/src/durable-object-deploy-handoff.ts +0 -30
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +0 -8385
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/README.md +0 -21
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +0 -251
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/coordinator-progress.ts +0 -289
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/csv-rows.ts +0 -85
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +0 -23
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/dataset-handles.ts +0 -528
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +0 -229
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/ledger-event-batches.ts +0 -81
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/live-progress.ts +0 -22
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +0 -920
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-latency-profile.ts +0 -90
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/output-datasets.ts +0 -475
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +0 -570
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/result-dataset-persistence.ts +0 -50
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/row-isolation.ts +0 -5
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/run-work-dispatcher.ts +0 -519
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -107
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +0 -2541
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-http-errors.ts +0 -7
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +0 -227
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/work-budget.ts +0 -130
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/worker-platform-budget.ts +0 -39
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/workflow-preview.ts +0 -26
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime-api-retry.ts +0 -23
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-instance-create.ts +0 -47
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry-state.ts +0 -167
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry.ts +0 -91
- package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +0 -329
- package/dist/bundling-sources/sdk/src/worker-play-entry.ts +0 -240
- package/dist/bundling-sources/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +0 -252
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -217
|
@@ -13,7 +13,16 @@ export const TERMINAL_RUN_RESULT_MAX_BYTES = 2_500_000;
|
|
|
13
13
|
* of provider payload — which is durable in scheduler Postgres and never read
|
|
14
14
|
* back from Convex, yet deterministically wedged the append.
|
|
15
15
|
*/
|
|
16
|
-
|
|
16
|
+
// The terminal projection is persisted twice on `playRuns` (top-level result
|
|
17
|
+
// and runSnapshot.result), in addition to the event document. Keep one copy at
|
|
18
|
+
// 256 KiB so ordinary snapshots retain headroom under Convex's 1 MiB document
|
|
19
|
+
// ceiling. The runtime route has a reference-only fallback for an unusually
|
|
20
|
+
// large pre-existing snapshot that still exceeds the aggregate document cap.
|
|
21
|
+
export const LEDGER_TERMINAL_RESULT_MAX_BYTES = 256 * 1024;
|
|
22
|
+
export const LEDGER_TERMINAL_RESULT_MAX_DEPTH = 10;
|
|
23
|
+
export const CONVEX_LEDGER_ARRAY_MAX_ITEMS = 8_192;
|
|
24
|
+
export const CONVEX_LEDGER_OBJECT_MAX_FIELDS = 1_024;
|
|
25
|
+
export const CONVEX_LEDGER_FIELD_NAME_MAX_LENGTH = 1_024;
|
|
17
26
|
export const CUSTOMER_OUTPUT_VALUE_MAX_BYTES = 1 * 1024 * 1024;
|
|
18
27
|
export const CUSTOMER_OUTPUT_TOTAL_MAX_BYTES = 2 * 1024 * 1024;
|
|
19
28
|
/** Inline Postgres receipt contract: one serialized output is at most 10 MiB. */
|
|
@@ -121,13 +130,183 @@ export type LedgerTerminalResultRef = {
|
|
|
121
130
|
key: 'terminal_result_json';
|
|
122
131
|
/** Serialized byte size of the result that was elided from the ledger. */
|
|
123
132
|
bytes: number;
|
|
124
|
-
reason:
|
|
133
|
+
reason: LedgerTerminalResultRefReason;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export type LedgerTerminalResultRefReason =
|
|
137
|
+
| 'terminal_result_exceeds_ledger_limit'
|
|
138
|
+
| 'terminal_result_exceeds_ledger_depth'
|
|
139
|
+
| 'terminal_result_has_invalid_field_name'
|
|
140
|
+
| 'terminal_result_array_too_long'
|
|
141
|
+
| 'terminal_result_object_too_wide'
|
|
142
|
+
| 'terminal_result_not_json_serializable'
|
|
143
|
+
| 'terminal_result_rejected_by_convex';
|
|
144
|
+
|
|
145
|
+
export type ConvexLedgerPayloadIssue = {
|
|
146
|
+
reason:
|
|
147
|
+
| 'size_limit'
|
|
148
|
+
| 'depth_limit'
|
|
149
|
+
| 'invalid_field_name'
|
|
150
|
+
| 'array_too_long'
|
|
151
|
+
| 'object_too_wide'
|
|
152
|
+
| 'not_json_serializable';
|
|
153
|
+
bytes?: number;
|
|
125
154
|
};
|
|
126
155
|
|
|
127
156
|
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
128
157
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
129
158
|
}
|
|
130
159
|
|
|
160
|
+
function isConvexFieldName(value: string): boolean {
|
|
161
|
+
if (
|
|
162
|
+
value.length > CONVEX_LEDGER_FIELD_NAME_MAX_LENGTH ||
|
|
163
|
+
value.startsWith('$')
|
|
164
|
+
) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
168
|
+
const code = value.charCodeAt(index);
|
|
169
|
+
if (code < 32 || code >= 127) return false;
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Validate the part of Convex's value contract that can permanently poison a
|
|
176
|
+
* durable run-ledger append. The walk is iterative and stops at the depth
|
|
177
|
+
* boundary, so adversarial nesting cannot overflow the JS stack while being
|
|
178
|
+
* classified. It intentionally returns no path or customer field name.
|
|
179
|
+
*/
|
|
180
|
+
export function inspectConvexLedgerPayload(
|
|
181
|
+
value: unknown,
|
|
182
|
+
): ConvexLedgerPayloadIssue | null {
|
|
183
|
+
const stack: Array<{ value: unknown; depth: number }> = [
|
|
184
|
+
{
|
|
185
|
+
value,
|
|
186
|
+
depth: value !== null && typeof value === 'object' ? 1 : 0,
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
while (stack.length > 0) {
|
|
191
|
+
const current = stack.pop()!;
|
|
192
|
+
if (current.depth > LEDGER_TERMINAL_RESULT_MAX_DEPTH) {
|
|
193
|
+
return { reason: 'depth_limit' };
|
|
194
|
+
}
|
|
195
|
+
if (Array.isArray(current.value)) {
|
|
196
|
+
if (current.value.length > CONVEX_LEDGER_ARRAY_MAX_ITEMS) {
|
|
197
|
+
return { reason: 'array_too_long' };
|
|
198
|
+
}
|
|
199
|
+
for (const item of current.value) {
|
|
200
|
+
stack.push({
|
|
201
|
+
value: item,
|
|
202
|
+
depth:
|
|
203
|
+
item !== null && typeof item === 'object'
|
|
204
|
+
? current.depth + 1
|
|
205
|
+
: current.depth,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (!current.value || typeof current.value !== 'object') continue;
|
|
211
|
+
|
|
212
|
+
const entries = Object.entries(current.value as Record<string, unknown>);
|
|
213
|
+
if (entries.length > CONVEX_LEDGER_OBJECT_MAX_FIELDS) {
|
|
214
|
+
return { reason: 'object_too_wide' };
|
|
215
|
+
}
|
|
216
|
+
for (const [key, entry] of entries) {
|
|
217
|
+
if (!isConvexFieldName(key)) {
|
|
218
|
+
return { reason: 'invalid_field_name' };
|
|
219
|
+
}
|
|
220
|
+
stack.push({
|
|
221
|
+
value: entry,
|
|
222
|
+
depth:
|
|
223
|
+
entry !== null && typeof entry === 'object'
|
|
224
|
+
? current.depth + 1
|
|
225
|
+
: current.depth,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
const bytes = jsonByteLength(value);
|
|
232
|
+
return bytes > LEDGER_TERMINAL_RESULT_MAX_BYTES
|
|
233
|
+
? { reason: 'size_limit', bytes }
|
|
234
|
+
: null;
|
|
235
|
+
} catch {
|
|
236
|
+
return { reason: 'not_json_serializable' };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function isLedgerTerminalResultRef(
|
|
241
|
+
value: unknown,
|
|
242
|
+
): value is LedgerTerminalResultRef {
|
|
243
|
+
return (
|
|
244
|
+
isPlainObject(value) &&
|
|
245
|
+
value.__kind === 'deepline.ledger_terminal_result_ref.v1' &&
|
|
246
|
+
value.store === 'scheduler_postgres' &&
|
|
247
|
+
value.key === 'terminal_result_json'
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function stripReplayOnlyTerminalResult(value: unknown): unknown {
|
|
252
|
+
if (!isPlainObject(value) || isLedgerTerminalResultRef(value)) return value;
|
|
253
|
+
const stripped: Record<string, unknown> = {};
|
|
254
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
255
|
+
if (
|
|
256
|
+
(LEDGER_STRIPPED_TERMINAL_RESULT_KEYS as readonly string[]).includes(key)
|
|
257
|
+
) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
stripped[key] = entry;
|
|
261
|
+
}
|
|
262
|
+
return stripped;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function refReasonForIssue(
|
|
266
|
+
issue: ConvexLedgerPayloadIssue['reason'],
|
|
267
|
+
): LedgerTerminalResultRefReason {
|
|
268
|
+
switch (issue) {
|
|
269
|
+
case 'size_limit':
|
|
270
|
+
return 'terminal_result_exceeds_ledger_limit';
|
|
271
|
+
case 'depth_limit':
|
|
272
|
+
return 'terminal_result_exceeds_ledger_depth';
|
|
273
|
+
case 'invalid_field_name':
|
|
274
|
+
return 'terminal_result_has_invalid_field_name';
|
|
275
|
+
case 'array_too_long':
|
|
276
|
+
return 'terminal_result_array_too_long';
|
|
277
|
+
case 'object_too_wide':
|
|
278
|
+
return 'terminal_result_object_too_wide';
|
|
279
|
+
case 'not_json_serializable':
|
|
280
|
+
return 'terminal_result_not_json_serializable';
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function ledgerTerminalResultRefForValue(
|
|
285
|
+
value: unknown,
|
|
286
|
+
reason: LedgerTerminalResultRefReason,
|
|
287
|
+
): LedgerTerminalResultRef {
|
|
288
|
+
let bytes = 0;
|
|
289
|
+
try {
|
|
290
|
+
bytes = jsonByteLength(value);
|
|
291
|
+
} catch {
|
|
292
|
+
// The bounded reason is the useful diagnostic. Never serialize the
|
|
293
|
+
// customer payload again merely to populate reference metadata.
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
__kind: 'deepline.ledger_terminal_result_ref.v1',
|
|
297
|
+
store: 'scheduler_postgres',
|
|
298
|
+
key: 'terminal_result_json',
|
|
299
|
+
bytes,
|
|
300
|
+
reason,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Optional derived summaries must never block the terminal lifecycle event. */
|
|
305
|
+
export function ledgerSummaryForLedger(value: unknown): unknown {
|
|
306
|
+
if (value === undefined || value === null) return value;
|
|
307
|
+
return inspectConvexLedgerPayload(value) ? undefined : value;
|
|
308
|
+
}
|
|
309
|
+
|
|
131
310
|
/**
|
|
132
311
|
* Shape a terminal run result for the Convex run ledger. Control-plane only:
|
|
133
312
|
*
|
|
@@ -138,40 +317,23 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
|
138
317
|
* the durable scheduler copy, so the ledger event stays small and the
|
|
139
318
|
* Convex append cannot wedge on an oversized/over-nested document.
|
|
140
319
|
*
|
|
141
|
-
*
|
|
142
|
-
* Postgres
|
|
320
|
+
* Any result accepted by the existing terminal persistence contract remains
|
|
321
|
+
* durable in scheduler Postgres; this only governs what the ledger embeds.
|
|
143
322
|
*/
|
|
144
323
|
export function terminalRunResultForLedger(value: unknown): unknown {
|
|
145
324
|
if (value === undefined || value === null) {
|
|
146
325
|
return value;
|
|
147
326
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
(LEDGER_STRIPPED_TERMINAL_RESULT_KEYS as readonly string[]).includes(
|
|
154
|
-
key,
|
|
155
|
-
)
|
|
156
|
-
) {
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
stripped[key] = entry;
|
|
160
|
-
}
|
|
161
|
-
candidate = stripped;
|
|
162
|
-
}
|
|
163
|
-
const bytes = jsonByteLength(candidate);
|
|
164
|
-
if (bytes <= LEDGER_TERMINAL_RESULT_MAX_BYTES) {
|
|
327
|
+
if (isLedgerTerminalResultRef(value)) return value;
|
|
328
|
+
const candidate = stripReplayOnlyTerminalResult(value);
|
|
329
|
+
const issue = inspectConvexLedgerPayload(candidate);
|
|
330
|
+
if (!issue) {
|
|
165
331
|
return candidate;
|
|
166
332
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
bytes,
|
|
172
|
-
reason: 'terminal_result_exceeds_ledger_limit',
|
|
173
|
-
};
|
|
174
|
-
return ref;
|
|
333
|
+
return ledgerTerminalResultRefForValue(
|
|
334
|
+
candidate,
|
|
335
|
+
refReasonForIssue(issue.reason),
|
|
336
|
+
);
|
|
175
337
|
}
|
|
176
338
|
|
|
177
339
|
export function assertCustomerOutputValueWithinLimit(input: {
|
|
@@ -107,7 +107,7 @@ export const PLAY_LATENCY_SUMMARY_COLUMNS: PlayLatencyPhaseDefinition[] = [
|
|
|
107
107
|
header: 'route_child',
|
|
108
108
|
phase: 'server.start_route_resolve_child_manifests',
|
|
109
109
|
source: 'server',
|
|
110
|
-
description: 'Start route child play manifest resolution
|
|
110
|
+
description: 'Start route child play manifest resolution.',
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
header: 'route_active',
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
} from './scheduler-backend';
|
|
12
12
|
|
|
13
13
|
export const PLAY_RUNTIME_PROVIDER_IDS = {
|
|
14
|
-
workersEdge: 'workers_edge',
|
|
15
14
|
absurd: 'absurd',
|
|
16
15
|
} as const;
|
|
17
16
|
|
|
@@ -27,34 +26,10 @@ export type PlayRuntimeProviderDescriptor = {
|
|
|
27
26
|
label: string;
|
|
28
27
|
};
|
|
29
28
|
|
|
30
|
-
export const PLAY_RUNTIME_PROVIDER_DISABLED_CODE =
|
|
31
|
-
'PLAY_RUNTIME_PROVIDER_DISABLED' as const;
|
|
32
|
-
|
|
33
|
-
export class PlayRuntimeProviderDisabledError extends Error {
|
|
34
|
-
readonly code = PLAY_RUNTIME_PROVIDER_DISABLED_CODE;
|
|
35
|
-
readonly profile: PlayRuntimeProviderId;
|
|
36
|
-
|
|
37
|
-
constructor(profile: PlayRuntimeProviderId) {
|
|
38
|
-
super(
|
|
39
|
-
`Play runtime profile "${profile}" is disabled. Deepline runs now execute on the "absurd" profile.`,
|
|
40
|
-
);
|
|
41
|
-
this.name = 'PlayRuntimeProviderDisabledError';
|
|
42
|
-
this.profile = profile;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
29
|
export const PLAY_RUNTIME_PROVIDERS: Record<
|
|
47
30
|
PlayRuntimeProviderId,
|
|
48
31
|
PlayRuntimeProviderDescriptor
|
|
49
32
|
> = {
|
|
50
|
-
workers_edge: {
|
|
51
|
-
id: PLAY_RUNTIME_PROVIDER_IDS.workersEdge,
|
|
52
|
-
scheduler: PLAY_SCHEDULER_BACKENDS.cfWorkflows,
|
|
53
|
-
runner: PLAY_RUNTIME_BACKENDS.cloudflareWorkers,
|
|
54
|
-
dedup: PLAY_DEDUP_BACKENDS.durableObject,
|
|
55
|
-
artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
|
|
56
|
-
label: 'Cloudflare Dynamic Workflows + Dynamic Workers + DO dedup',
|
|
57
|
-
},
|
|
58
33
|
absurd: {
|
|
59
34
|
id: PLAY_RUNTIME_PROVIDER_IDS.absurd,
|
|
60
35
|
scheduler: PLAY_SCHEDULER_BACKENDS.absurd,
|
|
@@ -73,14 +48,6 @@ export function defaultPlayRuntimeProvider(): PlayRuntimeProviderDescriptor {
|
|
|
73
48
|
return PLAY_RUNTIME_PROVIDERS.absurd;
|
|
74
49
|
}
|
|
75
50
|
|
|
76
|
-
export function assertPlayRuntimeProviderEnabled(
|
|
77
|
-
provider: PlayRuntimeProviderDescriptor,
|
|
78
|
-
): void {
|
|
79
|
-
if (provider.id === PLAY_RUNTIME_PROVIDER_IDS.workersEdge) {
|
|
80
|
-
throw new PlayRuntimeProviderDisabledError(provider.id);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
51
|
export function resolvePlayRuntimeProvider(
|
|
85
52
|
override?: string | null,
|
|
86
53
|
): PlayRuntimeProviderDescriptor {
|
|
@@ -101,7 +68,5 @@ export function resolvePlayRuntimeProvider(
|
|
|
101
68
|
export function resolveEnabledPlayRuntimeProvider(
|
|
102
69
|
override?: string | null,
|
|
103
70
|
): PlayRuntimeProviderDescriptor {
|
|
104
|
-
|
|
105
|
-
assertPlayRuntimeProviderEnabled(provider);
|
|
106
|
-
return provider;
|
|
71
|
+
return resolvePlayRuntimeProvider(override);
|
|
107
72
|
}
|
|
@@ -35,8 +35,7 @@ export type PlayRunLedgerEventSource =
|
|
|
35
35
|
/**
|
|
36
36
|
* Live progress for a single step/node.
|
|
37
37
|
*
|
|
38
|
-
* Verified producer semantics
|
|
39
|
-
* `apps/play-runner-workers/src/entry.ts`):
|
|
38
|
+
* Verified map-executor producer semantics:
|
|
40
39
|
*
|
|
41
40
|
* - `completed` counts SUCCESSFULLY written rows ONLY, never failures/skips.
|
|
42
41
|
* In-flight it is `min(total, totalRowsWritten + completedExecutedRows)`
|
|
@@ -969,7 +968,7 @@ function retryablePlatformDeployFailureSnapshot(
|
|
|
969
968
|
// failure isolation). Forcing `completed = total` here would fabricate
|
|
970
969
|
// successes that never happened and falsify the persisted counts. The truthful
|
|
971
970
|
// terminal counts are carried by the producer's final reconciled bump, which
|
|
972
|
-
// the
|
|
971
|
+
// the finalize path drains BEFORE emitting step.completed
|
|
973
972
|
// (entry.ts finalize ordering invariant). This settle path is the last-resort
|
|
974
973
|
// heal for the missing-final-bump case, where the honest thing is "we know it
|
|
975
974
|
// stopped, we do not know it fully succeeded" — leave the last observed
|
|
@@ -13,13 +13,6 @@ export function resolvePlayRunnerBackend(
|
|
|
13
13
|
const backend = normalizePlayRuntimeBackend(
|
|
14
14
|
backendId ?? process.env.DEEPLINE_PLAY_RUNNER_BACKEND,
|
|
15
15
|
);
|
|
16
|
-
if (backend === PLAY_RUNTIME_BACKENDS.cloudflareWorkers) {
|
|
17
|
-
throw new Error(
|
|
18
|
-
'The Cloudflare runner-only backend has been retired. Pass ' +
|
|
19
|
-
'`body.profile=workers_edge` on POST /api/v2/plays/run to use the ' +
|
|
20
|
-
'Cloudflare scheduler/runner profile.',
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
16
|
if (backend === PLAY_RUNTIME_BACKENDS.daytona) {
|
|
24
17
|
return daytonaPlayRunnerBackend;
|
|
25
18
|
}
|
|
@@ -91,7 +91,6 @@ import {
|
|
|
91
91
|
resolveMapRowOutcomeKey,
|
|
92
92
|
} from './map-row-outcome';
|
|
93
93
|
import { DEEPLINE_CELL_META_FIELD } from './cell-staleness';
|
|
94
|
-
import type { PlayArtifactKind } from './backend';
|
|
95
94
|
import {
|
|
96
95
|
PLAY_RUNTIME_CONTRACT,
|
|
97
96
|
PLAY_RUNTIME_CONTRACT_HEADER,
|
|
@@ -439,14 +438,6 @@ type RuntimeApiActionRequest =
|
|
|
439
438
|
| {
|
|
440
439
|
action: 'resolve_play';
|
|
441
440
|
playRef: string;
|
|
442
|
-
/**
|
|
443
|
-
* Artifact kind the caller can execute. Node runners (postgres
|
|
444
|
-
* scheduler inline executor, Daytona/local-process) request
|
|
445
|
-
* `cjs_node20` so a child published with an esm_workers artifact is
|
|
446
|
-
* re-bundled server-side into a `Module._compile`-loadable module.
|
|
447
|
-
* Omitted = the stored artifact is returned verbatim.
|
|
448
|
-
*/
|
|
449
|
-
artifactKind?: PlayArtifactKind;
|
|
450
441
|
}
|
|
451
442
|
| {
|
|
452
443
|
action: 'ensure_sheet';
|
|
@@ -2964,7 +2955,6 @@ async function writeRuntimeRows(
|
|
|
2964
2955
|
export async function resolveRuntimeReferencedPlay(
|
|
2965
2956
|
context: RuntimeApiContext,
|
|
2966
2957
|
playRef: string,
|
|
2967
|
-
options?: { artifactKind?: PlayArtifactKind },
|
|
2968
2958
|
): Promise<ResolvedRuntimePlay | null> {
|
|
2969
2959
|
const response = await postRuntimeApi<{
|
|
2970
2960
|
play: ResolvedRuntimePlay | null;
|
|
@@ -2972,7 +2962,6 @@ export async function resolveRuntimeReferencedPlay(
|
|
|
2972
2962
|
}>(context, {
|
|
2973
2963
|
action: 'resolve_play',
|
|
2974
2964
|
playRef,
|
|
2975
|
-
...(options?.artifactKind ? { artifactKind: options.artifactKind } : {}),
|
|
2976
2965
|
});
|
|
2977
2966
|
if (!response.play) {
|
|
2978
2967
|
return null;
|
|
@@ -7235,7 +7224,7 @@ async function failRuntimeMapRowChunks(
|
|
|
7235
7224
|
* field values that completed before the error — see
|
|
7236
7225
|
* `failRuntimeMapRowChunks` for the recovery contract.
|
|
7237
7226
|
*
|
|
7238
|
-
* Used by
|
|
7227
|
+
* Used by `persistCompletedMapRows` so map
|
|
7239
7228
|
* completion writes go through the shared runtime storage plane and skip the
|
|
7240
7229
|
* per-chunk Vercel hop.
|
|
7241
7230
|
*/
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* pg-backed Pool factory. Installed at boot by the Node
|
|
3
|
-
*
|
|
4
|
-
* raw TCP socket usage is banned in workerd.
|
|
2
|
+
* pg-backed Pool factory. Installed at boot by the Node play runner
|
|
3
|
+
* (Daytona/local).
|
|
5
4
|
*/
|
|
6
5
|
import { Pool, type PoolClient } from 'pg';
|
|
7
6
|
import {
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Driver-agnostic Postgres pool/client surface used by the runtime data plane.
|
|
3
3
|
*
|
|
4
|
-
* The runtime
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - Cloudflare Workers (workers_edge harness) — `pg` cannot bundle (raw TCP
|
|
9
|
-
* is banned at workerd boundary), so we use `@neondatabase/serverless`
|
|
10
|
-
* which speaks the same Postgres wire protocol over a WebSocket proxy.
|
|
11
|
-
*
|
|
12
|
-
* Rather than `if-platform` branches inside runtime-api.ts, each runtime
|
|
13
|
-
* registers its driver once at boot and the rest of the code uses the
|
|
14
|
-
* abstract `RuntimePool` / `RuntimePoolClient` types. Both `pg` and
|
|
15
|
-
* `@neondatabase/serverless` already expose the relevant subset of the
|
|
16
|
-
* `pg` API surface (`pool.connect()` → `client.query() / .release()`), so
|
|
4
|
+
* The Node runtime registers its `pg` driver once at boot and the rest of the
|
|
5
|
+
* data plane uses the abstract `RuntimePool` / `RuntimePoolClient` types. `pg`
|
|
6
|
+
* exposes the relevant API surface (`pool.connect()` → `client.query() /
|
|
7
|
+
* .release()`), so
|
|
17
8
|
* the wrappers are thin.
|
|
18
9
|
*/
|
|
19
10
|
|
|
@@ -143,8 +134,7 @@ export function createRuntimePool(input: {
|
|
|
143
134
|
if (!poolFactory) {
|
|
144
135
|
throw new Error(
|
|
145
136
|
'No runtime Postgres pool factory registered. Call ' +
|
|
146
|
-
'installPgRuntimePoolDriver()
|
|
147
|
-
'installNeonServerlessRuntimePoolDriver() (Workers) at boot before ' +
|
|
137
|
+
'installPgRuntimePoolDriver() at boot before ' +
|
|
148
138
|
'using runtime-api Postgres helpers.',
|
|
149
139
|
);
|
|
150
140
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scheduler-backend interface — owns play workflow lifecycle.
|
|
3
3
|
*
|
|
4
|
-
* One of
|
|
4
|
+
* One of two pluggable axes (alongside runner-backends and dedup-backends).
|
|
5
5
|
* Selected per-run via PlayExecutionProfile.
|
|
6
6
|
*
|
|
7
|
-
* Absurd is the
|
|
8
|
-
*
|
|
9
|
-
* launch admission is disabled.
|
|
7
|
+
* Absurd is the only durable production scheduler. In-process exists only for
|
|
8
|
+
* focused local execution.
|
|
10
9
|
*
|
|
11
10
|
* Customer plays are unaffected — this is purely the orchestration layer.
|
|
12
11
|
*/
|
|
@@ -24,9 +23,6 @@ import type { RuntimeTestPolicyOverrides } from './test-runtime-seams';
|
|
|
24
23
|
import type { PlayRunInputPayload } from './play-input';
|
|
25
24
|
|
|
26
25
|
export const PLAY_SCHEDULER_BACKENDS = {
|
|
27
|
-
cfWorkflows: 'cf-workflows',
|
|
28
|
-
/** Private legacy id retained only so old persisted rows can be interpreted. */
|
|
29
|
-
postgres: 'postgres',
|
|
30
26
|
/**
|
|
31
27
|
* Postgres-native durable-execution scheduler (vendored Absurd engine). Runs
|
|
32
28
|
* on the battle-tested run-state store without an external workflow engine.
|
|
@@ -47,10 +43,7 @@ export type PlaySchedulerSubmitInput = {
|
|
|
47
43
|
playName: string;
|
|
48
44
|
workflowFamilyKey?: string | null;
|
|
49
45
|
artifactStorageKey: string;
|
|
50
|
-
/**
|
|
51
|
-
* Optional inline artifact for node-compatible schedulers. Workers-edge
|
|
52
|
-
* schedulers use artifactStorageKey plus dynamicWorkerCode instead.
|
|
53
|
-
*/
|
|
46
|
+
/** Optional inline artifact for the Node scheduler. */
|
|
54
47
|
runtimeArtifact?: unknown;
|
|
55
48
|
artifactHash: string;
|
|
56
49
|
graphHash: string;
|
|
@@ -99,8 +92,6 @@ export type PlaySchedulerSubmitInput = {
|
|
|
99
92
|
* this field for DB-session unwrap and the re-minted `executorToken` for auth.
|
|
100
93
|
*/
|
|
101
94
|
preloadedDbSessionUnwrapKey?: string | null;
|
|
102
|
-
/** Optional immutable Worker module source for local Dynamic Worker loading. */
|
|
103
|
-
dynamicWorkerCode?: string | null;
|
|
104
95
|
executorToken: string;
|
|
105
96
|
/** Immutable facts used by durable schedulers to mint a fresh leg token. */
|
|
106
97
|
runtimeAuthority: RuntimeAuthorityDescriptor;
|
|
@@ -226,10 +217,7 @@ export function normalizePlaySchedulerBackend(
|
|
|
226
217
|
): PlaySchedulerBackendId {
|
|
227
218
|
const normalized = value?.trim().toLowerCase();
|
|
228
219
|
if (!normalized) {
|
|
229
|
-
return PLAY_SCHEDULER_BACKENDS.
|
|
230
|
-
}
|
|
231
|
-
if (normalized === 'cf-workflows' || normalized === 'cf_workflows') {
|
|
232
|
-
return PLAY_SCHEDULER_BACKENDS.cfWorkflows;
|
|
220
|
+
return PLAY_SCHEDULER_BACKENDS.absurd;
|
|
233
221
|
}
|
|
234
222
|
if (normalized === 'absurd' || normalized === 'absurd-scheduler') {
|
|
235
223
|
return PLAY_SCHEDULER_BACKENDS.absurd;
|
|
@@ -238,9 +226,6 @@ export function normalizePlaySchedulerBackend(
|
|
|
238
226
|
return PLAY_SCHEDULER_BACKENDS.inProcess;
|
|
239
227
|
}
|
|
240
228
|
throw new Error(
|
|
241
|
-
`Unsupported scheduler backend "${normalized}". Expected one of: ${
|
|
242
|
-
PLAY_SCHEDULER_BACKENDS.cfWorkflows,
|
|
243
|
-
PLAY_SCHEDULER_BACKENDS.absurd,
|
|
244
|
-
].join(', ')}.`,
|
|
229
|
+
`Unsupported scheduler backend "${normalized}". Expected one of: ${PLAY_SCHEDULER_BACKENDS.absurd}, ${PLAY_SCHEDULER_BACKENDS.inProcess}.`,
|
|
245
230
|
);
|
|
246
231
|
}
|
|
@@ -117,9 +117,7 @@ function adaptV2ExecuteResponseToToolResult(data: Record<string, unknown>): {
|
|
|
117
117
|
* Parsed view of a raw `/api/v2/integrations/:toolId/execute` JSON body.
|
|
118
118
|
*
|
|
119
119
|
* This is the single runtime-side seam from a V2 execute response to the
|
|
120
|
-
* inputs of {@link createToolExecuteResult}.
|
|
121
|
-
* in-process cjs runtime in `shared_libs/play-runtime/context.ts` and the
|
|
122
|
-
* Workers runtime in `apps/play-runner-workers`) must go through
|
|
120
|
+
* inputs of {@link createToolExecuteResult}. The CJS runtime must go through
|
|
123
121
|
* {@link parseToolExecuteResponse}; the intermediate envelope shapes
|
|
124
122
|
* (`toolResponse` adaptation, `_metadata.tool` parsing, status derivation)
|
|
125
123
|
* are private to this module.
|
|
@@ -1322,7 +1320,8 @@ function rememberLiveToolResultListDataset(
|
|
|
1322
1320
|
liveToolResultListDatasets.delete(datasetId);
|
|
1323
1321
|
liveToolResultListDatasets.set(datasetId, dataset);
|
|
1324
1322
|
while (
|
|
1325
|
-
liveToolResultListDatasets.size >
|
|
1323
|
+
liveToolResultListDatasets.size >
|
|
1324
|
+
LIVE_TOOL_RESULT_LIST_DATASET_REGISTRY_LIMIT
|
|
1326
1325
|
) {
|
|
1327
1326
|
const oldest = liveToolResultListDatasets.keys().next().value;
|
|
1328
1327
|
if (typeof oldest !== 'string') break;
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import type { PlayArtifactKind, PlayBundleArtifact } from './artifact-types';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Loud
|
|
5
|
-
*
|
|
4
|
+
* Loud guard that stops a historical or malformed non-CJS bundle from
|
|
5
|
+
* reaching a Node/Daytona (`cjs_node20`) runner.
|
|
6
6
|
*
|
|
7
7
|
* The Node runner loads play code with `Module._compile`, which cannot resolve
|
|
8
8
|
* `cloudflare:workers` scheme imports and dies with the opaque
|
|
9
9
|
* `ERR_UNSUPPORTED_ESM_URL_SCHEME: Received protocol 'cloudflare:'`. Those
|
|
10
|
-
* imports
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* profile (e.g. the absurd/Daytona scheduler falling back to a verbatim stored
|
|
14
|
-
* `esm_workers` bundle), this guard fires at the targeting/load seam with a
|
|
15
|
-
* message that names the mismatch instead of surfacing the ESM scheme error.
|
|
10
|
+
* imports can remain in historical `esm_workers` artifacts. If one reaches an
|
|
11
|
+
* active launch seam, this guard names the mismatch instead of surfacing the
|
|
12
|
+
* opaque ESM scheme error.
|
|
16
13
|
*/
|
|
17
14
|
|
|
18
15
|
/**
|
|
@@ -20,18 +17,17 @@ import type { PlayArtifactKind, PlayBundleArtifact } from './artifact-types';
|
|
|
20
17
|
* `cjs_node20` (the only kind that existed before the workers split). Mirror the
|
|
21
18
|
* default documented on `PlayBundleArtifact.artifactKind`.
|
|
22
19
|
*/
|
|
23
|
-
export function artifactKindOf(artifact: PlayBundleArtifact):
|
|
24
|
-
|
|
20
|
+
export function artifactKindOf(artifact: PlayBundleArtifact): string {
|
|
21
|
+
const rawKind = (artifact as { artifactKind?: unknown }).artifactKind;
|
|
22
|
+
return typeof rawKind === 'string' && rawKind.trim() ? rawKind : 'cjs_node20';
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
/**
|
|
28
|
-
* Detect `cloudflare:` scheme imports in bundled code. Matches
|
|
29
|
-
*
|
|
30
|
-
* with single or double quotes. This is the exact shape the Node runner cannot
|
|
31
|
-
* load.
|
|
26
|
+
* Detect `cloudflare:` scheme imports in bundled code. Matches static imports,
|
|
27
|
+
* dynamic imports, and require calls with single or double quotes.
|
|
32
28
|
*/
|
|
33
29
|
const CLOUDFLARE_SCHEME_IMPORT =
|
|
34
|
-
/(?:\bfrom\s*|\bimport\s
|
|
30
|
+
/(?:\bfrom\s*|\bimport\s*(?:\(\s*)?|\brequire\s*\(\s*)['"]cloudflare:[^'"]*['"]/;
|
|
35
31
|
|
|
36
32
|
export function bundledCodeHasCloudflareSchemeImport(
|
|
37
33
|
bundledCode: string,
|
|
@@ -41,7 +37,7 @@ export function bundledCodeHasCloudflareSchemeImport(
|
|
|
41
37
|
|
|
42
38
|
export class PlayArtifactKindMismatchError extends Error {
|
|
43
39
|
readonly expectedKind: PlayArtifactKind;
|
|
44
|
-
readonly actualKind:
|
|
40
|
+
readonly actualKind: string;
|
|
45
41
|
readonly reason:
|
|
46
42
|
| 'kind_mismatch'
|
|
47
43
|
| 'code_format_mismatch'
|
|
@@ -49,7 +45,7 @@ export class PlayArtifactKindMismatchError extends Error {
|
|
|
49
45
|
|
|
50
46
|
constructor(input: {
|
|
51
47
|
expectedKind: PlayArtifactKind;
|
|
52
|
-
actualKind:
|
|
48
|
+
actualKind: string;
|
|
53
49
|
reason:
|
|
54
50
|
| 'kind_mismatch'
|
|
55
51
|
| 'code_format_mismatch'
|
|
@@ -80,12 +76,6 @@ export function assertNodeRunnableArtifact(input: {
|
|
|
80
76
|
context: string;
|
|
81
77
|
}): void {
|
|
82
78
|
const { artifact, expectedKind, context } = input;
|
|
83
|
-
if (expectedKind !== 'cjs_node20') {
|
|
84
|
-
// This helper only guards the node runner. A workers-edge target never
|
|
85
|
-
// reaches the Node/Daytona load path, so there is nothing to assert.
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
79
|
const actualKind = artifactKindOf(artifact);
|
|
90
80
|
if (actualKind !== 'cjs_node20') {
|
|
91
81
|
throw new PlayArtifactKindMismatchError({
|
|
@@ -93,12 +83,9 @@ export function assertNodeRunnableArtifact(input: {
|
|
|
93
83
|
actualKind,
|
|
94
84
|
reason: 'kind_mismatch',
|
|
95
85
|
message:
|
|
96
|
-
`Node runner (${context}) received
|
|
97
|
-
`
|
|
98
|
-
`
|
|
99
|
-
`Module._compile. Rebundle/republish the play for the node runner ` +
|
|
100
|
-
`(profile=absurd / backend=daytona|local_process) instead of serving ` +
|
|
101
|
-
`the stored workers artifact verbatim.`,
|
|
86
|
+
`Node runner (${context}) received unsupported play artifact kind ` +
|
|
87
|
+
`"${actualKind}"; only "cjs_node20" is executable. Rebuild and ` +
|
|
88
|
+
`republish the play with the current SDK.`,
|
|
102
89
|
});
|
|
103
90
|
}
|
|
104
91
|
|
|
@@ -23,16 +23,12 @@ export type PlayArtifactCompatibility = {
|
|
|
23
23
|
runtimeBackend?: string | null;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
* - cjs_node20: Daytona / local-process (Node.js)
|
|
29
|
-
* - esm_workers: Cloudflare Workers (V8 isolate)
|
|
30
|
-
*/
|
|
31
|
-
export type PlayArtifactKind = 'cjs_node20' | 'esm_workers';
|
|
26
|
+
/** The only executable Play artifact contract. */
|
|
27
|
+
export type PlayArtifactKind = 'cjs_node20';
|
|
32
28
|
|
|
33
29
|
export type PlayBundleArtifact = {
|
|
34
|
-
codeFormat: 'cjs_module'
|
|
35
|
-
/** Defaults to cjs_node20 when not present
|
|
30
|
+
codeFormat: 'cjs_module';
|
|
31
|
+
/** Defaults to cjs_node20 when not present on legacy Node artifacts. */
|
|
36
32
|
artifactKind?: PlayArtifactKind;
|
|
37
33
|
entryFile: string;
|
|
38
34
|
virtualFilename: string;
|