deepline 0.1.119 → 0.1.121

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 (148) hide show
  1. package/README.md +4 -0
  2. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/README.md +21 -0
  3. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +185 -0
  4. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-batch.ts +107 -0
  5. package/dist/{repo → bundling-sources}/sdk/src/client.ts +116 -12
  6. package/dist/bundling-sources/sdk/src/compat.ts +191 -0
  7. package/dist/bundling-sources/sdk/src/gtm.ts +146 -0
  8. package/dist/bundling-sources/sdk/src/helpers.ts +12 -0
  9. package/dist/{repo → bundling-sources}/sdk/src/index.ts +2 -1
  10. package/dist/{repo → bundling-sources}/sdk/src/play.ts +3 -1
  11. package/dist/{repo → bundling-sources}/sdk/src/plays/bundle-play-file.ts +17 -5
  12. package/dist/{repo → bundling-sources}/sdk/src/release.ts +2 -2
  13. package/dist/{repo → bundling-sources}/sdk/src/runs/observe-transport.ts +2 -3
  14. package/dist/bundling-sources/shared_libs/play-data-plane/index.ts +3 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +838 -0
  16. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +5510 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/ctx-contract.ts +261 -0
  18. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +828 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/dataset-id.ts +10 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/daytona-runtime-config.ts +50 -0
  21. package/dist/bundling-sources/shared_libs/play-runtime/durability-store.ts +20 -0
  22. package/dist/bundling-sources/shared_libs/play-runtime/event-wait-tools.ts +9 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +171 -0
  24. package/dist/bundling-sources/shared_libs/play-runtime/hatchet-cold-execution-diagnosis.ts +321 -0
  25. package/dist/bundling-sources/shared_libs/play-runtime/hatchet-cold-execution-target.ts +158 -0
  26. package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +34 -0
  27. package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +34 -0
  28. package/dist/bundling-sources/shared_libs/play-runtime/live-state-contract.ts +50 -0
  29. package/dist/bundling-sources/shared_libs/play-runtime/map-execution-frame.ts +119 -0
  30. package/dist/{repo → bundling-sources}/shared_libs/play-runtime/map-row-identity.ts +1 -1
  31. package/dist/bundling-sources/shared_libs/play-runtime/play-latency-trace.ts +636 -0
  32. package/dist/bundling-sources/shared_libs/play-runtime/postgres-json.ts +9 -0
  33. package/dist/bundling-sources/shared_libs/play-runtime/progress-emitter.ts +197 -0
  34. package/dist/bundling-sources/shared_libs/play-runtime/projection.ts +262 -0
  35. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +143 -0
  36. package/dist/bundling-sources/shared_libs/play-runtime/public-play-contract.ts +42 -0
  37. package/dist/bundling-sources/shared_libs/play-runtime/receipt-status.ts +40 -0
  38. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +178 -0
  39. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +4015 -0
  40. package/dist/bundling-sources/shared_libs/play-runtime/runtime-constraints.ts +2 -0
  41. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +238 -0
  42. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +53 -0
  43. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +149 -0
  44. package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +68 -0
  45. package/dist/bundling-sources/shared_libs/play-runtime/tool-batch-executor.ts +149 -0
  46. package/dist/bundling-sources/shared_libs/play-runtime/tool-result-types.ts +159 -0
  47. package/dist/bundling-sources/shared_libs/play-runtime/tracing.ts +33 -0
  48. package/dist/bundling-sources/shared_libs/play-runtime/waterfall-replay.ts +79 -0
  49. package/dist/bundling-sources/shared_libs/play-runtime/worker-api-types.ts +139 -0
  50. package/dist/bundling-sources/shared_libs/plays/artifact-transport.ts +14 -0
  51. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +49 -0
  52. package/dist/bundling-sources/shared_libs/plays/compiler-manifest.ts +41 -0
  53. package/dist/bundling-sources/shared_libs/plays/dataset-summary.ts +163 -0
  54. package/dist/bundling-sources/shared_libs/plays/definition.ts +267 -0
  55. package/dist/bundling-sources/shared_libs/plays/file-refs.ts +11 -0
  56. package/dist/bundling-sources/shared_libs/plays/input-contract.ts +146 -0
  57. package/dist/bundling-sources/shared_libs/plays/resolve-static-pipeline.ts +190 -0
  58. package/dist/bundling-sources/shared_libs/plays/runtime-validation.ts +417 -0
  59. package/dist/bundling-sources/shared_libs/plays/tool-codegen.ts +142 -0
  60. package/dist/bundling-sources/shared_libs/security/safe-outbound-fetch.ts +274 -0
  61. package/dist/bundling-sources/shared_libs/temporal/preview-config.ts +150 -0
  62. package/dist/cli/index.js +811 -2207
  63. package/dist/cli/index.mjs +847 -2258
  64. package/dist/compiler-manifest-BjoRENv9.d.mts +227 -0
  65. package/dist/compiler-manifest-BjoRENv9.d.ts +227 -0
  66. package/dist/index.d.mts +8 -231
  67. package/dist/index.d.ts +8 -231
  68. package/dist/index.js +101 -15
  69. package/dist/index.mjs +101 -15
  70. package/dist/plays/bundle-play-file.d.mts +120 -0
  71. package/dist/plays/bundle-play-file.d.ts +120 -0
  72. package/dist/plays/bundle-play-file.mjs +1830 -0
  73. package/package.json +4 -9
  74. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/child-play-await.ts +0 -0
  75. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/child-play-submit.ts +0 -0
  76. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/coordinator-entry.ts +0 -0
  77. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/dedup-do.ts +0 -0
  78. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/entry.ts +0 -0
  79. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/csv-rows.ts +0 -0
  80. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/dataset-handles.ts +0 -0
  81. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +0 -0
  82. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/live-progress.ts +0 -0
  83. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +0 -0
  84. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/receipts.ts +0 -0
  85. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/row-isolation.ts +0 -0
  86. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/runtime/tool-http-errors.ts +0 -0
  87. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/workflow-instance-create.ts +0 -0
  88. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/workflow-retry-state.ts +0 -0
  89. /package/dist/{repo → bundling-sources}/apps/play-runner-workers/src/workflow-retry.ts +0 -0
  90. /package/dist/{repo → bundling-sources}/sdk/src/agent-runtime.ts +0 -0
  91. /package/dist/{repo → bundling-sources}/sdk/src/config.ts +0 -0
  92. /package/dist/{repo → bundling-sources}/sdk/src/errors.ts +0 -0
  93. /package/dist/{repo → bundling-sources}/sdk/src/http.ts +0 -0
  94. /package/dist/{repo → bundling-sources}/sdk/src/plays/harness-stub.ts +0 -0
  95. /package/dist/{repo → bundling-sources}/sdk/src/plays/local-file-discovery.ts +0 -0
  96. /package/dist/{repo → bundling-sources}/sdk/src/stream-reconnect.ts +0 -0
  97. /package/dist/{repo → bundling-sources}/sdk/src/tool-output.ts +0 -0
  98. /package/dist/{repo → bundling-sources}/sdk/src/types.ts +0 -0
  99. /package/dist/{repo → bundling-sources}/sdk/src/version.ts +0 -0
  100. /package/dist/{repo → bundling-sources}/sdk/src/worker-play-entry.ts +0 -0
  101. /package/dist/{repo → bundling-sources}/shared_libs/play-data-plane/cell-policy.ts +0 -0
  102. /package/dist/{repo → bundling-sources}/shared_libs/play-data-plane/column-names.ts +0 -0
  103. /package/dist/{repo → bundling-sources}/shared_libs/play-data-plane/sheet-contract.ts +0 -0
  104. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/backend.ts +0 -0
  105. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/batch-runtime.ts +0 -0
  106. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/batching-types.ts +0 -0
  107. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/cell-staleness.ts +0 -0
  108. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/coordinator-headers.ts +0 -0
  109. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/csv-rename.ts +0 -0
  110. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/db-session-crypto.ts +0 -0
  111. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/db-session-plan.ts +0 -0
  112. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/db-session.ts +0 -0
  113. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/dedup-backend.ts +0 -0
  114. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/default-batch-strategies.ts +0 -0
  115. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/email-status.ts +0 -0
  116. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/execution-plan.ts +0 -0
  117. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/extractor-targets.ts +0 -0
  118. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/fullenrich-batching.ts +0 -0
  119. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +0 -0
  120. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/governor/governor.ts +0 -0
  121. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/governor/policy.ts +0 -0
  122. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/governor/rate-state-backend.ts +0 -0
  123. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/live-events.ts +0 -0
  124. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/play-runtime-batching-registry.ts +0 -0
  125. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/profiles.ts +0 -0
  126. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/providers.ts +0 -0
  127. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/run-failure.ts +0 -0
  128. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/run-ledger.ts +0 -0
  129. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/run-snapshot-stream.ts +0 -0
  130. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/scheduler-backend.ts +0 -0
  131. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/secret-capability.ts +0 -0
  132. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/secret-redaction.ts +0 -0
  133. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/step-lifecycle-tracker.ts +0 -0
  134. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/step-program-dataset-builder.ts +0 -0
  135. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/submit-limits.ts +0 -0
  136. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/tool-result.ts +0 -0
  137. /package/dist/{repo → bundling-sources}/shared_libs/play-runtime/work-receipts.ts +0 -0
  138. /package/dist/{repo → bundling-sources}/shared_libs/plays/bootstrap-routes.ts +0 -0
  139. /package/dist/{repo → bundling-sources}/shared_libs/plays/bundling/index.ts +0 -0
  140. /package/dist/{repo → bundling-sources}/shared_libs/plays/bundling/limits.ts +0 -0
  141. /package/dist/{repo → bundling-sources}/shared_libs/plays/contracts.ts +0 -0
  142. /package/dist/{repo → bundling-sources}/shared_libs/plays/dataset.ts +0 -0
  143. /package/dist/{repo → bundling-sources}/shared_libs/plays/row-identity.ts +0 -0
  144. /package/dist/{repo → bundling-sources}/shared_libs/plays/secret-guardrails.ts +0 -0
  145. /package/dist/{repo → bundling-sources}/shared_libs/plays/static-pipeline.ts +0 -0
  146. /package/dist/{repo → bundling-sources}/shared_libs/security/outbound-url-policy.ts +0 -0
  147. /package/dist/{repo → bundling-sources}/shared_libs/security/safe-fetch.ts +0 -0
  148. /package/dist/{repo → bundling-sources}/shared_libs/temporal/constants.ts +0 -0
@@ -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,238 @@
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
+ registerRuntimeOneShotQueryFactory,
50
+ type RuntimePool,
51
+ type RuntimePoolClient,
52
+ } from './runtime-pg-driver';
53
+
54
+ /**
55
+ * Minimal local types for the Neon module's runtime surface.
56
+ *
57
+ * We INTENTIONALLY don't `import type { Pool, PoolClient } from
58
+ * '@neondatabase/serverless'` here — that would force tsc to read the
59
+ * package's full type tree on every typecheck, slowing the build, and
60
+ * the package's overloaded `connect()` resolves through types in a way
61
+ * that surfaces as `void` in some TS configurations.
62
+ *
63
+ * The minimal shape is just:
64
+ * - Pool ctor takes a config bag
65
+ * - Pool instance has connect() / end()
66
+ * - PoolClient instance has query() / release()
67
+ *
68
+ * If Neon ever changes this surface, the runtime cast will fail loudly
69
+ * the first time a play tries to use Postgres — which is exactly when
70
+ * we want to find out.
71
+ */
72
+ interface NeonPoolClient {
73
+ query<R = Record<string, unknown>>(
74
+ text: string,
75
+ params?: unknown[],
76
+ ): Promise<{ rows: R[] }>;
77
+ release(): void;
78
+ }
79
+
80
+ interface NeonPoolInstance {
81
+ connect(): Promise<NeonPoolClient>;
82
+ end(): Promise<void>;
83
+ }
84
+
85
+ interface NeonPoolConfig {
86
+ connectionString: string;
87
+ max?: number;
88
+ idleTimeoutMillis?: number;
89
+ connectionTimeoutMillis?: number;
90
+ }
91
+
92
+ interface NeonModule {
93
+ Pool: new (config: NeonPoolConfig) => NeonPoolInstance;
94
+ neon: (
95
+ connectionString: string,
96
+ options?: { fullResults?: boolean },
97
+ ) => {
98
+ query<R = Record<string, unknown>>(
99
+ text: string,
100
+ params?: unknown[],
101
+ options?: { fullResults?: boolean },
102
+ ): Promise<{ rows: R[] }>;
103
+ };
104
+ }
105
+
106
+ /**
107
+ * Cached promise of the loaded Neon module. Once the first connect()
108
+ * resolves, every subsequent connect on the same isolate hits this
109
+ * cache instead of re-importing.
110
+ *
111
+ * We cache the PROMISE rather than the resolved module so concurrent
112
+ * first-connect calls coalesce onto a single import — V8's module
113
+ * loader is already idempotent for the same specifier, but caching at
114
+ * this layer makes the contract obvious to readers.
115
+ */
116
+ let neonModulePromise: Promise<NeonModule> | null = null;
117
+ function loadNeonModule(): Promise<NeonModule> {
118
+ if (!neonModulePromise) {
119
+ neonModulePromise =
120
+ import('@neondatabase/serverless') as unknown as Promise<NeonModule>;
121
+ }
122
+ return neonModulePromise;
123
+ }
124
+
125
+ function wrapNeonClient(client: NeonPoolClient): RuntimePoolClient {
126
+ return {
127
+ query: <R extends Record<string, unknown> = Record<string, unknown>>(
128
+ text: string,
129
+ params?: unknown[],
130
+ ) =>
131
+ (
132
+ client.query as unknown as (
133
+ t: string,
134
+ p?: unknown[],
135
+ ) => Promise<{ rows: R[] }>
136
+ )(text, params),
137
+ release: () => {
138
+ client.release();
139
+ },
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Wrap a Neon `Pool` instance as our internal `RuntimePool` shape.
145
+ * `connect()` and `end()` are async on both sides, so this is a thin
146
+ * adapter — no logic, just type marshaling.
147
+ */
148
+ function wrapNeonPool(pool: NeonPoolInstance): RuntimePool {
149
+ return {
150
+ connect: async () =>
151
+ wrapNeonClient((await pool.connect()) as unknown as NeonPoolClient),
152
+ end: async () => {
153
+ await pool.end();
154
+ },
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Install the Neon-backed pool factory. Called once at Worker isolate
160
+ * boot — `registerRuntimePoolFactory` is idempotent and throws if a
161
+ * different factory was already registered (build-config bug).
162
+ *
163
+ * The factory itself is SYNCHRONOUS (returns a `RuntimePool`) but the
164
+ * underlying Neon Pool is created LAZILY: we capture the connection
165
+ * config in a closure and instantiate the real `Pool` on first
166
+ * `connect()`. Until then, no `@neondatabase/serverless` runtime code
167
+ * runs in the isolate — V8 doesn't parse the dynamic-imported chunk
168
+ * until the import() resolves.
169
+ */
170
+ export function installNeonServerlessRuntimePoolDriver(): void {
171
+ registerRuntimeOneShotQueryFactory((input) => {
172
+ let sqlPromise: Promise<ReturnType<NeonModule['neon']>> | null = null;
173
+ async function getSql(): Promise<ReturnType<NeonModule['neon']>> {
174
+ if (!sqlPromise) {
175
+ sqlPromise = loadNeonModule().then((neon) =>
176
+ neon.neon(input.connectionString, { fullResults: true }),
177
+ );
178
+ }
179
+ return sqlPromise;
180
+ }
181
+ return {
182
+ query: async <
183
+ R extends Record<string, unknown> = Record<string, unknown>,
184
+ >(
185
+ text: string,
186
+ params?: unknown[],
187
+ ) => {
188
+ const sql = await getSql();
189
+ return await sql.query<R>(text, params, { fullResults: true });
190
+ },
191
+ };
192
+ });
193
+
194
+ registerRuntimePoolFactory((input) => {
195
+ // Captured lazily so a Pool is only constructed if the play actually
196
+ // connects. Most plays that don't touch Postgres directly never even
197
+ // reach this branch — the factory is registered but never invoked.
198
+ let lazyPool: NeonPoolInstance | null = null;
199
+
200
+ /**
201
+ * Resolve the lazy Pool, creating it on first call.
202
+ *
203
+ * Race safety: workerd executes within a single JS event loop, so
204
+ * two concurrent `connect()` calls on the SAME wrapper run their
205
+ * "lazyPool == null" checks in turn — the first creates the Pool,
206
+ * the second sees it. No locking needed.
207
+ *
208
+ * If pool creation fails (e.g. DNS, bad connection string), the
209
+ * error propagates out of connect() to the caller. We don't cache
210
+ * a failed pool so retries can succeed on transient failures.
211
+ */
212
+ async function ensurePool(): Promise<NeonPoolInstance> {
213
+ if (lazyPool) return lazyPool;
214
+ const neon = await loadNeonModule();
215
+ const pool = new neon.Pool({
216
+ connectionString: input.connectionString,
217
+ max: input.maxConnections ?? 4,
218
+ idleTimeoutMillis: input.idleTimeoutMs ?? 15_000,
219
+ connectionTimeoutMillis: input.connectTimeoutMs ?? 10_000,
220
+ });
221
+ lazyPool = pool;
222
+ return pool;
223
+ }
224
+
225
+ return {
226
+ connect: async () => {
227
+ const pool = await ensurePool();
228
+ return wrapNeonClient(await pool.connect());
229
+ },
230
+ end: async () => {
231
+ if (lazyPool) {
232
+ await lazyPool.end();
233
+ lazyPool = null;
234
+ }
235
+ },
236
+ };
237
+ });
238
+ }
@@ -0,0 +1,53 @@
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
+ type RuntimePoolFactory,
12
+ } from './runtime-pg-driver';
13
+
14
+ function wrapPgClient(client: PoolClient): RuntimePoolClient {
15
+ return {
16
+ query: <R extends Record<string, unknown> = Record<string, unknown>>(
17
+ text: string,
18
+ params?: unknown[],
19
+ ) =>
20
+ (
21
+ client.query as unknown as (
22
+ t: string,
23
+ p?: unknown[],
24
+ ) => Promise<{ rows: R[] }>
25
+ )(text, params).then((result) => ({
26
+ rows: result.rows,
27
+ })),
28
+ release: () => {
29
+ client.release();
30
+ },
31
+ };
32
+ }
33
+
34
+ function wrapPgPool(pool: Pool): RuntimePool {
35
+ return {
36
+ connect: async () => wrapPgClient(await pool.connect()),
37
+ end: () => pool.end(),
38
+ };
39
+ }
40
+
41
+ const pgRuntimePoolFactory: RuntimePoolFactory = (input): RuntimePool => {
42
+ const pool = new Pool({
43
+ connectionString: input.connectionString,
44
+ max: input.maxConnections ?? 2,
45
+ idleTimeoutMillis: input.idleTimeoutMs ?? 15_000,
46
+ connectionTimeoutMillis: input.connectTimeoutMs ?? 10_000,
47
+ });
48
+ return wrapPgPool(pool);
49
+ };
50
+
51
+ export function installPgRuntimePoolDriver(): void {
52
+ registerRuntimePoolFactory(pgRuntimePoolFactory);
53
+ }
@@ -0,0 +1,149 @@
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 interface RuntimeOneShotQueryClient {
34
+ query<R extends Record<string, unknown> = Record<string, unknown>>(
35
+ text: string,
36
+ params?: unknown[],
37
+ ): Promise<{ rows: R[] }>;
38
+ }
39
+
40
+ export type RuntimePoolFactory = (input: {
41
+ connectionString: string;
42
+ /** Soft cap on simultaneous connections; defaults to 4. */
43
+ maxConnections?: number;
44
+ /** Idle timeout in ms before pool tears down a connection; defaults to 15000. */
45
+ idleTimeoutMs?: number;
46
+ /** Connect timeout in ms; defaults to 10000. */
47
+ connectTimeoutMs?: number;
48
+ }) => RuntimePool;
49
+
50
+ export type RuntimeOneShotQueryFactory = (input: {
51
+ connectionString: string;
52
+ }) => RuntimeOneShotQueryClient;
53
+
54
+ const runtimePgDriverRegistryKey = Symbol.for(
55
+ 'deepline.play-runtime.runtime-pg-driver.registry',
56
+ );
57
+
58
+ type RuntimePgDriverRegistry = {
59
+ poolFactory: RuntimePoolFactory | null;
60
+ oneShotQueryFactory: RuntimeOneShotQueryFactory | null;
61
+ };
62
+
63
+ function getRuntimePgDriverRegistry(): RuntimePgDriverRegistry {
64
+ const globalWithRegistry = globalThis as typeof globalThis & {
65
+ [runtimePgDriverRegistryKey]?: RuntimePgDriverRegistry;
66
+ };
67
+ globalWithRegistry[runtimePgDriverRegistryKey] ??= {
68
+ poolFactory: null,
69
+ oneShotQueryFactory: null,
70
+ };
71
+ return globalWithRegistry[runtimePgDriverRegistryKey];
72
+ }
73
+
74
+ /**
75
+ * Install a Pool factory at process / Worker boot. Idempotent — calling twice
76
+ * with different factories will throw to prevent silent driver swaps that
77
+ * would otherwise drop in-flight pooled connections.
78
+ */
79
+ export function registerRuntimePoolFactory(factory: RuntimePoolFactory): void {
80
+ const registry = getRuntimePgDriverRegistry();
81
+ if (registry.poolFactory && registry.poolFactory !== factory) {
82
+ throw new Error(
83
+ 'A different runtime Postgres pool factory is already registered. ' +
84
+ 'This is a build-config bug — only one driver should be installed per process.',
85
+ );
86
+ }
87
+ registry.poolFactory = factory;
88
+ }
89
+
90
+ export function isRuntimePoolFactoryRegistered(): boolean {
91
+ return getRuntimePgDriverRegistry().poolFactory !== null;
92
+ }
93
+
94
+ export function registerRuntimeOneShotQueryFactory(
95
+ factory: RuntimeOneShotQueryFactory,
96
+ ): void {
97
+ const registry = getRuntimePgDriverRegistry();
98
+ if (
99
+ registry.oneShotQueryFactory &&
100
+ registry.oneShotQueryFactory !== factory
101
+ ) {
102
+ throw new Error(
103
+ 'A different runtime one-shot Postgres query factory is already registered. ' +
104
+ 'This is a build-config bug — only one driver should be installed per process.',
105
+ );
106
+ }
107
+ registry.oneShotQueryFactory = factory;
108
+ }
109
+
110
+ export function isRuntimeOneShotQueryFactoryRegistered(): boolean {
111
+ return getRuntimePgDriverRegistry().oneShotQueryFactory !== null;
112
+ }
113
+
114
+ export function createRuntimeOneShotQueryClient(input: {
115
+ connectionString: string;
116
+ }): RuntimeOneShotQueryClient {
117
+ const { oneShotQueryFactory } = getRuntimePgDriverRegistry();
118
+ if (!oneShotQueryFactory) {
119
+ throw new Error(
120
+ 'No runtime one-shot Postgres query factory registered. Call the runtime Postgres driver installer at boot before using one-shot query helpers.',
121
+ );
122
+ }
123
+ return oneShotQueryFactory(input);
124
+ }
125
+
126
+ export function createRuntimePool(input: {
127
+ connectionString: string;
128
+ maxConnections?: number;
129
+ idleTimeoutMs?: number;
130
+ connectTimeoutMs?: number;
131
+ }): RuntimePool {
132
+ const { poolFactory } = getRuntimePgDriverRegistry();
133
+ if (!poolFactory) {
134
+ throw new Error(
135
+ 'No runtime Postgres pool factory registered. Call ' +
136
+ 'installPgRuntimePoolDriver() (Node) or ' +
137
+ 'installNeonServerlessRuntimePoolDriver() (Workers) at boot before ' +
138
+ 'using runtime-api Postgres helpers.',
139
+ );
140
+ }
141
+ return poolFactory(input);
142
+ }
143
+
144
+ /** Test seam — clears the registered factory so a test can swap drivers. */
145
+ export function __resetRuntimePoolFactoryForTests(): void {
146
+ const registry = getRuntimePgDriverRegistry();
147
+ registry.poolFactory = null;
148
+ registry.oneShotQueryFactory = null;
149
+ }
@@ -0,0 +1,68 @@
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
+ }
@@ -0,0 +1,149 @@
1
+ export type ToolBatchItem = {
2
+ itemKey: string;
3
+ payload: Record<string, unknown>;
4
+ inputHash?: string | null;
5
+ };
6
+
7
+ export type ToolBatchRequest = {
8
+ runId: string;
9
+ orgId: string;
10
+ toolId: string;
11
+ operation: string;
12
+ provider: string;
13
+ items: ToolBatchItem[];
14
+ waterfallId?: string | null;
15
+ stageId?: string | null;
16
+ fieldName?: string | null;
17
+ mapName?: string | null;
18
+ chunkIndex?: number | null;
19
+ userProvidedRateLimitKey?: string | null;
20
+ providerBatchSize: number;
21
+ };
22
+
23
+ export type ToolBatchItemResult = {
24
+ itemKey: string;
25
+ result: unknown;
26
+ cached?: boolean;
27
+ };
28
+
29
+ export type ToolBatchResult = {
30
+ runId: string;
31
+ toolId: string;
32
+ operation: string;
33
+ provider: string;
34
+ batchCount: number;
35
+ itemCount: number;
36
+ results: ToolBatchItemResult[];
37
+ };
38
+
39
+ export type ToolBatchExecutorTransport = {
40
+ executeProviderBatch(input: {
41
+ request: ToolBatchRequest;
42
+ batchIndex: number;
43
+ idempotencyKeys: string[];
44
+ rateLimitKey: string;
45
+ items: ToolBatchItem[];
46
+ }): Promise<ToolBatchItemResult[]>;
47
+ };
48
+
49
+ export type ToolBatchExecutor = {
50
+ executeToolBatch(request: ToolBatchRequest): Promise<ToolBatchResult>;
51
+ };
52
+
53
+ export function createToolBatchExecutor(
54
+ transport: ToolBatchExecutorTransport,
55
+ ): ToolBatchExecutor {
56
+ return {
57
+ async executeToolBatch(request) {
58
+ const providerBatchSize = Math.max(
59
+ 1,
60
+ Math.floor(request.providerBatchSize),
61
+ );
62
+ const batches = chunkToolBatchItems(request.items, providerBatchSize);
63
+ const results: ToolBatchItemResult[] = [];
64
+ for (let batchIndex = 0; batchIndex < batches.length; batchIndex += 1) {
65
+ const items = batches[batchIndex]!;
66
+ results.push(
67
+ ...(await transport.executeProviderBatch({
68
+ request,
69
+ batchIndex,
70
+ items,
71
+ rateLimitKey: buildToolBatchRateLimitKey(request),
72
+ idempotencyKeys: items.map((item) =>
73
+ buildToolBatchIdempotencyKey(request, item),
74
+ ),
75
+ })),
76
+ );
77
+ }
78
+ return {
79
+ runId: request.runId,
80
+ toolId: request.toolId,
81
+ operation: request.operation,
82
+ provider: request.provider,
83
+ batchCount: batches.length,
84
+ itemCount: request.items.length,
85
+ results,
86
+ };
87
+ },
88
+ };
89
+ }
90
+
91
+ export function buildToolBatchIdempotencyKey(
92
+ request: ToolBatchRequest,
93
+ item: ToolBatchItem,
94
+ ): string {
95
+ return [
96
+ request.runId,
97
+ request.mapName ?? '',
98
+ request.chunkIndex ?? '',
99
+ item.itemKey,
100
+ request.fieldName ?? '',
101
+ request.waterfallId ?? '',
102
+ request.stageId ?? '',
103
+ item.inputHash ?? stableToolBatchHash(item.payload),
104
+ ].join(':');
105
+ }
106
+
107
+ export function buildToolBatchRateLimitKey(request: ToolBatchRequest): string {
108
+ return [
109
+ request.orgId,
110
+ request.provider,
111
+ request.operation,
112
+ request.userProvidedRateLimitKey ?? '',
113
+ ].join(':');
114
+ }
115
+
116
+ function chunkToolBatchItems(
117
+ items: readonly ToolBatchItem[],
118
+ size: number,
119
+ ): ToolBatchItem[][] {
120
+ const chunks: ToolBatchItem[][] = [];
121
+ for (let index = 0; index < items.length; index += size) {
122
+ chunks.push(items.slice(index, index + size));
123
+ }
124
+ return chunks;
125
+ }
126
+
127
+ function stableToolBatchHash(value: unknown): string {
128
+ const text = stableStringify(value);
129
+ let hash = 2166136261;
130
+ for (let index = 0; index < text.length; index += 1) {
131
+ hash ^= text.charCodeAt(index);
132
+ hash = Math.imul(hash, 16777619);
133
+ }
134
+ return (hash >>> 0).toString(36);
135
+ }
136
+
137
+ function stableStringify(value: unknown): string {
138
+ if (value === null || typeof value !== 'object') {
139
+ return JSON.stringify(value);
140
+ }
141
+ if (Array.isArray(value)) {
142
+ return `[${value.map(stableStringify).join(',')}]`;
143
+ }
144
+ const record = value as Record<string, unknown>;
145
+ return `{${Object.keys(record)
146
+ .sort()
147
+ .map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`)
148
+ .join(',')}}`;
149
+ }