deepline 0.1.60 → 0.1.61

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 CHANGED
@@ -220,10 +220,10 @@ function resolveConfig(options) {
220
220
 
221
221
  // src/release.ts
222
222
  var SDK_RELEASE = {
223
- version: "0.1.60",
223
+ version: "0.1.61",
224
224
  apiContract: "2026-05-play-bootstrap-dataset-summary",
225
225
  supportPolicy: {
226
- latest: "0.1.60",
226
+ latest: "0.1.61",
227
227
  minimumSupported: "0.1.53",
228
228
  deprecatedBelow: "0.1.53"
229
229
  }
@@ -197,10 +197,10 @@ function resolveConfig(options) {
197
197
 
198
198
  // src/release.ts
199
199
  var SDK_RELEASE = {
200
- version: "0.1.60",
200
+ version: "0.1.61",
201
201
  apiContract: "2026-05-play-bootstrap-dataset-summary",
202
202
  supportPolicy: {
203
- latest: "0.1.60",
203
+ latest: "0.1.61",
204
204
  minimumSupported: "0.1.53",
205
205
  deprecatedBelow: "0.1.53"
206
206
  }
package/dist/index.js CHANGED
@@ -232,10 +232,10 @@ function resolveConfig(options) {
232
232
 
233
233
  // src/release.ts
234
234
  var SDK_RELEASE = {
235
- version: "0.1.60",
235
+ version: "0.1.61",
236
236
  apiContract: "2026-05-play-bootstrap-dataset-summary",
237
237
  supportPolicy: {
238
- latest: "0.1.60",
238
+ latest: "0.1.61",
239
239
  minimumSupported: "0.1.53",
240
240
  deprecatedBelow: "0.1.53"
241
241
  }
package/dist/index.mjs CHANGED
@@ -170,10 +170,10 @@ function resolveConfig(options) {
170
170
 
171
171
  // src/release.ts
172
172
  var SDK_RELEASE = {
173
- version: "0.1.60",
173
+ version: "0.1.61",
174
174
  apiContract: "2026-05-play-bootstrap-dataset-summary",
175
175
  supportPolicy: {
176
- latest: "0.1.60",
176
+ latest: "0.1.61",
177
177
  minimumSupported: "0.1.53",
178
178
  deprecatedBelow: "0.1.53"
179
179
  }
@@ -545,7 +545,7 @@ const WORKFLOW_POOL_PROTOCOL_VERSION =
545
545
  const WORKFLOW_POOL_DO_NAME = 'workflow-pool:v2';
546
546
  const WORKFLOW_POOL_START_EVENT_TYPE = 'play_start';
547
547
  const WORKFLOW_POOL_TTL_MS = 8 * 60 * 1000;
548
- const WORKFLOW_POOL_TARGET_SIZE = 16;
548
+ const WORKFLOW_POOL_TARGET_SIZE = 0;
549
549
  const WORKFLOW_POOL_READY_TIMEOUT_MS = 1_500;
550
550
  const WORKFLOW_POOL_READY_POLL_MS = 250;
551
551
  const WORKFLOW_POOL_REFILL_ON_MISS_TIMEOUT_MS = 2_500;
@@ -3637,10 +3637,10 @@ async function handleWorkflowRoute(input: {
3637
3637
  }
3638
3638
  return Response.json({ runId, status: 'cancelled' });
3639
3639
  }
3640
- if (!instance) {
3641
- return new Response('not found', { status: 404 });
3642
- }
3643
3640
  if (action === 'signal') {
3641
+ if (!instance) {
3642
+ return new Response('not found', { status: 404 });
3643
+ }
3644
3644
  const body = (await request.json().catch(() => ({}))) as Record<
3645
3645
  string,
3646
3646
  unknown
@@ -3697,11 +3697,14 @@ async function handleWorkflowRoute(input: {
3697
3697
  waitMs: 0,
3698
3698
  workflowStatus: 'terminal-cache',
3699
3699
  statusPolls: 0,
3700
- instanceId: instance.id,
3700
+ instanceId: instance?.id ?? null,
3701
3701
  },
3702
3702
  ...(includeTrace ? { coordinatorTrace } : {}),
3703
3703
  });
3704
3704
  }
3705
+ if (!instance) {
3706
+ return new Response('not found', { status: 404 });
3707
+ }
3705
3708
  const status = await instance.status();
3706
3709
  const workflowError = readWorkflowError(status);
3707
3710
  if (workflowError) {
@@ -3141,6 +3141,7 @@ function createMinimalWorkerCtx(
3141
3141
  ): unknown {
3142
3142
  let playCallCount = 0;
3143
3143
  const parentChildCalls: Record<string, number> = {};
3144
+ const stepCallCounts: Record<string, number> = {};
3144
3145
  const inFlightChildCallsByPlayName: Record<string, number> = {};
3145
3146
  let inFlightChildPlayCalls = 0;
3146
3147
  const childPlaySlotWaiters: Array<() => void> = [];
@@ -3182,6 +3183,7 @@ function createMinimalWorkerCtx(
3182
3183
  const executeWithRuntimeReceipt = async <T>(
3183
3184
  key: string,
3184
3185
  execute: () => Promise<T> | T,
3186
+ repairRunningReceiptForSameRun = false,
3185
3187
  ): Promise<T> => {
3186
3188
  const serialized = await runWorkerRuntimeReceiptBoundary<unknown>({
3187
3189
  baseUrl: req.baseUrl,
@@ -3192,9 +3194,36 @@ function createMinimalWorkerCtx(
3192
3194
  key,
3193
3195
  postRuntimeApi,
3194
3196
  execute: async () => serializeDurableStepValue(await execute()),
3197
+ repairRunningReceiptForSameRun,
3195
3198
  });
3196
3199
  return deserializeDurableStepValue(serialized) as T;
3197
3200
  };
3201
+ const executeWithWorkflowStep = async <T>(
3202
+ name: string,
3203
+ execute: () => Promise<T> | T,
3204
+ ): Promise<T> => {
3205
+ if (!workflowStep) {
3206
+ return await executeWithRuntimeReceipt(name, execute);
3207
+ }
3208
+ return await executeWithRuntimeReceipt(
3209
+ name,
3210
+ async () => {
3211
+ const serialized = await (
3212
+ workflowStep.do as unknown as (
3213
+ name: string,
3214
+ callback: () => Promise<unknown>,
3215
+ ) => Promise<unknown>
3216
+ )(name, async () => serializeDurableStepValue(await execute()));
3217
+ return deserializeDurableStepValue(serialized) as T;
3218
+ },
3219
+ true,
3220
+ );
3221
+ };
3222
+ const nextCtxStepReceiptKey = (name: string): string => {
3223
+ const count = stepCallCounts[name] ?? 0;
3224
+ stepCallCounts[name] = count + 1;
3225
+ return count === 0 ? `step:${name}` : `step:${name}:${count}`;
3226
+ };
3198
3227
  const staleRuntimeSuffix = (staleAfterSeconds?: number): string => {
3199
3228
  if (staleAfterSeconds === undefined) return '';
3200
3229
  if (
@@ -3952,11 +3981,8 @@ function createMinimalWorkerCtx(
3952
3981
  if (!normalizedName) {
3953
3982
  throw new Error('ctx.step(name, callback) requires a name.');
3954
3983
  }
3955
- // Static pipeline JS blocks are already Workflow steps in the Workers
3956
- // backend. Nesting another `step.do` here can leave preview runs parked
3957
- // inside the JS stage before they reach subsequent event waits.
3958
- return await executeWithRuntimeReceipt(
3959
- `step:${normalizedName}${staleRuntimeSuffix(options?.staleAfterSeconds)}`,
3984
+ return await executeWithWorkflowStep(
3985
+ `${nextCtxStepReceiptKey(normalizedName)}${staleRuntimeSuffix(options?.staleAfterSeconds)}`,
3960
3986
  callback,
3961
3987
  );
3962
3988
  },
@@ -4607,7 +4633,7 @@ async function executeRunRequest(
4607
4633
  runtimeBackend: 'cf_workflows_dynamic_worker',
4608
4634
  },
4609
4635
  ];
4610
- let lastLedgerFlushAt = 0;
4636
+ let lastLedgerFlushAt = startedAt;
4611
4637
  let ledgerFlushInFlight: Promise<void> = Promise.resolve();
4612
4638
 
4613
4639
  const appendRunLogLine = (line: string) => {
@@ -4760,7 +4786,6 @@ async function executeRunRequest(
4760
4786
  terminalEvent: PlayRunLedgerEvent,
4761
4787
  ): Promise<void> => {
4762
4788
  if (!options?.persistResultDatasets) return;
4763
- await ledgerFlushInFlight.catch(() => undefined);
4764
4789
  const now = nowMs();
4765
4790
  pendingRunLogLines = runLogBuffer;
4766
4791
  dirtyProgressNodeIds = new Set([
@@ -4768,6 +4793,7 @@ async function executeRunRequest(
4768
4793
  ...Object.keys(stepProgressByNodeId),
4769
4794
  ]);
4770
4795
  pendingLedgerEvents = [...pendingLedgerEvents, terminalEvent];
4796
+ await ledgerFlushInFlight;
4771
4797
  const events = drainPendingLedgerEvents(now);
4772
4798
  if (events.length === 0) return;
4773
4799
  try {
@@ -4851,7 +4877,7 @@ async function executeRunRequest(
4851
4877
  });
4852
4878
  if (options?.persistResultDatasets) {
4853
4879
  const ledgerFlushWaitStartedAt = nowMs();
4854
- await ledgerFlushInFlight.catch(() => undefined);
4880
+ await ledgerFlushInFlight;
4855
4881
  recordRunnerPerfTrace({
4856
4882
  req,
4857
4883
  phase: 'runner.run_ledger_flush_wait',
@@ -4866,29 +4892,19 @@ async function executeRunRequest(
4866
4892
  });
4867
4893
  const terminalResult = trimResultForStatus(serializedResult);
4868
4894
  const terminalOccurredAt = nowMs();
4869
- const terminalLedgerPromise = (async () => {
4870
- const terminalUpdateStartedAt = nowMs();
4871
- await flushTerminalLedgerEvents({
4872
- type: 'run.completed',
4873
- runId: req.runId,
4874
- source: 'worker',
4875
- occurredAt: terminalOccurredAt,
4876
- result: terminalResult,
4877
- });
4878
- recordRunnerPerfTrace({
4879
- req,
4880
- phase: 'runner.terminal_ledger_append',
4881
- ms: nowMs() - terminalUpdateStartedAt,
4882
- });
4883
- })().catch((error) => {
4884
- console.error(
4885
- `[play-harness] non-fatal terminal ledger append failed runId=${req.runId}: ${
4886
- error instanceof Error ? error.message : String(error)
4887
- }`,
4888
- );
4895
+ const terminalUpdateStartedAt = nowMs();
4896
+ await flushTerminalLedgerEvents({
4897
+ type: 'run.completed',
4898
+ runId: req.runId,
4899
+ source: 'worker',
4900
+ occurredAt: terminalOccurredAt,
4901
+ result: terminalResult,
4902
+ });
4903
+ recordRunnerPerfTrace({
4904
+ req,
4905
+ phase: 'runner.terminal_ledger_append',
4906
+ ms: nowMs() - terminalUpdateStartedAt,
4889
4907
  });
4890
-
4891
- await terminalLedgerPromise;
4892
4908
 
4893
4909
  const billingStartedAt = nowMs();
4894
4910
  const billingPromise = finalizeWorkerComputeBilling({
@@ -59,6 +59,10 @@ type RuntimeReceiptContext = {
59
59
  ) => Promise<WorkerRuntimeReceiptResponse>;
60
60
  };
61
61
 
62
+ type PostRuntimeReceiptAction = (
63
+ body: WorkerRuntimeReceiptAction,
64
+ ) => Promise<WorkerRuntimeReceiptResponse>;
65
+
62
66
  function scopedReceiptKey(input: {
63
67
  orgId?: string | null;
64
68
  playName: string;
@@ -81,27 +85,57 @@ function runningReceiptError(key: string, receipt: WorkerRuntimeReceipt): Error
81
85
  );
82
86
  }
83
87
 
88
+ async function executeAndPersistReceipt<T>(input: {
89
+ key: string;
90
+ playName: string;
91
+ runId: string;
92
+ execute: () => Promise<T> | T;
93
+ postRuntimeReceiptAction: PostRuntimeReceiptAction;
94
+ ownership: 'claimed' | 'workflow_replay';
95
+ }): Promise<T> {
96
+ let output: T;
97
+ try {
98
+ output = await input.execute();
99
+ } catch (error) {
100
+ const failed = await input.postRuntimeReceiptAction({
101
+ action: 'fail_runtime_step_receipt',
102
+ playName: input.playName,
103
+ runId: input.runId,
104
+ key: input.key,
105
+ error: errorMessage(error),
106
+ });
107
+ if (!failed.receipt) {
108
+ throw new Error(
109
+ `Runtime receipt ${input.key} ${input.ownership} execution failed and failed receipt could not be persisted: ${errorMessage(error)}`,
110
+ );
111
+ }
112
+ throw error;
113
+ }
114
+
115
+ const completed = await input.postRuntimeReceiptAction({
116
+ action: 'complete_runtime_step_receipt',
117
+ playName: input.playName,
118
+ runId: input.runId,
119
+ key: input.key,
120
+ output,
121
+ });
122
+ if (!completed.receipt) {
123
+ throw new Error(
124
+ `Runtime receipt ${input.key} ${input.ownership} execution completed but completed receipt could not be persisted.`,
125
+ );
126
+ }
127
+ return output;
128
+ }
129
+
84
130
  export async function runWorkerRuntimeReceiptBoundary<T>(
85
131
  input: RuntimeReceiptContext & {
86
132
  execute: () => Promise<T> | T;
133
+ repairRunningReceiptForSameRun?: boolean;
87
134
  },
88
135
  ): Promise<T> {
89
136
  const key = scopedReceiptKey(input);
90
137
  const postRuntimeReceiptAction = (body: WorkerRuntimeReceiptAction) =>
91
138
  input.postRuntimeApi(input.baseUrl, input.executorToken, body);
92
- const existing = await postRuntimeReceiptAction({
93
- action: 'get_runtime_step_receipt',
94
- playName: input.playName,
95
- runId: input.runId,
96
- key,
97
- });
98
- if (
99
- existing.receipt?.status === 'completed' ||
100
- existing.receipt?.status === 'skipped'
101
- ) {
102
- return receiptOutput<T>(existing.receipt);
103
- }
104
-
105
139
  const claimed = await postRuntimeReceiptAction({
106
140
  action: 'claim_runtime_step_receipt',
107
141
  playName: input.playName,
@@ -122,6 +156,19 @@ export async function runWorkerRuntimeReceiptBoundary<T>(
122
156
  return receiptOutput<T>(latest.receipt);
123
157
  }
124
158
  if (latest.receipt?.status === 'running') {
159
+ if (
160
+ input.repairRunningReceiptForSameRun &&
161
+ latest.receipt.runId === input.runId
162
+ ) {
163
+ return executeAndPersistReceipt({
164
+ key,
165
+ playName: input.playName,
166
+ runId: input.runId,
167
+ execute: input.execute,
168
+ postRuntimeReceiptAction,
169
+ ownership: 'workflow_replay',
170
+ });
171
+ }
125
172
  throw runningReceiptError(key, latest.receipt);
126
173
  }
127
174
  if (latest.receipt?.status === 'failed') {
@@ -134,35 +181,12 @@ export async function runWorkerRuntimeReceiptBoundary<T>(
134
181
  );
135
182
  }
136
183
 
137
- let output: T;
138
- try {
139
- output = await input.execute();
140
- } catch (error) {
141
- const failed = await postRuntimeReceiptAction({
142
- action: 'fail_runtime_step_receipt',
143
- playName: input.playName,
144
- runId: input.runId,
145
- key,
146
- error: errorMessage(error),
147
- });
148
- if (!failed.receipt) {
149
- throw new Error(
150
- `Runtime receipt ${key} execution failed and failed receipt could not be persisted: ${errorMessage(error)}`,
151
- );
152
- }
153
- throw error;
154
- }
155
- const completed = await postRuntimeReceiptAction({
156
- action: 'complete_runtime_step_receipt',
184
+ return executeAndPersistReceipt({
185
+ key,
157
186
  playName: input.playName,
158
187
  runId: input.runId,
159
- key,
160
- output,
188
+ execute: input.execute,
189
+ postRuntimeReceiptAction,
190
+ ownership: 'claimed',
161
191
  });
162
- if (!completed.receipt) {
163
- throw new Error(
164
- `Runtime receipt ${key} execution completed but completed receipt could not be persisted.`,
165
- );
166
- }
167
- return output;
168
192
  }
@@ -50,10 +50,10 @@ export type SdkRelease = {
50
50
  };
51
51
 
52
52
  export const SDK_RELEASE = {
53
- version: '0.1.60',
53
+ version: '0.1.61',
54
54
  apiContract: '2026-05-play-bootstrap-dataset-summary',
55
55
  supportPolicy: {
56
- latest: '0.1.60',
56
+ latest: '0.1.61',
57
57
  minimumSupported: '0.1.53',
58
58
  deprecatedBelow: '0.1.53',
59
59
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.60",
3
+ "version": "0.1.61",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {