deepline 0.0.1 → 0.1.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.
Files changed (100) hide show
  1. package/README.md +324 -0
  2. package/dist/cli/index.js +6750 -503
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/index.mjs +6735 -512
  5. package/dist/cli/index.mjs.map +1 -1
  6. package/dist/index.d.mts +2349 -32
  7. package/dist/index.d.ts +2349 -32
  8. package/dist/index.js +1631 -82
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +1617 -83
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +3256 -0
  13. package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +710 -0
  14. package/dist/repo/apps/play-runner-workers/src/entry.ts +5070 -0
  15. package/dist/repo/apps/play-runner-workers/src/runtime/README.md +21 -0
  16. package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +177 -0
  17. package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +52 -0
  18. package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +100 -0
  19. package/dist/repo/apps/play-runner-workers/src/runtime/tool-result.ts +184 -0
  20. package/dist/repo/sdk/src/cli/commands/auth.ts +482 -0
  21. package/dist/repo/sdk/src/cli/commands/billing.ts +188 -0
  22. package/dist/repo/sdk/src/cli/commands/csv.ts +123 -0
  23. package/dist/repo/sdk/src/cli/commands/db.ts +119 -0
  24. package/dist/repo/sdk/src/cli/commands/feedback.ts +40 -0
  25. package/dist/repo/sdk/src/cli/commands/org.ts +117 -0
  26. package/dist/repo/sdk/src/cli/commands/play.ts +3200 -0
  27. package/dist/repo/sdk/src/cli/commands/tools.ts +687 -0
  28. package/dist/repo/sdk/src/cli/dataset-stats.ts +341 -0
  29. package/dist/repo/sdk/src/cli/index.ts +138 -0
  30. package/dist/repo/sdk/src/cli/progress.ts +135 -0
  31. package/dist/repo/sdk/src/cli/trace.ts +61 -0
  32. package/dist/repo/sdk/src/cli/utils.ts +145 -0
  33. package/dist/repo/sdk/src/client.ts +1188 -0
  34. package/dist/repo/sdk/src/compat.ts +77 -0
  35. package/dist/repo/sdk/src/config.ts +285 -0
  36. package/dist/repo/sdk/src/errors.ts +125 -0
  37. package/dist/repo/sdk/src/http.ts +391 -0
  38. package/dist/repo/sdk/src/index.ts +139 -0
  39. package/dist/repo/sdk/src/play.ts +1330 -0
  40. package/dist/repo/sdk/src/plays/bundle-play-file.ts +133 -0
  41. package/dist/repo/sdk/src/plays/harness-stub.ts +210 -0
  42. package/dist/repo/sdk/src/plays/local-file-discovery.ts +326 -0
  43. package/dist/repo/sdk/src/tool-output.ts +489 -0
  44. package/dist/repo/sdk/src/types.ts +669 -0
  45. package/dist/repo/sdk/src/version.ts +2 -0
  46. package/dist/repo/sdk/src/worker-play-entry.ts +286 -0
  47. package/dist/repo/shared_libs/observability/node-tracing.ts +129 -0
  48. package/dist/repo/shared_libs/observability/tracing.ts +98 -0
  49. package/dist/repo/shared_libs/play-runtime/backend.ts +139 -0
  50. package/dist/repo/shared_libs/play-runtime/batch-runtime.ts +182 -0
  51. package/dist/repo/shared_libs/play-runtime/batching-types.ts +91 -0
  52. package/dist/repo/shared_libs/play-runtime/context.ts +3999 -0
  53. package/dist/repo/shared_libs/play-runtime/coordinator-headers.ts +78 -0
  54. package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +250 -0
  55. package/dist/repo/shared_libs/play-runtime/ctx-types.ts +713 -0
  56. package/dist/repo/shared_libs/play-runtime/dataset-id.ts +10 -0
  57. package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +304 -0
  58. package/dist/repo/shared_libs/play-runtime/db-session.ts +462 -0
  59. package/dist/repo/shared_libs/play-runtime/dedup-backend.ts +0 -0
  60. package/dist/repo/shared_libs/play-runtime/default-batch-strategies.ts +124 -0
  61. package/dist/repo/shared_libs/play-runtime/execution-plan.ts +262 -0
  62. package/dist/repo/shared_libs/play-runtime/live-events.ts +214 -0
  63. package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +50 -0
  64. package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +114 -0
  65. package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +158 -0
  66. package/dist/repo/shared_libs/play-runtime/profiles.ts +90 -0
  67. package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +172 -0
  68. package/dist/repo/shared_libs/play-runtime/protocol.ts +121 -0
  69. package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +42 -0
  70. package/dist/repo/shared_libs/play-runtime/result-normalization.ts +33 -0
  71. package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +208 -0
  72. package/dist/repo/shared_libs/play-runtime/runtime-api.ts +1873 -0
  73. package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +2 -0
  74. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +201 -0
  75. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +48 -0
  76. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +84 -0
  77. package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +174 -0
  78. package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +147 -0
  79. package/dist/repo/shared_libs/play-runtime/suspension.ts +68 -0
  80. package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +146 -0
  81. package/dist/repo/shared_libs/play-runtime/tool-result.ts +387 -0
  82. package/dist/repo/shared_libs/play-runtime/tracing.ts +31 -0
  83. package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +75 -0
  84. package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +140 -0
  85. package/dist/repo/shared_libs/plays/artifact-transport.ts +14 -0
  86. package/dist/repo/shared_libs/plays/artifact-types.ts +49 -0
  87. package/dist/repo/shared_libs/plays/bundling/index.ts +1346 -0
  88. package/dist/repo/shared_libs/plays/compiler-manifest.ts +186 -0
  89. package/dist/repo/shared_libs/plays/contracts.ts +51 -0
  90. package/dist/repo/shared_libs/plays/dataset.ts +308 -0
  91. package/dist/repo/shared_libs/plays/definition.ts +264 -0
  92. package/dist/repo/shared_libs/plays/file-refs.ts +11 -0
  93. package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +206 -0
  94. package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +164 -0
  95. package/dist/repo/shared_libs/plays/row-identity.ts +302 -0
  96. package/dist/repo/shared_libs/plays/runtime-validation.ts +415 -0
  97. package/dist/repo/shared_libs/plays/static-pipeline.ts +560 -0
  98. package/dist/repo/shared_libs/temporal/constants.ts +39 -0
  99. package/dist/repo/shared_libs/temporal/preview-config.ts +153 -0
  100. package/package.json +14 -12
@@ -0,0 +1,560 @@
1
+ import { normalizeTableNamespace } from './row-identity';
2
+
3
+ export interface PlayStaticPipeline {
4
+ tableNamespace?: string;
5
+ inputFields?: string[];
6
+ csvArg?: string;
7
+ hasInlineData?: boolean;
8
+ csvDescription?: string;
9
+ mapDescription?: string;
10
+ fields: string[];
11
+ stages?: PlayStaticSubstep[];
12
+ substeps: PlayStaticSubstep[];
13
+ sheetContract?: PlaySheetContract | null;
14
+ sheetContractErrors?: string[];
15
+ }
16
+
17
+ export type PlaySheetColumnSource =
18
+ | 'input'
19
+ | 'mapField'
20
+ | 'waterfallStep'
21
+ | 'childPlayColumn';
22
+
23
+ export interface PlaySheetColumnContract {
24
+ id: string;
25
+ sqlName: string;
26
+ source: PlaySheetColumnSource;
27
+ field?: string;
28
+ parentField?: string;
29
+ playId?: string;
30
+ waterfallId?: string;
31
+ outputField?: string;
32
+ outputSqlName?: string;
33
+ stepId?: string;
34
+ toolId?: string;
35
+ }
36
+
37
+ export interface PlaySheetContract {
38
+ tableNamespace: string;
39
+ columns: PlaySheetColumnContract[];
40
+ }
41
+
42
+ export function ensureCompiledSheetContract(
43
+ pipeline: PlayStaticPipeline | null | undefined,
44
+ ): PlayStaticPipeline | null | undefined {
45
+ if (!pipeline) {
46
+ return pipeline;
47
+ }
48
+ if (pipeline.sheetContract) {
49
+ return pipeline;
50
+ }
51
+ const compiled = compileSheetContract(pipeline);
52
+ return {
53
+ ...pipeline,
54
+ sheetContract: compiled.contract,
55
+ sheetContractErrors: compiled.errors,
56
+ };
57
+ }
58
+
59
+ const DEFAULT_MAX_EMBEDDED_PLAY_CALL_PIPELINE_DEPTH = 3;
60
+
61
+ function cloneStorageSafeSourceRange(
62
+ sourceRange: PlayStaticSourceRange | undefined,
63
+ ): PlayStaticSourceRange | undefined {
64
+ return sourceRange ? { ...sourceRange } : undefined;
65
+ }
66
+
67
+ function cloneStorageSafeSheetContract(
68
+ contract: PlaySheetContract | null | undefined,
69
+ ): PlaySheetContract | null | undefined {
70
+ if (!contract) return contract;
71
+ return {
72
+ ...contract,
73
+ columns: contract.columns.map((column) => ({ ...column })),
74
+ };
75
+ }
76
+
77
+ function truncateStaticSubstepsForStorage(
78
+ substeps: PlayStaticSubstep[] | undefined,
79
+ input: {
80
+ embeddedPlayCallPipelineDepth: number;
81
+ maxEmbeddedPlayCallPipelineDepth: number;
82
+ },
83
+ ): PlayStaticSubstep[] {
84
+ return (substeps ?? []).map((substep) => {
85
+ const base = {
86
+ ...substep,
87
+ sourceRange: cloneStorageSafeSourceRange(substep.sourceRange),
88
+ callPath: substep.callPath ? [...substep.callPath] : undefined,
89
+ };
90
+
91
+ if (base.type === 'map') {
92
+ return {
93
+ ...base,
94
+ inputFields: base.inputFields ? [...base.inputFields] : undefined,
95
+ outputFields: base.outputFields ? [...base.outputFields] : undefined,
96
+ waterfallIds: base.waterfallIds ? [...base.waterfallIds] : undefined,
97
+ sheetContract: cloneStorageSafeSheetContract(base.sheetContract),
98
+ };
99
+ }
100
+
101
+ if (base.type === 'waterfall') {
102
+ return {
103
+ ...base,
104
+ steps: base.steps?.map((step) => ({ ...step })),
105
+ };
106
+ }
107
+
108
+ if (base.type !== 'play_call') {
109
+ return base;
110
+ }
111
+
112
+ if (
113
+ !base.pipeline ||
114
+ input.embeddedPlayCallPipelineDepth >=
115
+ input.maxEmbeddedPlayCallPipelineDepth
116
+ ) {
117
+ return {
118
+ ...base,
119
+ pipeline: null,
120
+ resolutionError:
121
+ base.resolutionError ??
122
+ `Stored static pipeline truncated at ${base.playId}`,
123
+ };
124
+ }
125
+
126
+ return {
127
+ ...base,
128
+ pipeline: truncateStaticPipelineForStorage(base.pipeline, {
129
+ maxEmbeddedPlayCallPipelineDepth:
130
+ input.maxEmbeddedPlayCallPipelineDepth,
131
+ embeddedPlayCallPipelineDepth: input.embeddedPlayCallPipelineDepth + 1,
132
+ }),
133
+ };
134
+ });
135
+ }
136
+
137
+ export function truncateStaticPipelineForStorage(
138
+ pipeline: PlayStaticPipeline | null | undefined,
139
+ options: {
140
+ maxEmbeddedPlayCallPipelineDepth?: number;
141
+ embeddedPlayCallPipelineDepth?: number;
142
+ } = {},
143
+ ): PlayStaticPipeline | null | undefined {
144
+ if (!pipeline) {
145
+ return pipeline;
146
+ }
147
+ const maxEmbeddedPlayCallPipelineDepth =
148
+ options.maxEmbeddedPlayCallPipelineDepth ??
149
+ DEFAULT_MAX_EMBEDDED_PLAY_CALL_PIPELINE_DEPTH;
150
+ const embeddedPlayCallPipelineDepth =
151
+ options.embeddedPlayCallPipelineDepth ?? 0;
152
+
153
+ return {
154
+ ...pipeline,
155
+ inputFields: pipeline.inputFields ? [...pipeline.inputFields] : undefined,
156
+ fields: [...(pipeline.fields ?? [])],
157
+ stages: truncateStaticSubstepsForStorage(pipeline.stages, {
158
+ embeddedPlayCallPipelineDepth,
159
+ maxEmbeddedPlayCallPipelineDepth,
160
+ }),
161
+ substeps: truncateStaticSubstepsForStorage(pipeline.substeps, {
162
+ embeddedPlayCallPipelineDepth,
163
+ maxEmbeddedPlayCallPipelineDepth,
164
+ }),
165
+ sheetContract: cloneStorageSafeSheetContract(pipeline.sheetContract),
166
+ sheetContractErrors: pipeline.sheetContractErrors
167
+ ? [...pipeline.sheetContractErrors]
168
+ : undefined,
169
+ };
170
+ }
171
+
172
+ export interface PlayStaticSourceRange {
173
+ sourcePath?: string;
174
+ startLine: number;
175
+ endLine: number;
176
+ startColumn: number;
177
+ endColumn: number;
178
+ }
179
+
180
+ type PlayStaticSubstepMetadata = {
181
+ conditional?: boolean;
182
+ };
183
+
184
+ export type PlayStaticSubstep = PlayStaticSubstepMetadata &
185
+ (
186
+ | {
187
+ type: 'csv';
188
+ field: string;
189
+ path?: string;
190
+ description?: string;
191
+ sourceRange?: PlayStaticSourceRange;
192
+ callDepth?: number;
193
+ callPath?: string[];
194
+ }
195
+ | {
196
+ type: 'map';
197
+ field: string;
198
+ name?: string;
199
+ tableNamespace?: string;
200
+ inputFields?: string[];
201
+ outputFields?: string[];
202
+ waterfallIds?: string[];
203
+ sheetContract?: PlaySheetContract | null;
204
+ description?: string;
205
+ sourceRange?: PlayStaticSourceRange;
206
+ callDepth?: number;
207
+ callPath?: string[];
208
+ }
209
+ | {
210
+ type: 'tool';
211
+ toolId: string;
212
+ field: string;
213
+ description?: string;
214
+ inLoop?: boolean;
215
+ isEventWait?: boolean;
216
+ sourceRange?: PlayStaticSourceRange;
217
+ callDepth?: number;
218
+ callPath?: string[];
219
+ }
220
+ | {
221
+ type: 'waterfall';
222
+ tool?: string;
223
+ field: string;
224
+ inLoop?: boolean;
225
+ id?: string;
226
+ output?: string;
227
+ minResults?: number;
228
+ sourceText?: string;
229
+ steps?: Array<{
230
+ id: string;
231
+ kind?: 'tool' | 'code';
232
+ toolId?: string;
233
+ paramsSource?: string;
234
+ }>;
235
+ description?: string;
236
+ sourceRange?: PlayStaticSourceRange;
237
+ callDepth?: number;
238
+ callPath?: string[];
239
+ }
240
+ | {
241
+ type: 'step_suite';
242
+ field: string;
243
+ steps: PlayStaticSubstep[];
244
+ returnSource?: string;
245
+ description?: string;
246
+ sourceRange?: PlayStaticSourceRange;
247
+ callDepth?: number;
248
+ callPath?: string[];
249
+ }
250
+ | {
251
+ type: 'play_call';
252
+ playId: string;
253
+ field: string;
254
+ inLoop?: boolean;
255
+ pipeline?: PlayStaticPipeline | null;
256
+ cycleDetected?: boolean;
257
+ resolutionError?: string;
258
+ description?: string;
259
+ sourceRange?: PlayStaticSourceRange;
260
+ callDepth?: number;
261
+ callPath?: string[];
262
+ }
263
+ | {
264
+ type: 'run_javascript';
265
+ alias: string;
266
+ description?: string;
267
+ sourceRange?: PlayStaticSourceRange;
268
+ callDepth?: number;
269
+ callPath?: string[];
270
+ }
271
+ | {
272
+ type: 'code';
273
+ field: string;
274
+ description?: string;
275
+ sourceRange?: PlayStaticSourceRange;
276
+ callDepth?: number;
277
+ callPath?: string[];
278
+ }
279
+ );
280
+
281
+ export function getCompiledPipelineSubsteps(
282
+ pipeline: PlayStaticPipeline | null | undefined,
283
+ ): PlayStaticSubstep[] {
284
+ if (!pipeline) {
285
+ return [];
286
+ }
287
+ return [...(pipeline.stages ?? []), ...(pipeline.substeps ?? [])];
288
+ }
289
+
290
+ export function getTopLevelPipelineSubsteps(
291
+ pipeline: PlayStaticPipeline | null | undefined,
292
+ ): PlayStaticSubstep[] {
293
+ if (!pipeline) {
294
+ return [];
295
+ }
296
+ const topLevel = [...(pipeline.stages ?? [])];
297
+ const tableNamespace = pipeline.tableNamespace?.trim();
298
+ if (pipeline.csvArg && !topLevel.some((substep) => substep.type === 'csv')) {
299
+ topLevel.unshift({
300
+ type: 'csv',
301
+ field: 'csv',
302
+ path: pipeline.csvArg,
303
+ description: pipeline.csvDescription,
304
+ });
305
+ }
306
+ if (tableNamespace && !topLevel.some((substep) => substep.type === 'map')) {
307
+ topLevel.push({
308
+ type: 'map',
309
+ field: tableNamespace,
310
+ tableNamespace,
311
+ inputFields: pipeline.inputFields,
312
+ description: pipeline.mapDescription,
313
+ });
314
+ }
315
+ if (topLevel.length > 0) {
316
+ return topLevel;
317
+ }
318
+ return [...pipeline.substeps];
319
+ }
320
+
321
+ export function flattenStaticSubsteps(
322
+ substeps: PlayStaticSubstep[],
323
+ ): PlayStaticSubstep[] {
324
+ const flattened: PlayStaticSubstep[] = [];
325
+
326
+ for (const substep of substeps) {
327
+ flattened.push(substep);
328
+ if (substep.type === 'play_call' && substep.pipeline) {
329
+ const nestedSubsteps = getCompiledPipelineSubsteps(substep.pipeline);
330
+ if (nestedSubsteps.length > 0) {
331
+ flattened.push(...flattenStaticSubsteps(nestedSubsteps));
332
+ }
333
+ }
334
+ }
335
+
336
+ return flattened;
337
+ }
338
+
339
+ export function flattenStaticPipeline(
340
+ pipeline: PlayStaticPipeline,
341
+ ): PlayStaticSubstep[] {
342
+ return flattenStaticSubsteps(getCompiledPipelineSubsteps(pipeline));
343
+ }
344
+
345
+ export function resolveSheetContractForTableNamespace(
346
+ pipeline: PlayStaticPipeline | null | undefined,
347
+ tableNamespace: string | null | undefined,
348
+ ): PlaySheetContract | null {
349
+ const requestedNamespace = tableNamespace?.trim();
350
+ if (!pipeline || !requestedNamespace) {
351
+ return null;
352
+ }
353
+ const normalizedNamespace = normalizeTableNamespace(requestedNamespace);
354
+ const seen = new Set<PlayStaticPipeline>();
355
+
356
+ const resolveFromPipeline = (
357
+ currentPipeline: PlayStaticPipeline | null | undefined,
358
+ ): PlaySheetContract | null => {
359
+ if (!currentPipeline || seen.has(currentPipeline)) {
360
+ return null;
361
+ }
362
+ seen.add(currentPipeline);
363
+
364
+ const rootNamespace = currentPipeline.tableNamespace?.trim();
365
+ if (
366
+ rootNamespace &&
367
+ normalizeTableNamespace(rootNamespace) === normalizedNamespace &&
368
+ currentPipeline.sheetContract
369
+ ) {
370
+ return currentPipeline.sheetContract;
371
+ }
372
+
373
+ for (const substep of getCompiledPipelineSubsteps(currentPipeline)) {
374
+ if (substep.type === 'map') {
375
+ const substepNamespace = substep.tableNamespace?.trim();
376
+ if (
377
+ substepNamespace &&
378
+ normalizeTableNamespace(substepNamespace) === normalizedNamespace &&
379
+ substep.sheetContract
380
+ ) {
381
+ return substep.sheetContract;
382
+ }
383
+ continue;
384
+ }
385
+
386
+ if (substep.type === 'play_call') {
387
+ const nestedContract = resolveFromPipeline(substep.pipeline);
388
+ if (nestedContract) {
389
+ return nestedContract;
390
+ }
391
+ }
392
+ }
393
+
394
+ return null;
395
+ };
396
+
397
+ return resolveFromPipeline(pipeline);
398
+ }
399
+
400
+ export function sqlSafePlayColumnName(id: string): string {
401
+ const normalized = id
402
+ .trim()
403
+ .replace(/\.+/g, '__')
404
+ .replace(/[^A-Za-z0-9_]+/g, '_')
405
+ .replace(/^_+|_+$/g, '')
406
+ .toLowerCase();
407
+ const safe = normalized || 'column';
408
+ return /^[A-Za-z_]/.test(safe) ? safe : `c_${safe}`;
409
+ }
410
+
411
+ export function compileSheetContract(pipeline: PlayStaticPipeline): {
412
+ contract: PlaySheetContract | null;
413
+ errors: string[];
414
+ } {
415
+ const errors = [...(pipeline.sheetContractErrors ?? [])];
416
+ const tableNamespace = pipeline.tableNamespace?.trim();
417
+ if (!tableNamespace) {
418
+ return {
419
+ contract: null,
420
+ errors,
421
+ };
422
+ }
423
+
424
+ const columns: PlaySheetColumnContract[] = [];
425
+
426
+ const addColumn = (column: Omit<PlaySheetColumnContract, 'sqlName'>) => {
427
+ if (!column.id.trim()) {
428
+ errors.push('Sheet contract produced an empty column id.');
429
+ return;
430
+ }
431
+ if (columns.some((existing) => existing.id === column.id)) return;
432
+ columns.push({
433
+ ...column,
434
+ sqlName: sqlSafePlayColumnName(column.id),
435
+ });
436
+ };
437
+
438
+ const inputFields = pipeline.inputFields?.length
439
+ ? pipeline.inputFields
440
+ : [tableNamespace];
441
+ for (const inputField of inputFields) {
442
+ addColumn({ id: inputField, source: 'input', field: inputField });
443
+ }
444
+
445
+ for (const field of pipeline.fields) {
446
+ addColumn({ id: field, source: 'mapField', field });
447
+ }
448
+
449
+ for (const substep of pipeline.substeps) {
450
+ if (substep.type === 'waterfall') {
451
+ if (!substep.id) {
452
+ if (substep.tool) {
453
+ continue;
454
+ }
455
+ errors.push(
456
+ `Sheet contract cannot compile waterfall field "${substep.field}" without a literal waterfall id.`,
457
+ );
458
+ continue;
459
+ }
460
+ if (!substep.steps?.length) {
461
+ errors.push(
462
+ `Sheet contract cannot compile waterfall "${substep.id}" because its steps are not statically known. ` +
463
+ 'Use an inline array, a local const array, or a local no-arg function that returns an array of step("id", "tool", ...) calls.',
464
+ );
465
+ continue;
466
+ }
467
+ for (const step of substep.steps) {
468
+ addColumn({
469
+ id: `${substep.id}.${step.id}`,
470
+ source: 'waterfallStep',
471
+ field: substep.field,
472
+ waterfallId: substep.id,
473
+ outputField: substep.output,
474
+ outputSqlName: substep.output
475
+ ? sqlSafePlayColumnName(substep.output)
476
+ : undefined,
477
+ stepId: step.id,
478
+ toolId: step.toolId,
479
+ });
480
+ }
481
+ continue;
482
+ }
483
+
484
+ if (substep.type === 'step_suite') {
485
+ const addStepSuiteColumns = (
486
+ suite: Extract<PlayStaticSubstep, { type: 'step_suite' }>,
487
+ rootField: string,
488
+ ) => {
489
+ for (const step of suite.steps) {
490
+ if (!('field' in step)) {
491
+ continue;
492
+ }
493
+ const stepId = step.field.startsWith(`${rootField}.`)
494
+ ? step.field.slice(rootField.length + 1)
495
+ : step.field;
496
+ if (!stepId.trim()) {
497
+ continue;
498
+ }
499
+ addColumn({
500
+ id: step.field,
501
+ source: 'waterfallStep',
502
+ field: rootField,
503
+ waterfallId: rootField,
504
+ outputField: rootField,
505
+ outputSqlName: sqlSafePlayColumnName(rootField),
506
+ stepId,
507
+ toolId: step.type === 'tool' ? step.toolId : undefined,
508
+ });
509
+ if (step.type === 'step_suite') {
510
+ addStepSuiteColumns(step, rootField);
511
+ }
512
+ }
513
+ };
514
+ addStepSuiteColumns(substep, substep.field);
515
+ continue;
516
+ }
517
+ if (substep.type === 'play_call') {
518
+ if (substep.cycleDetected || substep.resolutionError) {
519
+ errors.push(
520
+ substep.resolutionError ??
521
+ `Sheet contract cannot compile recursive child play "${substep.playId}".`,
522
+ );
523
+ } else if (!substep.pipeline) {
524
+ errors.push(
525
+ `Sheet contract cannot compile child play field "${substep.field}" until "${substep.playId}" is statically resolved.`,
526
+ );
527
+ } else {
528
+ const child = compileSheetContract(substep.pipeline);
529
+ for (const childError of child.errors) {
530
+ errors.push(`${substep.playId}: ${childError}`);
531
+ }
532
+ if (child.contract) {
533
+ for (const childColumn of child.contract.columns) {
534
+ if (childColumn.source === 'input') continue;
535
+ addColumn({
536
+ id: `${substep.field}.${childColumn.id}`,
537
+ source: 'childPlayColumn',
538
+ parentField: substep.field,
539
+ playId: substep.playId,
540
+ field: childColumn.field,
541
+ waterfallId: childColumn.waterfallId,
542
+ outputField: childColumn.outputField,
543
+ outputSqlName: childColumn.outputSqlName,
544
+ stepId: childColumn.stepId,
545
+ toolId: childColumn.toolId,
546
+ });
547
+ }
548
+ }
549
+ }
550
+ }
551
+ }
552
+
553
+ return {
554
+ contract: {
555
+ tableNamespace,
556
+ columns,
557
+ },
558
+ errors: [...new Set(errors)],
559
+ };
560
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared Temporal execution constants.
3
+ *
4
+ * Keep values that both the API/auth surface and the worker need here so the
5
+ * API never imports from worker-only modules.
6
+ */
7
+
8
+ /**
9
+ * Local Temporal dev defaults.
10
+ *
11
+ * These match the host ports exposed by docker-compose.yml and the env files
12
+ * used by the local dev flows (`.env.local`, `.env.worktree`).
13
+ */
14
+ export const LOCAL_TEMPORAL_FRONTEND_PORT = 17233;
15
+ export const LOCAL_TEMPORAL_UI_PORT = 18233;
16
+ export const LOCAL_TEMPORAL_NAMESPACE = 'default';
17
+ export const LOCAL_TEMPORAL_ADDRESS =
18
+ `127.0.0.1:${LOCAL_TEMPORAL_FRONTEND_PORT}`;
19
+ export const LOCAL_TEMPORAL_UI_URL =
20
+ `http://127.0.0.1:${LOCAL_TEMPORAL_UI_PORT}`;
21
+
22
+ /** Maximum active user-code runtime for a standard play, in seconds. */
23
+ export const STANDARD_PLAY_RUNTIME_LIMIT_SECONDS = 10 * 60; // 10 minutes
24
+
25
+ /**
26
+ * Activity timeout includes cleanup/billing headroom after the 10 minute
27
+ * user-code runtime cap. Keep this higher than STANDARD_PLAY_RUNTIME_LIMIT_SECONDS.
28
+ */
29
+ export const PLAY_ACTIVITY_TIMEOUT_SECONDS = 12 * 60; // 12 minutes
30
+
31
+ /** Heartbeat cadence for the long-running play execution activity. */
32
+ export const PLAY_EXECUTE_ACTIVITY_HEARTBEAT_INTERVAL_SECONDS = 15;
33
+
34
+ /**
35
+ * TTL for workflow executor tokens, in seconds.
36
+ * Matches the activity timeout so tokens expire when the activity would
37
+ * time out anyway.
38
+ */
39
+ export const WORKFLOW_EXECUTOR_TOKEN_TTL_SECONDS = PLAY_ACTIVITY_TIMEOUT_SECONDS;