deepline 0.1.12 → 0.1.19

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 (80) hide show
  1. package/README.md +14 -6
  2. package/dist/cli/index.js +1298 -711
  3. package/dist/cli/index.mjs +1294 -707
  4. package/dist/index.d.mts +199 -23
  5. package/dist/index.d.ts +199 -23
  6. package/dist/index.js +219 -13
  7. package/dist/index.mjs +219 -13
  8. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +68 -12
  9. package/dist/repo/apps/play-runner-workers/src/entry.ts +241 -51
  10. package/dist/repo/sdk/src/client.ts +237 -0
  11. package/dist/repo/sdk/src/config.ts +125 -8
  12. package/dist/repo/sdk/src/http.ts +10 -2
  13. package/dist/repo/sdk/src/play.ts +19 -36
  14. package/dist/repo/sdk/src/plays/bundle-play-file.ts +22 -8
  15. package/dist/repo/sdk/src/plays/local-file-discovery.ts +207 -160
  16. package/dist/repo/sdk/src/types.ts +25 -0
  17. package/dist/repo/sdk/src/version.ts +2 -2
  18. package/dist/repo/shared_libs/play-runtime/tool-result.ts +237 -145
  19. package/dist/repo/shared_libs/plays/bundling/index.ts +206 -229
  20. package/dist/repo/shared_libs/plays/dataset.ts +28 -0
  21. package/package.json +5 -4
  22. package/dist/cli/index.js.map +0 -1
  23. package/dist/cli/index.mjs.map +0 -1
  24. package/dist/index.js.map +0 -1
  25. package/dist/index.mjs.map +0 -1
  26. package/dist/repo/apps/play-runner-workers/src/runtime/README.md +0 -21
  27. package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +0 -177
  28. package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +0 -52
  29. package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -100
  30. package/dist/repo/sdk/src/cli/commands/auth.ts +0 -500
  31. package/dist/repo/sdk/src/cli/commands/billing.ts +0 -188
  32. package/dist/repo/sdk/src/cli/commands/csv.ts +0 -123
  33. package/dist/repo/sdk/src/cli/commands/db.ts +0 -119
  34. package/dist/repo/sdk/src/cli/commands/feedback.ts +0 -40
  35. package/dist/repo/sdk/src/cli/commands/org.ts +0 -117
  36. package/dist/repo/sdk/src/cli/commands/play.ts +0 -3441
  37. package/dist/repo/sdk/src/cli/commands/tools.ts +0 -687
  38. package/dist/repo/sdk/src/cli/dataset-stats.ts +0 -415
  39. package/dist/repo/sdk/src/cli/index.ts +0 -148
  40. package/dist/repo/sdk/src/cli/progress.ts +0 -149
  41. package/dist/repo/sdk/src/cli/skills-sync.ts +0 -141
  42. package/dist/repo/sdk/src/cli/trace.ts +0 -61
  43. package/dist/repo/sdk/src/cli/utils.ts +0 -145
  44. package/dist/repo/sdk/src/compat.ts +0 -77
  45. package/dist/repo/shared_libs/observability/node-tracing.ts +0 -129
  46. package/dist/repo/shared_libs/observability/tracing.ts +0 -98
  47. package/dist/repo/shared_libs/play-runtime/context.ts +0 -4242
  48. package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +0 -250
  49. package/dist/repo/shared_libs/play-runtime/ctx-types.ts +0 -725
  50. package/dist/repo/shared_libs/play-runtime/dataset-id.ts +0 -10
  51. package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +0 -304
  52. package/dist/repo/shared_libs/play-runtime/db-session.ts +0 -462
  53. package/dist/repo/shared_libs/play-runtime/live-events.ts +0 -214
  54. package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +0 -50
  55. package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +0 -114
  56. package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +0 -158
  57. package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +0 -172
  58. package/dist/repo/shared_libs/play-runtime/protocol.ts +0 -121
  59. package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +0 -42
  60. package/dist/repo/shared_libs/play-runtime/result-normalization.ts +0 -33
  61. package/dist/repo/shared_libs/play-runtime/runtime-api.ts +0 -1873
  62. package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +0 -2
  63. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -201
  64. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +0 -48
  65. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +0 -84
  66. package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +0 -147
  67. package/dist/repo/shared_libs/play-runtime/suspension.ts +0 -68
  68. package/dist/repo/shared_libs/play-runtime/tracing.ts +0 -31
  69. package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +0 -75
  70. package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +0 -140
  71. package/dist/repo/shared_libs/plays/artifact-transport.ts +0 -14
  72. package/dist/repo/shared_libs/plays/artifact-types.ts +0 -49
  73. package/dist/repo/shared_libs/plays/compiler-manifest.ts +0 -186
  74. package/dist/repo/shared_libs/plays/definition.ts +0 -264
  75. package/dist/repo/shared_libs/plays/file-refs.ts +0 -11
  76. package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +0 -206
  77. package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +0 -164
  78. package/dist/repo/shared_libs/plays/runtime-validation.ts +0 -395
  79. package/dist/repo/shared_libs/temporal/constants.ts +0 -39
  80. package/dist/repo/shared_libs/temporal/preview-config.ts +0 -153
@@ -1,2 +0,0 @@
1
- export const DISALLOWED_RUN_JAVASCRIPT_TOOL_MESSAGE =
2
- 'No run_javascript tool in plays. Just write regular code.';
@@ -1,201 +0,0 @@
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
- }
@@ -1,48 +0,0 @@
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
- }
@@ -1,84 +0,0 @@
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
- }
@@ -1,147 +0,0 @@
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
- );
@@ -1,68 +0,0 @@
1
- export type PlayExecutionSuspension =
2
- | {
3
- kind: 'sleep';
4
- boundaryId: string;
5
- delayMs: number;
6
- }
7
- | {
8
- kind: 'integration_event';
9
- boundaryId: string;
10
- eventKey: string;
11
- timeoutMs: number;
12
- }
13
- | {
14
- kind: 'integration_event_batch';
15
- boundaries: Array<{
16
- boundaryId: string;
17
- eventKey: string;
18
- timeoutMs: number;
19
- }>;
20
- };
21
-
22
- export class PlayExecutionSuspendedError extends Error {
23
- readonly suspension: PlayExecutionSuspension;
24
-
25
- constructor(suspension: PlayExecutionSuspension) {
26
- super(
27
- suspension.kind === 'sleep'
28
- ? `Play execution suspended for durable sleep (${suspension.delayMs}ms).`
29
- : suspension.kind === 'integration_event_batch'
30
- ? `Play execution suspended waiting for ${suspension.boundaries.length} integration events.`
31
- : `Play execution suspended waiting for integration event ${JSON.stringify(suspension.eventKey)}.`,
32
- );
33
- this.name = 'PlayExecutionSuspendedError';
34
- this.suspension = suspension;
35
- }
36
- }
37
-
38
- export class PlayRowExecutionSuspendedError extends Error {
39
- readonly boundary: {
40
- boundaryId: string;
41
- eventKey: string;
42
- timeoutMs: number;
43
- };
44
-
45
- constructor(boundary: {
46
- boundaryId: string;
47
- eventKey: string;
48
- timeoutMs: number;
49
- }) {
50
- super(
51
- `Play row execution suspended waiting for integration event ${JSON.stringify(boundary.eventKey)}.`,
52
- );
53
- this.name = 'PlayRowExecutionSuspendedError';
54
- this.boundary = boundary;
55
- }
56
- }
57
-
58
- export function isPlayRowExecutionSuspendedError(
59
- value: unknown,
60
- ): value is PlayRowExecutionSuspendedError {
61
- return value instanceof PlayRowExecutionSuspendedError;
62
- }
63
-
64
- export function isPlayExecutionSuspendedError(
65
- value: unknown,
66
- ): value is PlayExecutionSuspendedError {
67
- return value instanceof PlayExecutionSuspendedError;
68
- }
@@ -1,31 +0,0 @@
1
- type SpanLike = {
2
- setAttribute: (key: string, value: unknown) => void;
3
- };
4
-
5
- type SpanOptions = {
6
- tracer?: string;
7
- attributes?: Record<string, unknown>;
8
- };
9
-
10
- export function setSpanAttributes(
11
- span: SpanLike | null | undefined,
12
- attributes: Record<string, unknown>,
13
- ): void {
14
- for (const [key, value] of Object.entries(attributes)) {
15
- span?.setAttribute?.(key, value);
16
- }
17
- }
18
-
19
- export async function withActiveSpan<T>(
20
- _name: string,
21
- options: SpanOptions,
22
- fn: (span: SpanLike) => Promise<T>,
23
- ): Promise<T> {
24
- const attributes = new Map<string, unknown>(Object.entries(options.attributes ?? {}));
25
- const span: SpanLike = {
26
- setAttribute(key, value) {
27
- attributes.set(key, value);
28
- },
29
- };
30
- return await fn(span);
31
- }
@@ -1,75 +0,0 @@
1
- import type { BatchResult, PlayCheckpoint, WaterfallRequest } from './ctx-types';
2
-
3
- export class WaterfallReplayStore {
4
- constructor(private readonly checkpoint: PlayCheckpoint) {}
5
-
6
- checkpointKey(input: { rowId: number; rowKey?: string | null }): string {
7
- return input.rowKey?.trim() || String(input.rowId);
8
- }
9
-
10
- getResolved(
11
- queueKey: string,
12
- input: {
13
- rowId: number;
14
- rowKey?: string | null;
15
- },
16
- ): { found: boolean; value: unknown } {
17
- const resolved = this.checkpoint.resolvedWaterfalls[queueKey];
18
- if (!resolved) {
19
- return { found: false, value: undefined };
20
- }
21
- const durableKey = this.checkpointKey(input);
22
- if (Object.prototype.hasOwnProperty.call(resolved, durableKey)) {
23
- return { found: true, value: resolved[durableKey] };
24
- }
25
- return { found: false, value: undefined };
26
- }
27
-
28
- setResolved(
29
- queueKey: string,
30
- input: {
31
- rowId: number;
32
- rowKey?: string | null;
33
- },
34
- value: unknown,
35
- ): void {
36
- this.checkpoint.resolvedWaterfalls[queueKey] ??= {};
37
- this.checkpoint.resolvedWaterfalls[queueKey]![this.checkpointKey(input)] =
38
- value;
39
- }
40
-
41
- readProviderBatch(input: {
42
- batchKey: string;
43
- requests: readonly WaterfallRequest[];
44
- }): Array<{ request: WaterfallRequest; result: unknown | null }> | null {
45
- const cached = this.checkpoint.completedBatches[input.batchKey];
46
- if (!cached) {
47
- return null;
48
- }
49
- const recovered = cached.flatMap((entry) => {
50
- const request = input.requests.find((candidate) =>
51
- entry.rowKey
52
- ? candidate.rowKey === entry.rowKey
53
- : candidate.rowId === entry.rowId,
54
- );
55
- return request ? [{ request, result: entry.result }] : [];
56
- });
57
- return recovered.length > 0 ? recovered : null;
58
- }
59
-
60
- writeProviderBatch(
61
- batchKey: string,
62
- results: ReadonlyArray<{
63
- request: WaterfallRequest;
64
- result: unknown | null;
65
- }>,
66
- ): void {
67
- this.checkpoint.completedBatches[batchKey] = results.map(
68
- (entry): BatchResult => ({
69
- rowId: entry.request.rowId,
70
- rowKey: entry.request.rowKey ?? null,
71
- result: entry.result,
72
- }),
73
- );
74
- }
75
- }