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.
Files changed (97) hide show
  1. package/dist/cli/index.js +212 -54
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/cli/index.mjs +198 -40
  4. package/dist/cli/index.mjs.map +1 -1
  5. package/dist/index.d.mts +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +1 -1
  8. package/dist/index.mjs +1 -1
  9. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +3256 -0
  10. package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +710 -0
  11. package/dist/repo/apps/play-runner-workers/src/entry.ts +5070 -0
  12. package/dist/repo/apps/play-runner-workers/src/runtime/README.md +21 -0
  13. package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +177 -0
  14. package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +52 -0
  15. package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +100 -0
  16. package/dist/repo/apps/play-runner-workers/src/runtime/tool-result.ts +184 -0
  17. package/dist/repo/sdk/src/cli/commands/auth.ts +482 -0
  18. package/dist/repo/sdk/src/cli/commands/billing.ts +188 -0
  19. package/dist/repo/sdk/src/cli/commands/csv.ts +123 -0
  20. package/dist/repo/sdk/src/cli/commands/db.ts +119 -0
  21. package/dist/repo/sdk/src/cli/commands/feedback.ts +40 -0
  22. package/dist/repo/sdk/src/cli/commands/org.ts +117 -0
  23. package/dist/repo/sdk/src/cli/commands/play.ts +3200 -0
  24. package/dist/repo/sdk/src/cli/commands/tools.ts +687 -0
  25. package/dist/repo/sdk/src/cli/dataset-stats.ts +341 -0
  26. package/dist/repo/sdk/src/cli/index.ts +138 -0
  27. package/dist/repo/sdk/src/cli/progress.ts +135 -0
  28. package/dist/repo/sdk/src/cli/trace.ts +61 -0
  29. package/dist/repo/sdk/src/cli/utils.ts +145 -0
  30. package/dist/repo/sdk/src/client.ts +1188 -0
  31. package/dist/repo/sdk/src/compat.ts +77 -0
  32. package/dist/repo/sdk/src/config.ts +285 -0
  33. package/dist/repo/sdk/src/errors.ts +125 -0
  34. package/dist/repo/sdk/src/http.ts +391 -0
  35. package/dist/repo/sdk/src/index.ts +139 -0
  36. package/dist/repo/sdk/src/play.ts +1330 -0
  37. package/dist/repo/sdk/src/plays/bundle-play-file.ts +133 -0
  38. package/dist/repo/sdk/src/plays/harness-stub.ts +210 -0
  39. package/dist/repo/sdk/src/plays/local-file-discovery.ts +326 -0
  40. package/dist/repo/sdk/src/tool-output.ts +489 -0
  41. package/dist/repo/sdk/src/types.ts +669 -0
  42. package/dist/repo/sdk/src/version.ts +2 -0
  43. package/dist/repo/sdk/src/worker-play-entry.ts +286 -0
  44. package/dist/repo/shared_libs/observability/node-tracing.ts +129 -0
  45. package/dist/repo/shared_libs/observability/tracing.ts +98 -0
  46. package/dist/repo/shared_libs/play-runtime/backend.ts +139 -0
  47. package/dist/repo/shared_libs/play-runtime/batch-runtime.ts +182 -0
  48. package/dist/repo/shared_libs/play-runtime/batching-types.ts +91 -0
  49. package/dist/repo/shared_libs/play-runtime/context.ts +3999 -0
  50. package/dist/repo/shared_libs/play-runtime/coordinator-headers.ts +78 -0
  51. package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +250 -0
  52. package/dist/repo/shared_libs/play-runtime/ctx-types.ts +713 -0
  53. package/dist/repo/shared_libs/play-runtime/dataset-id.ts +10 -0
  54. package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +304 -0
  55. package/dist/repo/shared_libs/play-runtime/db-session.ts +462 -0
  56. package/dist/repo/shared_libs/play-runtime/dedup-backend.ts +0 -0
  57. package/dist/repo/shared_libs/play-runtime/default-batch-strategies.ts +124 -0
  58. package/dist/repo/shared_libs/play-runtime/execution-plan.ts +262 -0
  59. package/dist/repo/shared_libs/play-runtime/live-events.ts +214 -0
  60. package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +50 -0
  61. package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +114 -0
  62. package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +158 -0
  63. package/dist/repo/shared_libs/play-runtime/profiles.ts +90 -0
  64. package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +172 -0
  65. package/dist/repo/shared_libs/play-runtime/protocol.ts +121 -0
  66. package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +42 -0
  67. package/dist/repo/shared_libs/play-runtime/result-normalization.ts +33 -0
  68. package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +208 -0
  69. package/dist/repo/shared_libs/play-runtime/runtime-api.ts +1873 -0
  70. package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +2 -0
  71. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +201 -0
  72. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +48 -0
  73. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +84 -0
  74. package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +174 -0
  75. package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +147 -0
  76. package/dist/repo/shared_libs/play-runtime/suspension.ts +68 -0
  77. package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +146 -0
  78. package/dist/repo/shared_libs/play-runtime/tool-result.ts +387 -0
  79. package/dist/repo/shared_libs/play-runtime/tracing.ts +31 -0
  80. package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +75 -0
  81. package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +140 -0
  82. package/dist/repo/shared_libs/plays/artifact-transport.ts +14 -0
  83. package/dist/repo/shared_libs/plays/artifact-types.ts +49 -0
  84. package/dist/repo/shared_libs/plays/bundling/index.ts +1346 -0
  85. package/dist/repo/shared_libs/plays/compiler-manifest.ts +186 -0
  86. package/dist/repo/shared_libs/plays/contracts.ts +51 -0
  87. package/dist/repo/shared_libs/plays/dataset.ts +308 -0
  88. package/dist/repo/shared_libs/plays/definition.ts +264 -0
  89. package/dist/repo/shared_libs/plays/file-refs.ts +11 -0
  90. package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +206 -0
  91. package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +164 -0
  92. package/dist/repo/shared_libs/plays/row-identity.ts +302 -0
  93. package/dist/repo/shared_libs/plays/runtime-validation.ts +415 -0
  94. package/dist/repo/shared_libs/plays/static-pipeline.ts +560 -0
  95. package/dist/repo/shared_libs/temporal/constants.ts +39 -0
  96. package/dist/repo/shared_libs/temporal/preview-config.ts +153 -0
  97. package/package.json +4 -4
@@ -0,0 +1,2 @@
1
+ export const DISALLOWED_RUN_JAVASCRIPT_TOOL_MESSAGE =
2
+ 'No run_javascript tool in plays. Just write regular code.';
@@ -0,0 +1,201 @@
1
+ /**
2
+ * `@neondatabase/serverless` Pool factory. Installed at boot by the
3
+ * workers_edge dynamic Worker harness. The serverless driver speaks the
4
+ * same Postgres wire protocol as `pg` but uses Neon's WebSocket proxy
5
+ * (or HTTP endpoint) so it works inside the workerd V8 isolate where raw
6
+ * TCP is unavailable.
7
+ *
8
+ * ## Lazy loading (the actual implementation)
9
+ *
10
+ * `@neondatabase/serverless` is ~143 KB minified — a non-trivial fraction
11
+ * of every per-graphHash play Worker bundle. The harness's
12
+ * `installNeonServerlessRuntimePoolDriver()` fires unconditionally at
13
+ * isolate startup, but the heavy module is loaded ON FIRST `pool.connect()`
14
+ * via dynamic `import('@neondatabase/serverless')`. Plays that never open
15
+ * a Postgres pool (csv-only, computation-only, tool-only plays) skip the
16
+ * import entirely, even though the driver registration ran at boot.
17
+ *
18
+ * Concretely:
19
+ * - Bundle still contains the dynamic-import path → `@neondatabase/serverless`
20
+ * is still in the per-play bundle (esbuild emits it as a deferred chunk
21
+ * in `format: 'esm'`, but workerd inlines all chunks for a Worker —
22
+ * so the bytes are still in the worker's compiled code).
23
+ * - V8 PARSE / COMPILE for those bytes is also deferred until the first
24
+ * `import()` call resolves; modern V8 does parse-on-demand for ESM
25
+ * dynamic imports. So plays that never connect skip the parse cost.
26
+ * - Plays that DO connect pay the import cost once per isolate, then
27
+ * reuse the cached module + pool for the rest of the run.
28
+ *
29
+ * If you change this file, double-check by:
30
+ * 1. Bundling a play that doesn't use `ctx.dataset` / postgres ops
31
+ * (e.g. tests/v2-plays/plays/03-tool-basic.play.ts).
32
+ * 2. Confirm the resulting bundle still references
33
+ * `@neondatabase/serverless` (the dynamic import path is preserved
34
+ * as a string), but no top-level `Pool` symbol is constructed.
35
+ * 3. Confirm that creating an actual pool via `createRuntimePool` in
36
+ * a test still resolves and returns a working client.
37
+ *
38
+ * Why we don't just `external: ['@neondatabase/serverless']` in
39
+ * bundle-play-file.ts:
40
+ * The `@neondatabase/serverless` package isn't provided by the
41
+ * workerd runtime — marking it external would crash the Worker on
42
+ * first import lookup. The lazy dynamic import is the right pattern:
43
+ * esbuild bundles the module, but its CODE STARTUP COST (parse +
44
+ * compile) is paid only when the import resolves.
45
+ */
46
+
47
+ import {
48
+ registerRuntimePoolFactory,
49
+ type RuntimePool,
50
+ type RuntimePoolClient,
51
+ } from './runtime-pg-driver';
52
+
53
+ /**
54
+ * Minimal local types for the Neon module's runtime surface.
55
+ *
56
+ * We INTENTIONALLY don't `import type { Pool, PoolClient } from
57
+ * '@neondatabase/serverless'` here — that would force tsc to read the
58
+ * package's full type tree on every typecheck, slowing the build, and
59
+ * the package's overloaded `connect()` resolves through types in a way
60
+ * that surfaces as `void` in some TS configurations.
61
+ *
62
+ * The minimal shape is just:
63
+ * - Pool ctor takes a config bag
64
+ * - Pool instance has connect() / end()
65
+ * - PoolClient instance has query() / release()
66
+ *
67
+ * If Neon ever changes this surface, the runtime cast will fail loudly
68
+ * the first time a play tries to use Postgres — which is exactly when
69
+ * we want to find out.
70
+ */
71
+ interface NeonPoolClient {
72
+ query<R = Record<string, unknown>>(
73
+ text: string,
74
+ params?: unknown[],
75
+ ): Promise<{ rows: R[] }>;
76
+ release(): void;
77
+ }
78
+
79
+ interface NeonPoolInstance {
80
+ connect(): Promise<NeonPoolClient>;
81
+ end(): Promise<void>;
82
+ }
83
+
84
+ interface NeonPoolConfig {
85
+ connectionString: string;
86
+ max?: number;
87
+ idleTimeoutMillis?: number;
88
+ connectionTimeoutMillis?: number;
89
+ }
90
+
91
+ interface NeonModule {
92
+ Pool: new (config: NeonPoolConfig) => NeonPoolInstance;
93
+ }
94
+
95
+ /**
96
+ * Cached promise of the loaded Neon module. Once the first connect()
97
+ * resolves, every subsequent connect on the same isolate hits this
98
+ * cache instead of re-importing.
99
+ *
100
+ * We cache the PROMISE rather than the resolved module so concurrent
101
+ * first-connect calls coalesce onto a single import — V8's module
102
+ * loader is already idempotent for the same specifier, but caching at
103
+ * this layer makes the contract obvious to readers.
104
+ */
105
+ let neonModulePromise: Promise<NeonModule> | null = null;
106
+ function loadNeonModule(): Promise<NeonModule> {
107
+ if (!neonModulePromise) {
108
+ neonModulePromise = import('@neondatabase/serverless') as unknown as Promise<NeonModule>;
109
+ }
110
+ return neonModulePromise;
111
+ }
112
+
113
+ function wrapNeonClient(client: NeonPoolClient): RuntimePoolClient {
114
+ return {
115
+ query: <R extends Record<string, unknown> = Record<string, unknown>>(
116
+ text: string,
117
+ params?: unknown[],
118
+ ) =>
119
+ (client.query as unknown as (
120
+ t: string,
121
+ p?: unknown[],
122
+ ) => Promise<{ rows: R[] }>)(text, params),
123
+ release: () => {
124
+ client.release();
125
+ },
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Wrap a Neon `Pool` instance as our internal `RuntimePool` shape.
131
+ * `connect()` and `end()` are async on both sides, so this is a thin
132
+ * adapter — no logic, just type marshaling.
133
+ */
134
+ function wrapNeonPool(pool: NeonPoolInstance): RuntimePool {
135
+ return {
136
+ connect: async () =>
137
+ wrapNeonClient((await pool.connect()) as unknown as NeonPoolClient),
138
+ end: async () => {
139
+ await pool.end();
140
+ },
141
+ };
142
+ }
143
+
144
+ /**
145
+ * Install the Neon-backed pool factory. Called once at Worker isolate
146
+ * boot — `registerRuntimePoolFactory` is idempotent and throws if a
147
+ * different factory was already registered (build-config bug).
148
+ *
149
+ * The factory itself is SYNCHRONOUS (returns a `RuntimePool`) but the
150
+ * underlying Neon Pool is created LAZILY: we capture the connection
151
+ * config in a closure and instantiate the real `Pool` on first
152
+ * `connect()`. Until then, no `@neondatabase/serverless` runtime code
153
+ * runs in the isolate — V8 doesn't parse the dynamic-imported chunk
154
+ * until the import() resolves.
155
+ */
156
+ export function installNeonServerlessRuntimePoolDriver(): void {
157
+ registerRuntimePoolFactory((input) => {
158
+ // Captured lazily so a Pool is only constructed if the play actually
159
+ // connects. Most plays that don't touch Postgres directly never even
160
+ // reach this branch — the factory is registered but never invoked.
161
+ let lazyPool: NeonPoolInstance | null = null;
162
+
163
+ /**
164
+ * Resolve the lazy Pool, creating it on first call.
165
+ *
166
+ * Race safety: workerd executes within a single JS event loop, so
167
+ * two concurrent `connect()` calls on the SAME wrapper run their
168
+ * "lazyPool == null" checks in turn — the first creates the Pool,
169
+ * the second sees it. No locking needed.
170
+ *
171
+ * If pool creation fails (e.g. DNS, bad connection string), the
172
+ * error propagates out of connect() to the caller. We don't cache
173
+ * a failed pool so retries can succeed on transient failures.
174
+ */
175
+ async function ensurePool(): Promise<NeonPoolInstance> {
176
+ if (lazyPool) return lazyPool;
177
+ const neon = await loadNeonModule();
178
+ const pool = new neon.Pool({
179
+ connectionString: input.connectionString,
180
+ max: input.maxConnections ?? 4,
181
+ idleTimeoutMillis: input.idleTimeoutMs ?? 15_000,
182
+ connectionTimeoutMillis: input.connectTimeoutMs ?? 10_000,
183
+ });
184
+ lazyPool = pool;
185
+ return pool;
186
+ }
187
+
188
+ return {
189
+ connect: async () => {
190
+ const pool = await ensurePool();
191
+ return wrapNeonClient(await pool.connect());
192
+ },
193
+ end: async () => {
194
+ if (lazyPool) {
195
+ await lazyPool.end();
196
+ lazyPool = null;
197
+ }
198
+ },
199
+ };
200
+ });
201
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * pg-backed Pool factory. Installed at boot by the Node-runtime
3
+ * play-runner (Daytona/local). NOT used by the workers_edge harness — pg's
4
+ * raw TCP socket usage is banned in workerd.
5
+ */
6
+ import { Pool, type PoolClient } from 'pg';
7
+ import {
8
+ registerRuntimePoolFactory,
9
+ type RuntimePool,
10
+ type RuntimePoolClient,
11
+ } from './runtime-pg-driver';
12
+
13
+ function wrapPgClient(client: PoolClient): RuntimePoolClient {
14
+ return {
15
+ query: <R extends Record<string, unknown> = Record<string, unknown>>(
16
+ text: string,
17
+ params?: unknown[],
18
+ ) =>
19
+ (client.query as unknown as (
20
+ t: string,
21
+ p?: unknown[],
22
+ ) => Promise<{ rows: R[] }>)(text, params).then((result) => ({
23
+ rows: result.rows,
24
+ })),
25
+ release: () => {
26
+ client.release();
27
+ },
28
+ };
29
+ }
30
+
31
+ function wrapPgPool(pool: Pool): RuntimePool {
32
+ return {
33
+ connect: async () => wrapPgClient(await pool.connect()),
34
+ end: () => pool.end(),
35
+ };
36
+ }
37
+
38
+ export function installPgRuntimePoolDriver(): void {
39
+ registerRuntimePoolFactory((input) => {
40
+ const pool = new Pool({
41
+ connectionString: input.connectionString,
42
+ max: input.maxConnections ?? 4,
43
+ idleTimeoutMillis: input.idleTimeoutMs ?? 15_000,
44
+ connectionTimeoutMillis: input.connectTimeoutMs ?? 10_000,
45
+ });
46
+ return wrapPgPool(pool);
47
+ });
48
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Driver-agnostic Postgres pool/client surface used by the runtime data plane.
3
+ *
4
+ * The runtime data plane (`runtime-api.ts` direct-Neon writes) needs to run in
5
+ * two very different environments:
6
+ *
7
+ * - Node (Daytona/local play-runner) — uses the `pg` library, raw TCP to Neon.
8
+ * - Cloudflare Workers (workers_edge harness) — `pg` cannot bundle (raw TCP
9
+ * is banned at workerd boundary), so we use `@neondatabase/serverless`
10
+ * which speaks the same Postgres wire protocol over a WebSocket proxy.
11
+ *
12
+ * Rather than `if-platform` branches inside runtime-api.ts, each runtime
13
+ * registers its driver once at boot and the rest of the code uses the
14
+ * abstract `RuntimePool` / `RuntimePoolClient` types. Both `pg` and
15
+ * `@neondatabase/serverless` already expose the relevant subset of the
16
+ * `pg` API surface (`pool.connect()` → `client.query() / .release()`), so
17
+ * the wrappers are thin.
18
+ */
19
+
20
+ export interface RuntimePoolClient {
21
+ query<R extends Record<string, unknown> = Record<string, unknown>>(
22
+ text: string,
23
+ params?: unknown[],
24
+ ): Promise<{ rows: R[] }>;
25
+ release(): void;
26
+ }
27
+
28
+ export interface RuntimePool {
29
+ connect(): Promise<RuntimePoolClient>;
30
+ end(): Promise<void>;
31
+ }
32
+
33
+ export type RuntimePoolFactory = (input: {
34
+ connectionString: string;
35
+ /** Soft cap on simultaneous connections; defaults to 4. */
36
+ maxConnections?: number;
37
+ /** Idle timeout in ms before pool tears down a connection; defaults to 15000. */
38
+ idleTimeoutMs?: number;
39
+ /** Connect timeout in ms; defaults to 10000. */
40
+ connectTimeoutMs?: number;
41
+ }) => RuntimePool;
42
+
43
+ let registeredFactory: RuntimePoolFactory | null = null;
44
+
45
+ /**
46
+ * Install a Pool factory at process / Worker boot. Idempotent — calling twice
47
+ * with different factories will throw to prevent silent driver swaps that
48
+ * would otherwise drop in-flight pooled connections.
49
+ */
50
+ export function registerRuntimePoolFactory(factory: RuntimePoolFactory): void {
51
+ if (registeredFactory && registeredFactory !== factory) {
52
+ throw new Error(
53
+ 'A different runtime Postgres pool factory is already registered. ' +
54
+ 'This is a build-config bug — only one driver should be installed per process.',
55
+ );
56
+ }
57
+ registeredFactory = factory;
58
+ }
59
+
60
+ export function isRuntimePoolFactoryRegistered(): boolean {
61
+ return registeredFactory !== null;
62
+ }
63
+
64
+ export function createRuntimePool(input: {
65
+ connectionString: string;
66
+ maxConnections?: number;
67
+ idleTimeoutMs?: number;
68
+ connectTimeoutMs?: number;
69
+ }): RuntimePool {
70
+ if (!registeredFactory) {
71
+ throw new Error(
72
+ 'No runtime Postgres pool factory registered. Call ' +
73
+ 'installPgRuntimePoolDriver() (Node) or ' +
74
+ 'installNeonServerlessRuntimePoolDriver() (Workers) at boot before ' +
75
+ 'using runtime-api Postgres helpers.',
76
+ );
77
+ }
78
+ return registeredFactory(input);
79
+ }
80
+
81
+ /** Test seam — clears the registered factory so a test can swap drivers. */
82
+ export function __resetRuntimePoolFactoryForTests(): void {
83
+ registeredFactory = null;
84
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Scheduler-backend interface — owns play workflow lifecycle.
3
+ *
4
+ * One of three pluggable axes (alongside runner-backends and dedup-backends).
5
+ * Selected per-run via PlayExecutionProfile.
6
+ *
7
+ * Temporal is the existing production scheduler. Cloudflare Workflows is the
8
+ * edge scheduler used by the workers_edge profile.
9
+ *
10
+ * Customer plays are unaffected — this is purely the orchestration layer.
11
+ */
12
+
13
+ import type {
14
+ PlayCheckpoint,
15
+ PlayExecutionEvent,
16
+ PlayRowUpdate,
17
+ } from './ctx-types';
18
+ import type { ExecutionPlan } from './execution-plan';
19
+ import type { PlayRuntimeManifestMap } from '../plays/compiler-manifest';
20
+
21
+ export const PLAY_SCHEDULER_BACKENDS = {
22
+ temporal: 'temporal',
23
+ cfWorkflows: 'cf-workflows',
24
+ inProcess: 'in-process',
25
+ } as const;
26
+
27
+ export type PlaySchedulerBackendId =
28
+ (typeof PLAY_SCHEDULER_BACKENDS)[keyof typeof PLAY_SCHEDULER_BACKENDS];
29
+
30
+ export type PlayCallGovernanceSnapshot = {
31
+ rootRunId: string;
32
+ parentRunId: string;
33
+ parentPlayName: string;
34
+ key: string;
35
+ ancestryPlayIds: string[];
36
+ callDepth: number;
37
+ };
38
+
39
+ export type PlaySchedulerSubmitInput = {
40
+ runId: string;
41
+ playId: string;
42
+ playName: string;
43
+ artifactStorageKey: string;
44
+ artifactHash: string;
45
+ graphHash: string;
46
+ input: Record<string, unknown>;
47
+ inputFile?: {
48
+ name?: string;
49
+ path?: string;
50
+ r2Key?: string;
51
+ storageKey?: string;
52
+ fileName?: string;
53
+ logicalPath?: string;
54
+ } | null;
55
+ inlineCsv?: { name: string; rows: Record<string, unknown>[] } | null;
56
+ /**
57
+ * Tiny input files (<= WORKERS_EDGE_INLINE_INPUT_MAX_BYTES) carried as raw
58
+ * base64 bytes through the scheduler submit so the cf-workflows backend can
59
+ * build inlineCsv without an R2 PUT+GET round trip. Mirrors the
60
+ * Temporal-side `inlineInputFile` fast path.
61
+ */
62
+ inlineInputFile?: {
63
+ logicalPath: string;
64
+ fileName: string;
65
+ contentBase64: string;
66
+ contentType: string;
67
+ bytes: number;
68
+ } | null;
69
+ packagedFiles?: Array<{
70
+ playPath?: string;
71
+ logicalPath?: string;
72
+ fileName?: string;
73
+ storageKey: string;
74
+ contentType?: string;
75
+ bytes?: number;
76
+ inlineText?: string;
77
+ }> | null;
78
+ contractSnapshot?: unknown;
79
+ executionPlan?: ExecutionPlan | null;
80
+ childPlayManifests?: PlayRuntimeManifestMap | null;
81
+ playCallGovernance?: PlayCallGovernanceSnapshot | null;
82
+ /** Optional immutable Worker module source for local Dynamic Worker loading. */
83
+ dynamicWorkerCode?: string | null;
84
+ executorToken: string;
85
+ baseUrl: string;
86
+ orgId: string;
87
+ userEmail: string;
88
+ userId?: string | null;
89
+ /** runner backend to use for executing attempts */
90
+ runtimeBackend: string;
91
+ /** dedup backend for cross-attempt cross-process idempotency */
92
+ dedupBackend: string;
93
+ /** If known at submit time, total input rows (for partition decisions). */
94
+ totalRows?: number;
95
+ /** Internal scheduler/coordinator URL for Worker-side capabilities. */
96
+ coordinatorUrl?: string | null;
97
+ };
98
+
99
+ export type PlaySchedulerProgressEvent =
100
+ | { type: 'status'; status: string; logs?: string[]; ts: number }
101
+ | { type: 'log'; line: string; ts: number }
102
+ | { type: 'row'; update: PlayRowUpdate; ts: number }
103
+ | { type: 'execution_event'; event: PlayExecutionEvent; ts: number }
104
+ | { type: 'completed'; result: unknown; ts: number }
105
+ | { type: 'failed'; error: string; ts: number }
106
+ | { type: 'suspended'; reason: string; ts: number };
107
+
108
+ export type PlaySchedulerRunHandle = {
109
+ runId: string;
110
+ /**
111
+ * Optional snapshot of the run's state captured during submit() so callers
112
+ * can skip an immediate follow-up status read. Populated by backends that
113
+ * piggyback the read on the create round-trip (currently cf-workflows).
114
+ */
115
+ initialState?: Record<string, unknown> | null;
116
+ /**
117
+ * Stream live progress events. Implementations may use SSE, polling, etc.
118
+ * The contract: yields events in order until terminal status.
119
+ */
120
+ observe(): AsyncIterable<PlaySchedulerProgressEvent>;
121
+ /** Cooperatively cancel the run. */
122
+ cancel(): Promise<void>;
123
+ /** Inject an external event (HITL, webhook). */
124
+ signal(payload: PlaySchedulerSignalPayload): Promise<void>;
125
+ /** Block until terminal state and return final envelope. */
126
+ result(): Promise<PlaySchedulerResultEnvelope>;
127
+ };
128
+
129
+ export type PlaySchedulerSignalPayload = {
130
+ kind: 'integration_event' | 'cancel' | 'custom';
131
+ eventKey?: string;
132
+ data?: unknown;
133
+ };
134
+
135
+ export type PlaySchedulerResultEnvelope = {
136
+ runId: string;
137
+ status: 'completed' | 'failed' | 'cancelled';
138
+ output?: unknown;
139
+ error?: string;
140
+ finalCheckpoint?: PlayCheckpoint;
141
+ totalRows?: number;
142
+ durationMs?: number;
143
+ };
144
+
145
+ export interface PlaySchedulerBackend {
146
+ readonly id: PlaySchedulerBackendId;
147
+
148
+ /** Submit a play run; returns a handle to observe / cancel / signal it. */
149
+ submit(input: PlaySchedulerSubmitInput): Promise<PlaySchedulerRunHandle>;
150
+
151
+ /** Open a handle to an already-submitted run (e.g. for tail-reconnect). */
152
+ attach(
153
+ runId: string,
154
+ options?: { coordinatorUrl?: string | null },
155
+ ): Promise<PlaySchedulerRunHandle>;
156
+ }
157
+
158
+ export function normalizePlaySchedulerBackend(
159
+ value?: string | null,
160
+ ): PlaySchedulerBackendId {
161
+ const normalized = value?.trim().toLowerCase();
162
+ if (!normalized || normalized === 'temporal') {
163
+ return PLAY_SCHEDULER_BACKENDS.temporal;
164
+ }
165
+ if (normalized === 'cf-workflows' || normalized === 'cf_workflows') {
166
+ return PLAY_SCHEDULER_BACKENDS.cfWorkflows;
167
+ }
168
+ if (normalized === 'in-process' || normalized === 'in_process') {
169
+ return PLAY_SCHEDULER_BACKENDS.inProcess;
170
+ }
171
+ throw new Error(
172
+ `Unsupported scheduler backend "${normalized}". Expected one of: ${Object.values(PLAY_SCHEDULER_BACKENDS).join(', ')}.`,
173
+ );
174
+ }
@@ -0,0 +1,147 @@
1
+ export interface PlayStaticPipeline {
2
+ tableNamespace?: string;
3
+ inputFields?: string[];
4
+ csvArg?: string;
5
+ hasInlineData?: boolean;
6
+ csvDescription?: string;
7
+ mapDescription?: string;
8
+ fields: string[];
9
+ stages?: PlayStaticSubstep[];
10
+ substeps: PlayStaticSubstep[];
11
+ sheetContract?: PlaySheetContract | null;
12
+ sheetContractErrors?: string[];
13
+ }
14
+
15
+ export type PlaySheetColumnSource =
16
+ | 'input'
17
+ | 'mapField'
18
+ | 'waterfallStep'
19
+ | 'childPlayColumn';
20
+
21
+ export interface PlaySheetColumnContract {
22
+ id: string;
23
+ sqlName: string;
24
+ source: PlaySheetColumnSource;
25
+ field?: string;
26
+ parentField?: string;
27
+ playId?: string;
28
+ waterfallId?: string;
29
+ outputField?: string;
30
+ outputSqlName?: string;
31
+ stepId?: string;
32
+ toolId?: string;
33
+ }
34
+
35
+ export interface PlaySheetContract {
36
+ tableNamespace: string;
37
+ columns: PlaySheetColumnContract[];
38
+ }
39
+
40
+ export interface PlayStaticSourceRange {
41
+ sourcePath?: string;
42
+ startLine: number;
43
+ endLine: number;
44
+ startColumn: number;
45
+ endColumn: number;
46
+ }
47
+
48
+ type PlayStaticSubstepMetadata = {
49
+ conditional?: boolean;
50
+ };
51
+
52
+ export type PlayStaticSubstep = PlayStaticSubstepMetadata &
53
+ (
54
+ | {
55
+ type: 'csv';
56
+ field: string;
57
+ path?: string;
58
+ description?: string;
59
+ sourceRange?: PlayStaticSourceRange;
60
+ callDepth?: number;
61
+ callPath?: string[];
62
+ }
63
+ | {
64
+ type: 'map';
65
+ field: string;
66
+ name?: string;
67
+ tableNamespace?: string;
68
+ inputFields?: string[];
69
+ outputFields?: string[];
70
+ waterfallIds?: string[];
71
+ sheetContract?: PlaySheetContract | null;
72
+ description?: string;
73
+ sourceRange?: PlayStaticSourceRange;
74
+ callDepth?: number;
75
+ callPath?: string[];
76
+ }
77
+ | {
78
+ type: 'tool';
79
+ toolId: string;
80
+ field: string;
81
+ description?: string;
82
+ inLoop?: boolean;
83
+ isEventWait?: boolean;
84
+ sourceRange?: PlayStaticSourceRange;
85
+ callDepth?: number;
86
+ callPath?: string[];
87
+ }
88
+ | {
89
+ type: 'waterfall';
90
+ tool?: string;
91
+ field: string;
92
+ inLoop?: boolean;
93
+ id?: string;
94
+ output?: string;
95
+ minResults?: number;
96
+ sourceText?: string;
97
+ steps?: Array<{
98
+ id: string;
99
+ kind?: 'tool' | 'code';
100
+ toolId?: string;
101
+ paramsSource?: string;
102
+ }>;
103
+ description?: string;
104
+ sourceRange?: PlayStaticSourceRange;
105
+ callDepth?: number;
106
+ callPath?: string[];
107
+ }
108
+ | {
109
+ type: 'step_suite';
110
+ field: string;
111
+ steps: PlayStaticSubstep[];
112
+ returnSource?: string;
113
+ description?: string;
114
+ sourceRange?: PlayStaticSourceRange;
115
+ callDepth?: number;
116
+ callPath?: string[];
117
+ }
118
+ | {
119
+ type: 'play_call';
120
+ playId: string;
121
+ field: string;
122
+ inLoop?: boolean;
123
+ pipeline?: PlayStaticPipeline | null;
124
+ cycleDetected?: boolean;
125
+ resolutionError?: string;
126
+ description?: string;
127
+ sourceRange?: PlayStaticSourceRange;
128
+ callDepth?: number;
129
+ callPath?: string[];
130
+ }
131
+ | {
132
+ type: 'run_javascript';
133
+ alias: string;
134
+ description?: string;
135
+ sourceRange?: PlayStaticSourceRange;
136
+ callDepth?: number;
137
+ callPath?: string[];
138
+ }
139
+ | {
140
+ type: 'code';
141
+ field: string;
142
+ description?: string;
143
+ sourceRange?: PlayStaticSourceRange;
144
+ callDepth?: number;
145
+ callPath?: string[];
146
+ }
147
+ );