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.
Files changed (26) hide show
  1. package/dist/cli/index.js +69 -37
  2. package/dist/cli/index.mjs +69 -37
  3. package/dist/index.d.mts +32 -1
  4. package/dist/index.d.ts +32 -1
  5. package/dist/index.js +7 -4
  6. package/dist/index.mjs +7 -4
  7. package/dist/repo/apps/play-runner-workers/src/child-play-await.ts +192 -0
  8. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +1320 -1644
  9. package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +515 -648
  10. package/dist/repo/apps/play-runner-workers/src/entry.ts +896 -354
  11. package/dist/repo/apps/play-runner-workers/src/workflow-retry-state.ts +209 -0
  12. package/dist/repo/sdk/src/client.ts +9 -2
  13. package/dist/repo/sdk/src/release.ts +2 -2
  14. package/dist/repo/sdk/src/types.ts +5 -0
  15. package/dist/repo/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +231 -0
  16. package/dist/repo/shared_libs/play-runtime/governor/governor.ts +376 -0
  17. package/dist/repo/shared_libs/play-runtime/governor/policy.ts +179 -0
  18. package/dist/repo/shared_libs/play-runtime/governor/rate-state-backend.ts +87 -0
  19. package/dist/repo/shared_libs/play-runtime/run-failure.ts +12 -0
  20. package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +24 -0
  21. package/dist/repo/shared_libs/play-runtime/submit-limits.ts +35 -0
  22. package/dist/repo/shared_libs/plays/bundling/index.ts +4 -12
  23. package/dist/repo/shared_libs/plays/bundling/limits.ts +29 -0
  24. package/dist/repo/shared_libs/plays/static-pipeline.ts +314 -1
  25. package/dist/repo/shared_libs/temporal/constants.ts +38 -0
  26. 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.78",
244
+ version: "0.1.80",
245
245
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
246
246
  supportPolicy: {
247
- latest: "0.1.78",
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.78",
182
+ version: "0.1.80",
183
183
  apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
184
184
  supportPolicy: {
185
- latest: "0.1.78",
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
+ }