deepline 0.2.55 → 0.2.57

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 (49) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +14 -0
  2. package/dist/bundling-sources/sdk/src/http.ts +19 -1
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/sdk/src/stream-reconnect.ts +6 -0
  5. package/dist/bundling-sources/sdk/src/types.ts +7 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +146 -12
  7. package/dist/bundling-sources/shared_libs/play-runtime/batch-runtime.ts +6 -3
  8. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +1631 -748
  9. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +20 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +81 -52
  11. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +146 -6
  12. package/dist/bundling-sources/shared_libs/play-runtime/gateway-auth-session.ts +56 -22
  13. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +14 -11
  14. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +21 -2
  15. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +81 -21
  16. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +7 -0
  17. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
  18. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +21 -0
  19. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +27 -2
  20. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +49 -10
  21. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +96 -3
  22. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +341 -67
  23. package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +10 -0
  24. package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +8 -1
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +17 -2
  26. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +4 -1
  27. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +17 -1
  28. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +16 -2
  29. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-writer.ts +25 -0
  30. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +3 -0
  31. package/dist/bundling-sources/shared_libs/play-runtime/suspension.ts +2 -0
  32. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +80 -1
  33. package/dist/bundling-sources/shared_libs/plays/docflow.ts +113 -14
  34. package/dist/bundling-sources/shared_libs/plays/play-exports.ts +53 -4
  35. package/dist/bundling-sources/shared_libs/security/safe-fetch.ts +9 -0
  36. package/dist/bundling-sources/shared_libs/security/safe-outbound-fetch.ts +85 -48
  37. package/dist/cli/index.js +429 -54
  38. package/dist/cli/index.mjs +409 -28
  39. package/dist/{compiler-manifest-Bl8kmLx9.d.mts → compiler-manifest-TgaC4DeD.d.mts} +13 -0
  40. package/dist/{compiler-manifest-Bl8kmLx9.d.ts → compiler-manifest-TgaC4DeD.d.ts} +13 -0
  41. package/dist/index.d.mts +21 -3
  42. package/dist/index.d.ts +21 -3
  43. package/dist/index.js +29 -2
  44. package/dist/index.mjs +29 -2
  45. package/dist/install-integrity.json +2 -2
  46. package/dist/plays/bundle-play-file.d.mts +2 -2
  47. package/dist/plays/bundle-play-file.d.ts +2 -2
  48. package/dist/plays/bundle-play-file.mjs +78 -18
  49. package/package.json +1 -1
@@ -34,6 +34,16 @@ export type PlayFileExport = {
34
34
  name: string;
35
35
  /** Other export names that resolve to the same `definePlay` call. */
36
36
  aliases: string[];
37
+ /**
38
+ * The play's own name — `definePlay('<this>', …)` — when it is a literal.
39
+ *
40
+ * An export name is a module detail (`scalar`, `batch`); the play name is what
41
+ * the product, the registry and the customer call this thing. So it is a legal
42
+ * way to address the play, which is why an `@mermaid <name>` header may write
43
+ * either. Null when the first argument is not a string literal, which is only
44
+ * possible for a play the registry could not name either.
45
+ */
46
+ playName: string | null;
37
47
  };
38
48
 
39
49
  function getIdentifierName(node: unknown): string | null {
@@ -83,6 +93,16 @@ export function isDefinePlayCall(node: AstNode | null): boolean {
83
93
  return false;
84
94
  }
85
95
 
96
+ /** The literal name a `definePlay('…', …)` call declares, when it is one. */
97
+ function definePlayName(node: AstNode | null): string | null {
98
+ const expression = unwrapStaticExpression(node);
99
+ if (!expression || expression.type !== 'CallExpression') return null;
100
+ const first = astArray(expression.arguments)[0] ?? null;
101
+ return first?.type === 'Literal' && typeof first.value === 'string'
102
+ ? first.value
103
+ : null;
104
+ }
105
+
86
106
  /**
87
107
  * The plays `sourceCode` exports, default first, then named exports in source
88
108
  * order. `null` means acorn could not parse the file — the caller abstains and
@@ -163,13 +183,26 @@ export function listPlayFileExports(
163
183
  .map(([exported]) => exported)
164
184
  : [];
165
185
  if (defaultLocalName) aliasedLocals.add(defaultLocalName);
166
- exports.push({ name: PLAY_DEFAULT_EXPORT, aliases });
186
+ exports.push({
187
+ name: PLAY_DEFAULT_EXPORT,
188
+ aliases,
189
+ playName: definePlayName(
190
+ defaultLocalName
191
+ ? (declarations.get(defaultLocalName) ?? null)
192
+ : defaultExpression,
193
+ ),
194
+ });
167
195
  }
168
196
  for (const [exportedName, localName] of namedExports) {
169
197
  if (exportedName === PLAY_DEFAULT_EXPORT) continue;
170
198
  if (aliasedLocals.has(localName)) continue;
171
- if (!isDefinePlayCall(declarations.get(localName) ?? null)) continue;
172
- exports.push({ name: exportedName, aliases: [] });
199
+ const declaration = declarations.get(localName) ?? null;
200
+ if (!isDefinePlayCall(declaration)) continue;
201
+ exports.push({
202
+ name: exportedName,
203
+ aliases: [],
204
+ playName: definePlayName(declaration),
205
+ });
173
206
  }
174
207
 
175
208
  return exports;
@@ -180,6 +213,12 @@ export function listPlayFileExports(
180
213
  * canonical name. `scalar` in `export default scalar` resolves to `default`;
181
214
  * an unknown name resolves to `null` so the caller can fail loudly with the
182
215
  * available set rather than silently binding nothing.
216
+ *
217
+ * The play's own name resolves too, and is the better thing to write: a diagram
218
+ * headed `@mermaid scalar` names a module-local binding, while one headed
219
+ * `@mermaid name-and-domain-to-email-waterfall` names the play the reader came
220
+ * here for. Export names keep working because every diagram authored before this
221
+ * used one.
183
222
  */
184
223
  export function canonicalPlayExportName(
185
224
  exportName: string | null | undefined,
@@ -191,6 +230,12 @@ export function canonicalPlayExportName(
191
230
  return entry.name;
192
231
  }
193
232
  }
233
+ // Second pass, so an export literally named after another play's play name
234
+ // can never lose to it. Ambiguity between two plays' names is impossible:
235
+ // the registry rejects a duplicate play name before this ever runs.
236
+ for (const entry of exports) {
237
+ if (entry.playName === requested) return entry.name;
238
+ }
194
239
  return null;
195
240
  }
196
241
 
@@ -198,5 +243,9 @@ export function canonicalPlayExportName(
198
243
  export function playExportNamesForMessage(
199
244
  exports: readonly PlayFileExport[],
200
245
  ): string[] {
201
- return exports.flatMap((entry) => [entry.name, ...entry.aliases]);
246
+ return exports.flatMap((entry) => [
247
+ ...(entry.playName ? [entry.playName] : []),
248
+ entry.name,
249
+ ...entry.aliases,
250
+ ]);
202
251
  }
@@ -19,6 +19,10 @@ function removeHeader(headers: Headers, name: string) {
19
19
  if (headers.has(name)) headers.delete(name);
20
20
  }
21
21
 
22
+ function cancelResponseBodyBestEffort(response: Response): void {
23
+ void response.body?.cancel().catch(() => undefined);
24
+ }
25
+
22
26
  function requestInitForRedirect(
23
27
  init: RequestInit,
24
28
  from: URL,
@@ -83,6 +87,7 @@ export async function safePublicFetch(
83
87
  return response;
84
88
  }
85
89
  if (redirectMode === 'error') {
90
+ cancelResponseBodyBestEffort(response);
86
91
  throw new Error(
87
92
  `Redirect blocked while fetching ${currentUrl.toString()}.`,
88
93
  );
@@ -96,11 +101,15 @@ export async function safePublicFetch(
96
101
  return response;
97
102
  }
98
103
  if (redirectCount === maxRedirects) {
104
+ cancelResponseBodyBestEffort(response);
99
105
  throw new Error(
100
106
  `Too many redirects while fetching ${currentUrl.toString()}.`,
101
107
  );
102
108
  }
103
109
 
110
+ // A redirect response can stream an unbounded body. The next request must
111
+ // not leave that body/socket flowing in the background.
112
+ cancelResponseBodyBestEffort(response);
104
113
  const nextUrl = resolveRedirectUrl(location, currentUrl);
105
114
  currentInit = requestInitForRedirect(
106
115
  currentInit,
@@ -14,6 +14,8 @@ import {
14
14
  type NodeSafeFetchOptions = {
15
15
  maxRedirects?: number;
16
16
  maxResponseBytes?: number;
17
+ /** Return after validated headers so the caller can enforce a body deadline. */
18
+ streamResponseBody?: boolean;
17
19
  truncateResponseBody?: boolean;
18
20
  sensitiveHeaders?: Iterable<string>;
19
21
  validateUrl?: (url: URL) => void;
@@ -219,62 +221,83 @@ function createRequest(
219
221
  );
220
222
  return;
221
223
  }
222
-
223
- const chunks: Buffer[] = [];
224
- let receivedBytes = 0;
225
- let settled = false;
226
- const resolveResponse = () => {
227
- if (settled) return;
228
- settled = true;
224
+ if (noBodyResponse) {
225
+ response.resume();
229
226
  resolve(
230
- new Response(noBodyResponse ? null : Buffer.concat(chunks), {
227
+ new Response(null, {
231
228
  status,
232
229
  statusText: response.statusMessage,
233
230
  headers: response.headers as HeadersInit,
234
231
  }),
235
232
  );
236
- };
237
- response.on('data', (chunk) => {
238
- if (settled) return;
239
- const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
240
- const previousReceivedBytes = receivedBytes;
241
- receivedBytes += buffer.byteLength;
242
- if (
243
- maxResponseBytes !== undefined &&
244
- receivedBytes > maxResponseBytes &&
245
- !truncateResponseBody
246
- ) {
247
- response.destroy(
248
- new Error(
249
- `Response body exceeds ${maxResponseBytes} byte limit.`,
250
- ),
251
- );
252
- return;
253
- }
254
- if (!noBodyResponse) {
255
- if (maxResponseBytes !== undefined && truncateResponseBody) {
256
- const remainingBytes = Math.max(
257
- 0,
258
- maxResponseBytes - previousReceivedBytes,
259
- );
260
- if (remainingBytes > 0) {
261
- chunks.push(buffer.subarray(0, remainingBytes));
233
+ return;
234
+ }
235
+
236
+ let receivedBytes = 0;
237
+ let bodySettled = false;
238
+ const body = new ReadableStream<Uint8Array>({
239
+ start(controller) {
240
+ response.on('data', (chunk) => {
241
+ if (bodySettled) return;
242
+ const buffer = Buffer.isBuffer(chunk)
243
+ ? chunk
244
+ : Buffer.from(chunk);
245
+ const previousReceivedBytes = receivedBytes;
246
+ receivedBytes += buffer.byteLength;
247
+ if (
248
+ maxResponseBytes !== undefined &&
249
+ receivedBytes > maxResponseBytes &&
250
+ !truncateResponseBody
251
+ ) {
252
+ bodySettled = true;
253
+ const error = new Error(
254
+ `Response body exceeds ${maxResponseBytes} byte limit.`,
255
+ );
256
+ controller.error(error);
257
+ response.destroy(error);
258
+ return;
262
259
  }
263
- if (receivedBytes >= maxResponseBytes) {
264
- resolveResponse();
265
- response.destroy();
260
+ if (maxResponseBytes !== undefined && truncateResponseBody) {
261
+ const remainingBytes = Math.max(
262
+ 0,
263
+ maxResponseBytes - previousReceivedBytes,
264
+ );
265
+ if (remainingBytes > 0) {
266
+ controller.enqueue(buffer.subarray(0, remainingBytes));
267
+ }
268
+ if (receivedBytes >= maxResponseBytes) {
269
+ bodySettled = true;
270
+ controller.close();
271
+ response.destroy();
272
+ }
273
+ return;
266
274
  }
267
- } else {
268
- chunks.push(buffer);
269
- }
270
- }
275
+ controller.enqueue(buffer);
276
+ });
277
+ response.on('error', (error) => {
278
+ if (bodySettled) return;
279
+ bodySettled = true;
280
+ controller.error(error);
281
+ });
282
+ response.on('end', () => {
283
+ if (bodySettled) return;
284
+ bodySettled = true;
285
+ controller.close();
286
+ });
287
+ },
288
+ cancel(reason) {
289
+ if (bodySettled) return;
290
+ bodySettled = true;
291
+ response.destroy(reason instanceof Error ? reason : undefined);
292
+ },
271
293
  });
272
- response.on('error', (error) => {
273
- if (settled) return;
274
- settled = true;
275
- reject(error);
276
- });
277
- response.on('end', resolveResponse);
294
+ resolve(
295
+ new Response(body, {
296
+ status,
297
+ statusText: response.statusMessage,
298
+ headers: response.headers as HeadersInit,
299
+ }),
300
+ );
278
301
  },
279
302
  );
280
303
 
@@ -359,9 +382,21 @@ export async function safeOutboundFetch(
359
382
  });
360
383
 
361
384
  if (!isRedirectStatus(response.status)) {
362
- return response;
385
+ if (options.streamResponseBody) return response;
386
+ const body = response.body ? await response.arrayBuffer() : null;
387
+ const buffered = new Response(body, {
388
+ status: response.status,
389
+ statusText: response.statusText,
390
+ headers: response.headers,
391
+ });
392
+ Object.defineProperty(buffered, 'url', {
393
+ configurable: true,
394
+ value: response.url,
395
+ });
396
+ return buffered;
363
397
  }
364
398
  if (redirectMode === 'error') {
399
+ void response.body?.cancel().catch(() => undefined);
365
400
  throw new Error(
366
401
  `Redirect blocked while fetching ${currentUrl.toString()}.`,
367
402
  );
@@ -375,11 +410,13 @@ export async function safeOutboundFetch(
375
410
  return response;
376
411
  }
377
412
  if (redirectCount === maxRedirects) {
413
+ void response.body?.cancel().catch(() => undefined);
378
414
  throw new Error(
379
415
  `Too many redirects while fetching ${currentUrl.toString()}.`,
380
416
  );
381
417
  }
382
418
 
419
+ void response.body?.cancel().catch(() => undefined);
383
420
  const nextUrl = resolveRedirectUrl(location, currentUrl);
384
421
  currentInit = initForRedirect(
385
422
  currentInit,