deepline 0.1.78 → 0.1.80
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/dist/cli/index.js +69 -37
- package/dist/cli/index.mjs +69 -37
- package/dist/index.d.mts +32 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +7 -4
- package/dist/index.mjs +7 -4
- package/dist/repo/apps/play-runner-workers/src/child-play-await.ts +192 -0
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +1320 -1644
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +515 -648
- package/dist/repo/apps/play-runner-workers/src/entry.ts +896 -354
- package/dist/repo/apps/play-runner-workers/src/workflow-retry-state.ts +209 -0
- package/dist/repo/sdk/src/client.ts +9 -2
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/sdk/src/types.ts +5 -0
- package/dist/repo/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +231 -0
- package/dist/repo/shared_libs/play-runtime/governor/governor.ts +376 -0
- package/dist/repo/shared_libs/play-runtime/governor/policy.ts +179 -0
- package/dist/repo/shared_libs/play-runtime/governor/rate-state-backend.ts +87 -0
- package/dist/repo/shared_libs/play-runtime/run-failure.ts +12 -0
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +24 -0
- package/dist/repo/shared_libs/play-runtime/submit-limits.ts +35 -0
- package/dist/repo/shared_libs/plays/bundling/index.ts +4 -12
- package/dist/repo/shared_libs/plays/bundling/limits.ts +29 -0
- package/dist/repo/shared_libs/plays/static-pipeline.ts +314 -1
- package/dist/repo/shared_libs/temporal/constants.ts +38 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -241,10 +241,10 @@ var import_node_path2 = require("path");
|
|
|
241
241
|
|
|
242
242
|
// src/release.ts
|
|
243
243
|
var SDK_RELEASE = {
|
|
244
|
-
version: "0.1.
|
|
244
|
+
version: "0.1.80",
|
|
245
245
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
246
246
|
supportPolicy: {
|
|
247
|
-
latest: "0.1.
|
|
247
|
+
latest: "0.1.80",
|
|
248
248
|
minimumSupported: "0.1.53",
|
|
249
249
|
deprecatedBelow: "0.1.53"
|
|
250
250
|
}
|
|
@@ -881,6 +881,7 @@ var DeeplineClient = class {
|
|
|
881
881
|
params.set("grep", options.grep.trim());
|
|
882
882
|
params.set("grep_mode", options.grepMode ?? "all");
|
|
883
883
|
}
|
|
884
|
+
params.set("compact", options?.compact === true ? "true" : "false");
|
|
884
885
|
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
885
886
|
const res = await this.http.get(
|
|
886
887
|
`/api/v2/tools${suffix}`
|
|
@@ -1436,6 +1437,7 @@ var DeeplineClient = class {
|
|
|
1436
1437
|
if (status) {
|
|
1437
1438
|
params.set("status", status);
|
|
1438
1439
|
}
|
|
1440
|
+
params.set("compact", "true");
|
|
1439
1441
|
const response = await this.http.get(
|
|
1440
1442
|
`/api/v2/runs?${params.toString()}`
|
|
1441
1443
|
);
|
|
@@ -1600,10 +1602,11 @@ var DeeplineClient = class {
|
|
|
1600
1602
|
* @param name - Play name
|
|
1601
1603
|
* @returns Version list (newest first)
|
|
1602
1604
|
*/
|
|
1603
|
-
async listPlayVersions(name) {
|
|
1605
|
+
async listPlayVersions(name, options) {
|
|
1604
1606
|
const encodedName = encodeURIComponent(name);
|
|
1607
|
+
const suffix = options?.full ? "?full=true" : "";
|
|
1605
1608
|
const response = await this.http.get(
|
|
1606
|
-
`/api/v2/plays/${encodedName}/versions`
|
|
1609
|
+
`/api/v2/plays/${encodedName}/versions${suffix}`
|
|
1607
1610
|
);
|
|
1608
1611
|
return response.versions ?? [];
|
|
1609
1612
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -179,10 +179,10 @@ import { join as join2 } from "path";
|
|
|
179
179
|
|
|
180
180
|
// src/release.ts
|
|
181
181
|
var SDK_RELEASE = {
|
|
182
|
-
version: "0.1.
|
|
182
|
+
version: "0.1.80",
|
|
183
183
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
184
184
|
supportPolicy: {
|
|
185
|
-
latest: "0.1.
|
|
185
|
+
latest: "0.1.80",
|
|
186
186
|
minimumSupported: "0.1.53",
|
|
187
187
|
deprecatedBelow: "0.1.53"
|
|
188
188
|
}
|
|
@@ -819,6 +819,7 @@ var DeeplineClient = class {
|
|
|
819
819
|
params.set("grep", options.grep.trim());
|
|
820
820
|
params.set("grep_mode", options.grepMode ?? "all");
|
|
821
821
|
}
|
|
822
|
+
params.set("compact", options?.compact === true ? "true" : "false");
|
|
822
823
|
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
823
824
|
const res = await this.http.get(
|
|
824
825
|
`/api/v2/tools${suffix}`
|
|
@@ -1374,6 +1375,7 @@ var DeeplineClient = class {
|
|
|
1374
1375
|
if (status) {
|
|
1375
1376
|
params.set("status", status);
|
|
1376
1377
|
}
|
|
1378
|
+
params.set("compact", "true");
|
|
1377
1379
|
const response = await this.http.get(
|
|
1378
1380
|
`/api/v2/runs?${params.toString()}`
|
|
1379
1381
|
);
|
|
@@ -1538,10 +1540,11 @@ var DeeplineClient = class {
|
|
|
1538
1540
|
* @param name - Play name
|
|
1539
1541
|
* @returns Version list (newest first)
|
|
1540
1542
|
*/
|
|
1541
|
-
async listPlayVersions(name) {
|
|
1543
|
+
async listPlayVersions(name, options) {
|
|
1542
1544
|
const encodedName = encodeURIComponent(name);
|
|
1545
|
+
const suffix = options?.full ? "?full=true" : "";
|
|
1543
1546
|
const response = await this.http.get(
|
|
1544
|
-
`/api/v2/plays/${encodedName}/versions`
|
|
1547
|
+
`/api/v2/plays/${encodedName}/versions${suffix}`
|
|
1545
1548
|
);
|
|
1546
1549
|
return response.versions ?? [];
|
|
1547
1550
|
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Child-play terminal await — the race between a Cloudflare Workflow
|
|
3
|
+
* `waitForEvent('child_play_terminal:...')` and a coordinator terminal-state
|
|
4
|
+
* poll, extracted from entry.ts so the runtime keeps a small, testable surface
|
|
5
|
+
* for "block until this child run reaches a terminal state".
|
|
6
|
+
*
|
|
7
|
+
* Behavior is identical to the inline implementation it replaces: arm the
|
|
8
|
+
* workflow event wait, race it against `pollParentChildTerminalState`, and
|
|
9
|
+
* resolve on whichever reports the child's terminal status first. The poll
|
|
10
|
+
* never resolves on a non-terminal/absent state (it returns a never-settling
|
|
11
|
+
* promise on timeout) so the event wait remains the primary path and the poll
|
|
12
|
+
* is a coordinator-side safety net for missed signals.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export type WorkflowStepLike = {
|
|
16
|
+
waitForEvent: (
|
|
17
|
+
name: string,
|
|
18
|
+
options: { type: string; timeout: string },
|
|
19
|
+
) => Promise<{ payload: unknown }>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ChildTerminalCoordinator = {
|
|
23
|
+
readChildTerminalState(
|
|
24
|
+
parentRunId: string,
|
|
25
|
+
eventKey: string,
|
|
26
|
+
timeoutMs?: number,
|
|
27
|
+
): Promise<{ data?: unknown } | null>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type ChildPlayTerminalWaitResult = {
|
|
31
|
+
output: unknown;
|
|
32
|
+
source: 'workflow_event' | 'parent_child_terminal_cache';
|
|
33
|
+
attempts?: number;
|
|
34
|
+
waitMs: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export interface AwaitChildTerminalInput {
|
|
38
|
+
parentRunId: string;
|
|
39
|
+
workflowStep: WorkflowStepLike | undefined;
|
|
40
|
+
workflowId: string;
|
|
41
|
+
playName: string;
|
|
42
|
+
key: string;
|
|
43
|
+
timeoutMs: number;
|
|
44
|
+
/** Coordinator binding for the terminal-state poll. Null disables the poll. */
|
|
45
|
+
coordinator: ChildTerminalCoordinator | null;
|
|
46
|
+
now: () => number;
|
|
47
|
+
/** SHA-256 hex digest helper (same canonical hash entry.ts uses). */
|
|
48
|
+
hashJson: (value: unknown) => Promise<string>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
52
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function workflowEventType(name: string): string {
|
|
56
|
+
const normalized = name
|
|
57
|
+
.trim()
|
|
58
|
+
.replace(/[^A-Za-z0-9_-]+/g, '_')
|
|
59
|
+
.replace(/^_+|_+$/g, '')
|
|
60
|
+
.slice(0, 100);
|
|
61
|
+
return normalized || 'deepline_event';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function integrationEventType(eventKey: string): string {
|
|
65
|
+
return workflowEventType(`integration_event_${eventKey}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function workflowTimeoutFromMs(timeoutMs: number): string {
|
|
69
|
+
const seconds = Math.max(1, Math.ceil(timeoutMs / 1000));
|
|
70
|
+
return `${seconds} second${seconds === 1 ? '' : 's'}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function readChildTerminalPayload(value: unknown): Record<string, unknown> {
|
|
74
|
+
if (!isRecord(value)) return {};
|
|
75
|
+
const data = value.data;
|
|
76
|
+
return isRecord(data) ? data : value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function extractChildPlayOutput(status: Record<string, unknown>): unknown {
|
|
80
|
+
const result = status.result;
|
|
81
|
+
if (isRecord(result) && 'output' in result) {
|
|
82
|
+
return result.output;
|
|
83
|
+
}
|
|
84
|
+
return result ?? null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function childPlayEventKey(input: {
|
|
88
|
+
key: string;
|
|
89
|
+
workflowId: string;
|
|
90
|
+
hashJson: (value: unknown) => Promise<string>;
|
|
91
|
+
}): Promise<string> {
|
|
92
|
+
const readableKey = workflowEventType(input.key).slice(0, 40);
|
|
93
|
+
const digest = (
|
|
94
|
+
await input.hashJson({ key: input.key, workflowId: input.workflowId })
|
|
95
|
+
).slice(0, 32);
|
|
96
|
+
return `child_play_${digest}_${readableKey}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function pollParentChildTerminalState(input: {
|
|
100
|
+
coordinator: ChildTerminalCoordinator | null;
|
|
101
|
+
parentRunId: string;
|
|
102
|
+
eventKey: string;
|
|
103
|
+
timeoutMs: number;
|
|
104
|
+
now: () => number;
|
|
105
|
+
}): Promise<{
|
|
106
|
+
source: 'parent_child_terminal_cache';
|
|
107
|
+
payload: Record<string, unknown>;
|
|
108
|
+
attempts: number;
|
|
109
|
+
}> {
|
|
110
|
+
const { coordinator, parentRunId } = input;
|
|
111
|
+
if (!coordinator?.readChildTerminalState || !parentRunId) {
|
|
112
|
+
return await new Promise(() => undefined);
|
|
113
|
+
}
|
|
114
|
+
const startedAt = input.now();
|
|
115
|
+
let attempts = 0;
|
|
116
|
+
while (input.now() - startedAt < input.timeoutMs) {
|
|
117
|
+
attempts += 1;
|
|
118
|
+
const remainingMs = Math.max(
|
|
119
|
+
0,
|
|
120
|
+
input.timeoutMs - (input.now() - startedAt),
|
|
121
|
+
);
|
|
122
|
+
const waitMs = Math.min(remainingMs, 30_000);
|
|
123
|
+
const state = await coordinator
|
|
124
|
+
.readChildTerminalState(parentRunId, input.eventKey, waitMs)
|
|
125
|
+
.catch(() => null);
|
|
126
|
+
if (isRecord(state?.data)) {
|
|
127
|
+
return {
|
|
128
|
+
source: 'parent_child_terminal_cache',
|
|
129
|
+
payload: state.data,
|
|
130
|
+
attempts,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return await new Promise(() => undefined);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Block until the child run reaches a terminal state, via the workflow event
|
|
139
|
+
* wait raced against the coordinator terminal-state poll. Throws on a non-
|
|
140
|
+
* completed terminal status.
|
|
141
|
+
*/
|
|
142
|
+
export async function awaitChildTerminal(
|
|
143
|
+
input: AwaitChildTerminalInput,
|
|
144
|
+
): Promise<ChildPlayTerminalWaitResult> {
|
|
145
|
+
if (!input.workflowStep) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
'ctx.runPlay child waits require the cf-workflows runtime event scheduler.',
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const waitStartedAt = input.now();
|
|
151
|
+
const eventKey = await childPlayEventKey({
|
|
152
|
+
key: input.key,
|
|
153
|
+
workflowId: input.workflowId,
|
|
154
|
+
hashJson: input.hashJson,
|
|
155
|
+
});
|
|
156
|
+
const eventPromise = input.workflowStep
|
|
157
|
+
.waitForEvent(`child_play_terminal:${eventKey}`, {
|
|
158
|
+
type: integrationEventType(eventKey),
|
|
159
|
+
timeout: workflowTimeoutFromMs(input.timeoutMs),
|
|
160
|
+
})
|
|
161
|
+
.then((event) => ({
|
|
162
|
+
source: 'workflow_event' as const,
|
|
163
|
+
payload: readChildTerminalPayload(event.payload),
|
|
164
|
+
attempts: undefined as number | undefined,
|
|
165
|
+
}));
|
|
166
|
+
const terminal = await Promise.race([
|
|
167
|
+
eventPromise,
|
|
168
|
+
pollParentChildTerminalState({
|
|
169
|
+
coordinator: input.coordinator,
|
|
170
|
+
parentRunId: input.parentRunId,
|
|
171
|
+
eventKey,
|
|
172
|
+
timeoutMs: Math.min(input.timeoutMs, 30_000),
|
|
173
|
+
now: input.now,
|
|
174
|
+
}),
|
|
175
|
+
]);
|
|
176
|
+
const payload = terminal.payload;
|
|
177
|
+
const status = String(payload.status ?? '').toLowerCase();
|
|
178
|
+
if (status === 'completed') {
|
|
179
|
+
return {
|
|
180
|
+
output: extractChildPlayOutput(payload),
|
|
181
|
+
source: terminal.source,
|
|
182
|
+
attempts: terminal.attempts,
|
|
183
|
+
waitMs: input.now() - waitStartedAt,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const error = isRecord(payload.error) ? payload.error : null;
|
|
187
|
+
const message =
|
|
188
|
+
(typeof error?.message === 'string' && error.message.trim()) ||
|
|
189
|
+
(typeof payload.error === 'string' && payload.error.trim()) ||
|
|
190
|
+
`Child play ${input.playName} (${input.workflowId}) finished with status ${status || 'unknown'}.`;
|
|
191
|
+
throw new Error(message);
|
|
192
|
+
}
|