deepline 0.1.0 → 0.1.2
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 +212 -54
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +198 -40
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +3256 -0
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +710 -0
- package/dist/repo/apps/play-runner-workers/src/entry.ts +5070 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/README.md +21 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +177 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +52 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +100 -0
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-result.ts +184 -0
- package/dist/repo/sdk/src/cli/commands/auth.ts +482 -0
- package/dist/repo/sdk/src/cli/commands/billing.ts +188 -0
- package/dist/repo/sdk/src/cli/commands/csv.ts +123 -0
- package/dist/repo/sdk/src/cli/commands/db.ts +119 -0
- package/dist/repo/sdk/src/cli/commands/feedback.ts +40 -0
- package/dist/repo/sdk/src/cli/commands/org.ts +117 -0
- package/dist/repo/sdk/src/cli/commands/play.ts +3200 -0
- package/dist/repo/sdk/src/cli/commands/tools.ts +687 -0
- package/dist/repo/sdk/src/cli/dataset-stats.ts +341 -0
- package/dist/repo/sdk/src/cli/index.ts +138 -0
- package/dist/repo/sdk/src/cli/progress.ts +135 -0
- package/dist/repo/sdk/src/cli/trace.ts +61 -0
- package/dist/repo/sdk/src/cli/utils.ts +145 -0
- package/dist/repo/sdk/src/client.ts +1188 -0
- package/dist/repo/sdk/src/compat.ts +77 -0
- package/dist/repo/sdk/src/config.ts +285 -0
- package/dist/repo/sdk/src/errors.ts +125 -0
- package/dist/repo/sdk/src/http.ts +391 -0
- package/dist/repo/sdk/src/index.ts +139 -0
- package/dist/repo/sdk/src/play.ts +1330 -0
- package/dist/repo/sdk/src/plays/bundle-play-file.ts +133 -0
- package/dist/repo/sdk/src/plays/harness-stub.ts +210 -0
- package/dist/repo/sdk/src/plays/local-file-discovery.ts +326 -0
- package/dist/repo/sdk/src/tool-output.ts +489 -0
- package/dist/repo/sdk/src/types.ts +669 -0
- package/dist/repo/sdk/src/version.ts +2 -0
- package/dist/repo/sdk/src/worker-play-entry.ts +286 -0
- package/dist/repo/shared_libs/observability/node-tracing.ts +129 -0
- package/dist/repo/shared_libs/observability/tracing.ts +98 -0
- package/dist/repo/shared_libs/play-runtime/backend.ts +139 -0
- package/dist/repo/shared_libs/play-runtime/batch-runtime.ts +182 -0
- package/dist/repo/shared_libs/play-runtime/batching-types.ts +91 -0
- package/dist/repo/shared_libs/play-runtime/context.ts +3999 -0
- package/dist/repo/shared_libs/play-runtime/coordinator-headers.ts +78 -0
- package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +250 -0
- package/dist/repo/shared_libs/play-runtime/ctx-types.ts +713 -0
- package/dist/repo/shared_libs/play-runtime/dataset-id.ts +10 -0
- package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +304 -0
- package/dist/repo/shared_libs/play-runtime/db-session.ts +462 -0
- package/dist/repo/shared_libs/play-runtime/dedup-backend.ts +0 -0
- package/dist/repo/shared_libs/play-runtime/default-batch-strategies.ts +124 -0
- package/dist/repo/shared_libs/play-runtime/execution-plan.ts +262 -0
- package/dist/repo/shared_libs/play-runtime/live-events.ts +214 -0
- package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +50 -0
- package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +114 -0
- package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +158 -0
- package/dist/repo/shared_libs/play-runtime/profiles.ts +90 -0
- package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +172 -0
- package/dist/repo/shared_libs/play-runtime/protocol.ts +121 -0
- package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +42 -0
- package/dist/repo/shared_libs/play-runtime/result-normalization.ts +33 -0
- package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +208 -0
- package/dist/repo/shared_libs/play-runtime/runtime-api.ts +1873 -0
- package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +2 -0
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +201 -0
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +48 -0
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +84 -0
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +174 -0
- package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +147 -0
- package/dist/repo/shared_libs/play-runtime/suspension.ts +68 -0
- package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +146 -0
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +387 -0
- package/dist/repo/shared_libs/play-runtime/tracing.ts +31 -0
- package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +75 -0
- package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +140 -0
- package/dist/repo/shared_libs/plays/artifact-transport.ts +14 -0
- package/dist/repo/shared_libs/plays/artifact-types.ts +49 -0
- package/dist/repo/shared_libs/plays/bundling/index.ts +1346 -0
- package/dist/repo/shared_libs/plays/compiler-manifest.ts +186 -0
- package/dist/repo/shared_libs/plays/contracts.ts +51 -0
- package/dist/repo/shared_libs/plays/dataset.ts +308 -0
- package/dist/repo/shared_libs/plays/definition.ts +264 -0
- package/dist/repo/shared_libs/plays/file-refs.ts +11 -0
- package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +206 -0
- package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +164 -0
- package/dist/repo/shared_libs/plays/row-identity.ts +302 -0
- package/dist/repo/shared_libs/plays/runtime-validation.ts +415 -0
- package/dist/repo/shared_libs/plays/static-pipeline.ts +560 -0
- package/dist/repo/shared_libs/temporal/constants.ts +39 -0
- package/dist/repo/shared_libs/temporal/preview-config.ts +153 -0
- package/package.json +4 -4
|
@@ -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;
|