deepline 0.3.258 → 0.3.260

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 (69) hide show
  1. package/dist/bundling-sources/sdk/src/api-error.ts +45 -0
  2. package/dist/bundling-sources/sdk/src/client.ts +98 -459
  3. package/dist/bundling-sources/sdk/src/http.ts +1 -34
  4. package/dist/bundling-sources/sdk/src/index.ts +8 -0
  5. package/dist/bundling-sources/sdk/src/plays/csv-data-input.ts +139 -0
  6. package/dist/bundling-sources/sdk/src/plays/run-request.ts +855 -0
  7. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  8. package/dist/bundling-sources/sdk/src/runs/overview.ts +45 -2
  9. package/dist/bundling-sources/sdk/src/types.ts +5 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +8 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +42 -10
  12. package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +3 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +23 -0
  14. package/dist/bundling-sources/shared_libs/play-runtime/live-state-contract.ts +3 -0
  15. package/dist/bundling-sources/shared_libs/play-runtime/play-admission-outcome.ts +23 -5
  16. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/gateway-adapter.ts +1 -1
  17. package/dist/bundling-sources/shared_libs/play-runtime/run-execution-state.ts +845 -0
  18. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +106 -6
  19. package/dist/bundling-sources/shared_libs/play-runtime/run-observation.ts +440 -0
  20. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +35 -2
  21. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +66 -7
  22. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-crash-details.ts +95 -0
  23. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +13 -2
  24. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +0 -29
  25. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-transition.ts +47 -2
  26. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +6 -0
  27. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +475 -36
  28. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +78 -11
  29. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +550 -42
  30. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +181 -8
  31. package/dist/bundling-sources/shared_libs/play-runtime/step-lifecycle-tracker.ts +0 -18
  32. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +80 -7
  33. package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +37 -2
  34. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +148 -18
  35. package/dist/bundling-sources/shared_libs/plays/cascade-falloff.ts +86 -0
  36. package/dist/bundling-sources/shared_libs/plays/docflow-unreached-reason.ts +611 -0
  37. package/dist/bundling-sources/shared_libs/plays/docflow.ts +21 -0
  38. package/dist/bundling-sources/shared_libs/plays/play-exports.ts +28 -5
  39. package/dist/bundling-sources/shared_libs/plays/settings-contract.ts +92 -10
  40. package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +5 -0
  41. package/dist/bundling-sources/shared_libs/plays/trigger-config-contract.ts +222 -0
  42. package/dist/bundling-sources/shared_libs/plays/trigger-config-route.ts +15 -0
  43. package/dist/cli/index.js +4957 -771
  44. package/dist/cli/index.mjs +4957 -771
  45. package/dist/client-B5XbKrrs.d.mts +6564 -0
  46. package/dist/client-C9Y49yya.d.ts +6564 -0
  47. package/dist/{compiler-manifest-C4mdRJOP.d.mts → compiler-manifest-CUuh8C3b.d.mts} +14 -1
  48. package/dist/{compiler-manifest-C4mdRJOP.d.ts → compiler-manifest-CUuh8C3b.d.ts} +14 -1
  49. package/dist/index.d.mts +7 -6275
  50. package/dist/index.d.ts +7 -6275
  51. package/dist/index.js +360 -326
  52. package/dist/index.mjs +360 -326
  53. package/dist/install-integrity.json +22 -2
  54. package/dist/plays/bundle-play-file.d.mts +2 -2
  55. package/dist/plays/bundle-play-file.d.ts +2 -2
  56. package/dist/plays/bundle-play-file.mjs +117 -18
  57. package/dist/plays/csv-data-input.d.mts +37 -0
  58. package/dist/plays/csv-data-input.d.ts +37 -0
  59. package/dist/plays/csv-data-input.js +3135 -0
  60. package/dist/plays/csv-data-input.mjs +3108 -0
  61. package/dist/plays/run-request.d.mts +6 -0
  62. package/dist/plays/run-request.d.ts +6 -0
  63. package/dist/plays/run-request.js +664 -0
  64. package/dist/plays/run-request.mjs +614 -0
  65. package/dist/release.d.mts +1 -1
  66. package/dist/release.d.ts +1 -1
  67. package/dist/release.js +1 -1
  68. package/dist/release.mjs +1 -1
  69. package/package.json +12 -1
@@ -3,6 +3,14 @@ import type {
3
3
  PlaySettingsPatch,
4
4
  PlaySettingsPathsPage,
5
5
  } from '../../shared_libs/plays/settings-contract';
6
+ import type {
7
+ PlayTriggerConfigUpdate,
8
+ PlayTriggerConfigUpdateResult,
9
+ PlayTriggerConfigView,
10
+ } from '../../shared_libs/plays/trigger-config-contract';
11
+ // Value import from the dependency-free module: the client is bundled into
12
+ // authored Plays, where `zod` (the contract's schemas) cannot resolve.
13
+ import { playTriggerConfigPath } from '../../shared_libs/plays/trigger-config-route';
6
14
  import { iterateCursorPages } from './pagination.js';
7
15
  import { playInputExampleArgs } from './plays/input-example.js';
8
16
  /**
@@ -77,7 +85,6 @@ import type {
77
85
  PlayRunResult,
78
86
  PlayRunStart,
79
87
  PlayStatus,
80
- PlayRunPackage,
81
88
  PlayLiveEvent,
82
89
  PlayListItem,
83
90
  ProductNotificationSettings,
@@ -112,6 +119,17 @@ import { isStopAllPlayRunsDryRunResult } from './types.js';
112
119
  import type { MonitorDefinition } from './monitors.js';
113
120
  import type { MonitorFleetDefinition } from './monitor-fleets.js';
114
121
  import type { PlayStagedFileRef } from './plays/local-file-discovery.js';
122
+ import {
123
+ buildPlayRunStartBody,
124
+ isPlayRunPackage,
125
+ mintStagedPlayFileUploads,
126
+ normalizePlayRunStart,
127
+ PLAY_RUN_START_STREAM_PATH,
128
+ stagePlayFiles,
129
+ startPlayRun,
130
+ type MintStagedFileUpload,
131
+ type ResolvedStartPlayRunRequest,
132
+ } from './plays/run-request';
115
133
  import type { PlayCompilerManifest } from '../../shared_libs/plays/compiler-manifest.js';
116
134
  import type { EnrichCompiledConfig } from './cli/enrich-play-compiler.js';
117
135
  import {
@@ -394,6 +412,30 @@ function resolvePlayRunRuntimeSelection(
394
412
  };
395
413
  }
396
414
 
415
+ /**
416
+ * Resolve the environment-derived run-start fields (eval integration mode,
417
+ * test policy overrides, preview runtime) into explicit request fields, in the
418
+ * order the SDK has always validated them. The shared body builder in
419
+ * `plays/run-request` never reads the environment.
420
+ */
421
+ function resolveStartPlayRunRequest(request: StartPlayRunRequest): {
422
+ request: ResolvedStartPlayRunRequest;
423
+ runtime: PlayRuntimeSelection | undefined;
424
+ } {
425
+ const integrationMode = resolvePlayRunIntegrationMode(request);
426
+ const testPolicyOverrides =
427
+ request.testPolicyOverrides ?? parseEnvTestPolicyOverrides();
428
+ const runtime = resolvePlayRunRuntimeSelection(request);
429
+ const resolved: ResolvedStartPlayRunRequest = { ...request };
430
+ delete resolved.integrationMode;
431
+ delete resolved.runtime;
432
+ delete resolved.testPolicyOverrides;
433
+ if (integrationMode) resolved.integrationMode = integrationMode;
434
+ if (runtime) resolved.runtime = runtime;
435
+ if (testPolicyOverrides) resolved.testPolicyOverrides = testPolicyOverrides;
436
+ return { request: resolved, runtime };
437
+ }
438
+
397
439
  function runtimeSelectionHeaders(
398
440
  runtime: PlayRuntimeSelection | undefined,
399
441
  ): Record<string, string> | undefined {
@@ -884,7 +926,7 @@ export type RunsNamespace = {
884
926
  runId?: string;
885
927
  limit?: number;
886
928
  offset?: number;
887
- rowMode?: 'output' | 'all';
929
+ rowMode?: 'output' | 'all' | 'live';
888
930
  /** Cancel the page request, including its response body and retry waits. */
889
931
  signal?: AbortSignal;
890
932
  }) => Promise<PlaySheetRowsResult>;
@@ -2163,6 +2205,17 @@ export type BillingUsageOptions = {
2163
2205
  runId?: string;
2164
2206
  };
2165
2207
 
2208
+ /** One run's billed credits and settlement state from `getRunBilling`. */
2209
+ export type RunBillingResult = {
2210
+ runs: Array<{
2211
+ runId: string;
2212
+ /** Customer-visible billed credits so far; absent when unknown. */
2213
+ credits?: number;
2214
+ /** The run owns a charge reservation that has not settled yet. */
2215
+ settling: boolean;
2216
+ }>;
2217
+ };
2218
+
2166
2219
  export type BillingUsageResult = {
2167
2220
  org_id: string;
2168
2221
  balance?: number;
@@ -2308,17 +2361,6 @@ function preferPrebuiltPlayDescriptions<T extends PlayDescription>(
2308
2361
  .map(({ play }) => play);
2309
2362
  }
2310
2363
 
2311
- function isPlayRunPackage(value: unknown): value is PlayRunPackage {
2312
- return Boolean(
2313
- value &&
2314
- typeof value === 'object' &&
2315
- !Array.isArray(value) &&
2316
- (value as Record<string, unknown>).kind === 'play_run' &&
2317
- (value as Record<string, unknown>).run &&
2318
- typeof (value as { run?: { id?: unknown } }).run?.id === 'string',
2319
- );
2320
- }
2321
-
2322
2364
  function normalizePlayStatus(raw: Record<string, unknown>): PlayStatus {
2323
2365
  const runPackage = isPlayRunPackage(raw)
2324
2366
  ? raw
@@ -2367,170 +2409,6 @@ function normalizePlayStatus(raw: Record<string, unknown>): PlayStatus {
2367
2409
  };
2368
2410
  }
2369
2411
 
2370
- function normalizePlayRunStart(raw: Record<string, unknown>): PlayRunStart {
2371
- const runPackage = isPlayRunPackage(raw)
2372
- ? raw
2373
- : isPlayRunPackage(raw.package)
2374
- ? raw.package
2375
- : null;
2376
- if (!runPackage) {
2377
- const workflowId =
2378
- typeof raw.workflowId === 'string' && raw.workflowId
2379
- ? raw.workflowId
2380
- : typeof raw.runId === 'string'
2381
- ? raw.runId
2382
- : '';
2383
- return {
2384
- ...(raw as unknown as Omit<PlayRunStart, 'workflowId'>),
2385
- workflowId,
2386
- };
2387
- }
2388
- const status =
2389
- typeof runPackage.run.status === 'string'
2390
- ? runPackage.run.status
2391
- : 'running';
2392
- return {
2393
- workflowId: runPackage.run.id,
2394
- name: runPackage.run.playName,
2395
- status,
2396
- ...(runPackage.run.dashboardUrl
2397
- ? { dashboardUrl: runPackage.run.dashboardUrl }
2398
- : {}),
2399
- ...(isTerminalPlayRunLifecycleStatus(status)
2400
- ? { finalStatus: runPackage }
2401
- : {}),
2402
- package: runPackage,
2403
- };
2404
- }
2405
-
2406
- function decodeBase64Bytes(value: string): Uint8Array {
2407
- const binary = atob(value);
2408
- const bytes = new Uint8Array(binary.length);
2409
- for (let index = 0; index < binary.length; index += 1) {
2410
- bytes[index] = binary.charCodeAt(index);
2411
- }
2412
- return bytes;
2413
- }
2414
-
2415
- /**
2416
- * A staged-file upload target minted by POST /api/v2/plays/files/stage/mint.
2417
- * When `alreadyStaged` is true the server already holds the content-addressed
2418
- * object and `uploadUrl` is null; otherwise the client PUTs the body to
2419
- * `uploadUrl` with `uploadHeaders`.
2420
- */
2421
- type MintStagedFileUpload = {
2422
- logicalPath: string;
2423
- contentHash: string;
2424
- ref: PlayStagedFileRef;
2425
- alreadyStaged: boolean;
2426
- uploadUrl: string | null;
2427
- uploadHeaders: Record<string, string> | null;
2428
- uploadExpiresAt: string | null;
2429
- };
2430
-
2431
- // Legacy multipart staging proxies the body through the serverless function,
2432
- // which caps request bodies near 4.5MB. Stay conservatively below that so the
2433
- // fail-loud guidance fires before the platform returns an opaque 413.
2434
- const STAGE_LEGACY_MULTIPART_MAX_BYTES = 4_000_000;
2435
-
2436
- const STAGE_DIRECT_UPLOAD_MAX_ATTEMPTS = 3;
2437
-
2438
- function stagedUploadIdentity(
2439
- logicalPath: string,
2440
- contentHash: string,
2441
- ): string {
2442
- return `${contentHash}:${logicalPath}`;
2443
- }
2444
-
2445
- function isStagedUploadMintUnsupported(error: unknown): boolean {
2446
- // A server without the mint route returns 404. Treat only that as
2447
- // "unsupported, fall back"; every other failure propagates.
2448
- return error instanceof DeeplineError && error.statusCode === 404;
2449
- }
2450
-
2451
- function isStagedUploadDirectEgressDenied(error: unknown): boolean {
2452
- return (
2453
- error instanceof DeeplineError &&
2454
- error.code === 'STAGED_FILE_UPLOAD_EGRESS_DENIED'
2455
- );
2456
- }
2457
-
2458
- function formatMegabytes(bytes: number): string {
2459
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2460
- }
2461
-
2462
- async function uploadStagedFileToPresignedUrl(input: {
2463
- url: string;
2464
- headers: Record<string, string>;
2465
- body: Uint8Array;
2466
- logicalPath: string;
2467
- }): Promise<void> {
2468
- // Wrap the bytes in a fresh Blob so the body is a BodyInit and the upload is
2469
- // re-runnable across retries (a consumed stream would not be).
2470
- const arrayBuffer = input.body.buffer.slice(
2471
- input.body.byteOffset,
2472
- input.body.byteOffset + input.body.byteLength,
2473
- ) as ArrayBuffer;
2474
- let lastError: unknown;
2475
- for (
2476
- let attempt = 1;
2477
- attempt <= STAGE_DIRECT_UPLOAD_MAX_ATTEMPTS;
2478
- attempt += 1
2479
- ) {
2480
- try {
2481
- const response = await fetch(input.url, {
2482
- method: 'PUT',
2483
- headers: input.headers,
2484
- body: new Blob([arrayBuffer]),
2485
- });
2486
- if (response.ok) {
2487
- return;
2488
- }
2489
- const text = await response.text().catch(() => '');
2490
- const egressDenied =
2491
- response.status === 403 &&
2492
- response.headers.get('x-deny-reason')?.trim().toLowerCase() ===
2493
- 'host_not_allowed';
2494
- lastError = new DeeplineError(
2495
- `Direct storage upload of ${input.logicalPath} failed: ${response.status} ${text.slice(0, 200)}`,
2496
- response.status,
2497
- egressDenied
2498
- ? 'STAGED_FILE_UPLOAD_EGRESS_DENIED'
2499
- : 'STAGED_FILE_UPLOAD_FAILED',
2500
- { logicalPath: input.logicalPath },
2501
- );
2502
- // 4xx (other than throttling) will not recover on retry.
2503
- if (response.status < 500 && response.status !== 429) {
2504
- break;
2505
- }
2506
- } catch (error) {
2507
- // fetch rejects network-level failures instead of returning a Response.
2508
- // Sandboxed egress proxies commonly reject the TLS CONNECT this way, so
2509
- // preserve the existing multipart fallback after direct retries finish.
2510
- lastError =
2511
- error instanceof TypeError
2512
- ? new DeeplineError(
2513
- `Direct storage upload of ${input.logicalPath} could not reach the storage endpoint: ${error.message}`,
2514
- undefined,
2515
- 'STAGED_FILE_UPLOAD_EGRESS_DENIED',
2516
- { logicalPath: input.logicalPath },
2517
- )
2518
- : error;
2519
- }
2520
- if (attempt < STAGE_DIRECT_UPLOAD_MAX_ATTEMPTS) {
2521
- await sleep(250 * attempt);
2522
- }
2523
- }
2524
- throw lastError instanceof Error
2525
- ? lastError
2526
- : new DeeplineError(
2527
- `Direct storage upload of ${input.logicalPath} failed.`,
2528
- undefined,
2529
- 'STAGED_FILE_UPLOAD_FAILED',
2530
- { logicalPath: input.logicalPath },
2531
- );
2532
- }
2533
-
2534
2412
  function readStringArray(value: unknown): string[] {
2535
2413
  return Array.isArray(value)
2536
2414
  ? value.filter((line): line is string => typeof line === 'string')
@@ -3422,74 +3300,12 @@ export class DeeplineClient {
3422
3300
  * ```
3423
3301
  */
3424
3302
  async startPlayRun(request: StartPlayRunRequest): Promise<PlayRunStart> {
3425
- const integrationMode = resolvePlayRunIntegrationMode(request);
3426
- const testPolicyOverrides =
3427
- request.testPolicyOverrides ?? parseEnvTestPolicyOverrides();
3428
- const forceToolRefresh = request.forceToolRefresh === true;
3429
- const runtime = resolvePlayRunRuntimeSelection(request);
3430
- const response = await this.http.post<Record<string, unknown>>(
3431
- '/api/v2/plays/run',
3432
- {
3433
- ...(request.name ? { name: request.name } : {}),
3434
- ...(request.revisionId ? { revisionId: request.revisionId } : {}),
3435
- ...(request.artifactStorageKey
3436
- ? { artifactStorageKey: request.artifactStorageKey }
3437
- : {}),
3438
- ...(request.sourceCode ? { sourceCode: request.sourceCode } : {}),
3439
- ...(request.sourceFiles ? { sourceFiles: request.sourceFiles } : {}),
3440
- ...(request.description ? { description: request.description } : {}),
3441
- ...('staticPipeline' in request
3442
- ? { staticPipeline: request.staticPipeline }
3443
- : {}),
3444
- ...(request.artifactHash ? { artifactHash: request.artifactHash } : {}),
3445
- ...(request.graphHash ? { graphHash: request.graphHash } : {}),
3446
- ...(request.runtimeArtifact
3447
- ? { runtimeArtifact: request.runtimeArtifact }
3448
- : {}),
3449
- ...(request.compilerManifest
3450
- ? { compilerManifest: request.compilerManifest }
3451
- : {}),
3452
- ...(request.inputFileUpload
3453
- ? { inputFileUpload: request.inputFileUpload }
3454
- : {}),
3455
- ...(request.packagedFileUploads?.length
3456
- ? { packagedFileUploads: request.packagedFileUploads }
3457
- : {}),
3458
- ...(request.input ? { input: request.input } : {}),
3459
- ...(request.inputFile ? { inputFile: request.inputFile } : {}),
3460
- ...(request.packagedFiles?.length
3461
- ? { packagedFiles: request.packagedFiles }
3462
- : {}),
3463
- ...(request.force ? { force: true } : {}),
3464
- ...(forceToolRefresh ? { forceToolRefresh: true } : {}),
3465
- ...(typeof request.maxConcurrentExternalCalls === 'number'
3466
- ? {
3467
- maxConcurrentExternalCalls: request.maxConcurrentExternalCalls,
3468
- }
3469
- : {}),
3470
- ...(typeof request.maxConcurrentRows === 'number'
3471
- ? { maxConcurrentRows: request.maxConcurrentRows }
3472
- : {}),
3473
- ...(typeof request.waitForCompletionMs === 'number'
3474
- ? { waitForCompletionMs: request.waitForCompletionMs }
3475
- : {}),
3476
- // Profile selection is the API's job, not the CLI's. The server
3477
- // defaults to absurd; callers normally omit this field.
3478
- ...(request.profile ? { profile: request.profile } : {}),
3479
- ...(integrationMode ? { integrationMode } : {}),
3480
- ...(request.fixtureBehavior
3481
- ? { fixtureBehavior: request.fixtureBehavior }
3482
- : {}),
3483
- ...(runtime ? { runtime } : {}),
3484
- ...(testPolicyOverrides ? { testPolicyOverrides } : {}),
3485
- },
3486
- runtimeSelectionHeaders(runtime),
3487
- // A start can reach the server even when its response is lost or times
3488
- // out. Retrying this mutation without an idempotency key can create a
3489
- // second root run, so callers must resolve ambiguous failures explicitly.
3490
- { maxRetries: 0, exactUrlOnly: true },
3303
+ const resolved = resolveStartPlayRunRequest(request);
3304
+ return startPlayRun(
3305
+ this.http,
3306
+ resolved.request,
3307
+ runtimeSelectionHeaders(resolved.runtime),
3491
3308
  );
3492
- return normalizePlayRunStart(response);
3493
3309
  }
3494
3310
 
3495
3311
  /**
@@ -3509,67 +3325,14 @@ export class DeeplineClient {
3509
3325
  request: StartPlayRunRequest,
3510
3326
  options?: { signal?: AbortSignal },
3511
3327
  ): AsyncGenerator<PlayLiveEvent> {
3512
- const integrationMode = resolvePlayRunIntegrationMode(request);
3513
- const testPolicyOverrides =
3514
- request.testPolicyOverrides ?? parseEnvTestPolicyOverrides();
3515
- const forceToolRefresh = request.forceToolRefresh === true;
3516
- const runtime = resolvePlayRunRuntimeSelection(request);
3517
- const body = {
3518
- ...(request.name ? { name: request.name } : {}),
3519
- ...(request.revisionId ? { revisionId: request.revisionId } : {}),
3520
- ...(request.artifactStorageKey
3521
- ? { artifactStorageKey: request.artifactStorageKey }
3522
- : {}),
3523
- ...(request.sourceCode ? { sourceCode: request.sourceCode } : {}),
3524
- ...(request.sourceFiles ? { sourceFiles: request.sourceFiles } : {}),
3525
- ...(request.description ? { description: request.description } : {}),
3526
- ...('staticPipeline' in request
3527
- ? { staticPipeline: request.staticPipeline }
3528
- : {}),
3529
- ...(request.artifactHash ? { artifactHash: request.artifactHash } : {}),
3530
- ...(request.graphHash ? { graphHash: request.graphHash } : {}),
3531
- ...(request.runtimeArtifact
3532
- ? { runtimeArtifact: request.runtimeArtifact }
3533
- : {}),
3534
- ...(request.compilerManifest
3535
- ? { compilerManifest: request.compilerManifest }
3536
- : {}),
3537
- ...(request.inputFileUpload
3538
- ? { inputFileUpload: request.inputFileUpload }
3539
- : {}),
3540
- ...(request.packagedFileUploads?.length
3541
- ? { packagedFileUploads: request.packagedFileUploads }
3542
- : {}),
3543
- ...(request.input ? { input: request.input } : {}),
3544
- ...(request.inputFile ? { inputFile: request.inputFile } : {}),
3545
- ...(request.packagedFiles?.length
3546
- ? { packagedFiles: request.packagedFiles }
3547
- : {}),
3548
- ...(request.force ? { force: true } : {}),
3549
- ...(forceToolRefresh ? { forceToolRefresh: true } : {}),
3550
- ...(typeof request.maxConcurrentExternalCalls === 'number'
3551
- ? { maxConcurrentExternalCalls: request.maxConcurrentExternalCalls }
3552
- : {}),
3553
- ...(typeof request.maxConcurrentRows === 'number'
3554
- ? { maxConcurrentRows: request.maxConcurrentRows }
3555
- : {}),
3556
- ...(typeof request.waitForCompletionMs === 'number'
3557
- ? { waitForCompletionMs: request.waitForCompletionMs }
3558
- : {}),
3559
- ...(request.profile ? { profile: request.profile } : {}),
3560
- ...(integrationMode ? { integrationMode } : {}),
3561
- ...(request.fixtureBehavior
3562
- ? { fixtureBehavior: request.fixtureBehavior }
3563
- : {}),
3564
- ...(runtime ? { runtime } : {}),
3565
- ...(testPolicyOverrides ? { testPolicyOverrides } : {}),
3566
- };
3328
+ const resolved = resolveStartPlayRunRequest(request);
3329
+ const body = buildPlayRunStartBody(resolved.request);
3567
3330
  for await (const event of this.http.streamSse<PlayLiveEvent>(
3568
- '/api/v2/plays/run?stream=true',
3331
+ PLAY_RUN_START_STREAM_PATH,
3569
3332
  {
3570
3333
  method: 'POST',
3571
3334
  body,
3572
- headers: runtimeSelectionHeaders(runtime),
3335
+ headers: runtimeSelectionHeaders(resolved.runtime),
3573
3336
  signal: options?.signal,
3574
3337
  },
3575
3338
  )) {
@@ -3998,94 +3761,7 @@ export class DeeplineClient {
3998
3761
  bytes: number;
3999
3762
  }>,
4000
3763
  ): Promise<PlayStagedFileRef[]> {
4001
- // Primary path: mint presigned R2 PUT targets and upload each file body
4002
- // straight to storage. This bypasses the ~4.5MB serverless request-body
4003
- // limit that the legacy multipart proxy hits (413
4004
- // FUNCTION_PAYLOAD_TOO_LARGE), so large enriched CSVs stage and resume.
4005
- let uploads: MintStagedFileUpload[];
4006
- try {
4007
- uploads = await this.mintStagedPlayFileUploads(
4008
- files.map((file) => ({
4009
- logicalPath: file.logicalPath,
4010
- contentHash: file.contentHash,
4011
- contentType: file.contentType,
4012
- bytes: file.bytes,
4013
- })),
4014
- );
4015
- } catch (error) {
4016
- if (isStagedUploadMintUnsupported(error)) {
4017
- // The connected server predates direct-to-storage staging. Fall back to
4018
- // the legacy multipart proxy, but only for files small enough to clear
4019
- // the serverless body limit; larger files fail loud with guidance.
4020
- return this.stagePlayFilesViaMultipart(files);
4021
- }
4022
- throw error;
4023
- }
4024
-
4025
- const uploadByIdentity = new Map<string, MintStagedFileUpload>();
4026
- for (const upload of uploads) {
4027
- uploadByIdentity.set(
4028
- stagedUploadIdentity(upload.logicalPath, upload.contentHash),
4029
- upload,
4030
- );
4031
- }
4032
-
4033
- type DirectStageResult =
4034
- | { ref: PlayStagedFileRef }
4035
- | { fallbackFile: (typeof files)[number] };
4036
- const directResults: DirectStageResult[] = await Promise.all(
4037
- files.map(async (file) => {
4038
- const upload = uploadByIdentity.get(
4039
- stagedUploadIdentity(file.logicalPath, file.contentHash),
4040
- );
4041
- if (!upload) {
4042
- throw new DeeplineError(
4043
- `The staging server did not return an upload target for ${file.logicalPath}.`,
4044
- undefined,
4045
- 'STAGED_FILE_MINT_INCOMPLETE',
4046
- );
4047
- }
4048
- if (upload.alreadyStaged || !upload.uploadUrl) {
4049
- return { ref: upload.ref };
4050
- }
4051
- try {
4052
- await uploadStagedFileToPresignedUrl({
4053
- url: upload.uploadUrl,
4054
- headers: upload.uploadHeaders ?? {
4055
- 'content-type': file.contentType,
4056
- },
4057
- body: decodeBase64Bytes(file.contentBase64),
4058
- logicalPath: file.logicalPath,
4059
- });
4060
- return { ref: upload.ref };
4061
- } catch (error) {
4062
- if (isStagedUploadDirectEgressDenied(error)) {
4063
- return { fallbackFile: file };
4064
- }
4065
- throw error;
4066
- }
4067
- }),
4068
- );
4069
-
4070
- return await Promise.all(
4071
- directResults.map(async (result) => {
4072
- if ('fallbackFile' in result) {
4073
- const [ref] = await this.stagePlayFilesViaMultipart(
4074
- [result.fallbackFile],
4075
- 'direct-egress-denied',
4076
- );
4077
- if (!ref) {
4078
- throw new DeeplineError(
4079
- `The staging server did not return an upload target for ${result.fallbackFile.logicalPath}.`,
4080
- undefined,
4081
- 'STAGED_FILE_MINT_INCOMPLETE',
4082
- );
4083
- }
4084
- return ref;
4085
- }
4086
- return result.ref;
4087
- }),
4088
- );
3764
+ return stagePlayFiles(this.http, files);
4089
3765
  }
4090
3766
 
4091
3767
  /**
@@ -4103,72 +3779,7 @@ export class DeeplineClient {
4103
3779
  bytes: number;
4104
3780
  }>,
4105
3781
  ): Promise<MintStagedFileUpload[]> {
4106
- const response = await this.http.post<{
4107
- uploads: MintStagedFileUpload[];
4108
- }>('/api/v2/plays/files/stage/mint', { files });
4109
- return response.uploads ?? [];
4110
- }
4111
-
4112
- private async stagePlayFilesViaMultipart(
4113
- files: Array<{
4114
- logicalPath: string;
4115
- contentBase64: string;
4116
- contentHash: string;
4117
- contentType: string;
4118
- bytes: number;
4119
- }>,
4120
- reason: 'mint-unsupported' | 'direct-egress-denied' = 'mint-unsupported',
4121
- ): Promise<PlayStagedFileRef[]> {
4122
- for (const file of files) {
4123
- if (file.bytes > STAGE_LEGACY_MULTIPART_MAX_BYTES) {
4124
- const reasonMessage =
4125
- reason === 'direct-egress-denied'
4126
- ? "direct storage is blocked by this environment's network egress policy"
4127
- : 'the connected Deepline server does not support direct-to-storage uploads';
4128
- throw new DeeplineError(
4129
- `Cannot stage ${file.logicalPath} (${formatMegabytes(file.bytes)}): ${reasonMessage}, and this file exceeds the ~4.5MB request-body limit the legacy upload path is subject to.`,
4130
- 413,
4131
- 'STAGED_FILE_TOO_LARGE_FOR_LEGACY_UPLOAD',
4132
- {
4133
- logicalPath: file.logicalPath,
4134
- bytes: file.bytes,
4135
- maxBytes: STAGE_LEGACY_MULTIPART_MAX_BYTES,
4136
- },
4137
- );
4138
- }
4139
- }
4140
- const buildFormData = () => {
4141
- const formData = new FormData();
4142
- formData.set(
4143
- 'metadata',
4144
- JSON.stringify({
4145
- files: files.map((file, index) => ({
4146
- index,
4147
- logicalPath: file.logicalPath,
4148
- contentHash: file.contentHash,
4149
- contentType: file.contentType,
4150
- bytes: file.bytes,
4151
- })),
4152
- }),
4153
- );
4154
- for (const [index, file] of files.entries()) {
4155
- const bytes = decodeBase64Bytes(file.contentBase64);
4156
- const body = bytes.buffer.slice(
4157
- bytes.byteOffset,
4158
- bytes.byteOffset + bytes.byteLength,
4159
- ) as ArrayBuffer;
4160
- formData.set(
4161
- `file:${index}`,
4162
- new Blob([body], { type: file.contentType }),
4163
- file.logicalPath,
4164
- );
4165
- }
4166
- return formData;
4167
- };
4168
- const response = await this.http.postFormData<{
4169
- files: PlayStagedFileRef[];
4170
- }>('/api/v2/plays/files/stage', buildFormData);
4171
- return response.files;
3782
+ return mintStagedPlayFileUploads(this.http, files);
4172
3783
  }
4173
3784
 
4174
3785
  /**
@@ -4750,7 +4361,7 @@ export class DeeplineClient {
4750
4361
  }
4751
4362
  return this.http.post<RerunPlayRunResult>(
4752
4363
  `/api/v2/runs/${encodeURIComponent(runId)}/rerun`,
4753
- {},
4364
+ options?.inputOverrides ? { inputOverrides: options.inputOverrides } : {},
4754
4365
  { 'Idempotency-Key': idempotencyKey || globalThis.crypto.randomUUID() },
4755
4366
  );
4756
4367
  }
@@ -4906,7 +4517,7 @@ export class DeeplineClient {
4906
4517
  runId?: string;
4907
4518
  limit?: number;
4908
4519
  offset?: number;
4909
- rowMode?: 'output' | 'all';
4520
+ rowMode?: 'output' | 'all' | 'live';
4910
4521
  /** Cancel the page request, including its response body and retry waits. */
4911
4522
  signal?: AbortSignal;
4912
4523
  }): Promise<PlaySheetRowsResult> {
@@ -4918,8 +4529,8 @@ export class DeeplineClient {
4918
4529
  if (input.runId?.trim()) {
4919
4530
  params.set('runId', input.runId.trim());
4920
4531
  }
4921
- if (input.rowMode === 'all') {
4922
- params.set('rowMode', 'all');
4532
+ if (input.rowMode === 'all' || input.rowMode === 'live') {
4533
+ params.set('rowMode', input.rowMode);
4923
4534
  }
4924
4535
  const result = await this.http.get<PlaySheetRowsResult>(
4925
4536
  `/api/v2/plays/${encodeURIComponent(input.playName)}/sheet?${params.toString()}`,
@@ -5146,6 +4757,23 @@ export class DeeplineClient {
5146
4757
  );
5147
4758
  }
5148
4759
 
4760
+ /** Read a Play's cron and webhook triggers and their scheduler state. */
4761
+ async getPlayTriggerConfig(playName: string): Promise<PlayTriggerConfigView> {
4762
+ return this.http.get(playTriggerConfigPath(playName));
4763
+ }
4764
+
4765
+ /**
4766
+ * Declare a Play's cron and/or webhook trigger (null removes it) and publish
4767
+ * the rewritten source as a new live revision. Retry-safe: a request the
4768
+ * live revision already satisfies returns `changed: false`.
4769
+ */
4770
+ async updatePlayTriggerConfig(
4771
+ playName: string,
4772
+ update: PlayTriggerConfigUpdate,
4773
+ ): Promise<PlayTriggerConfigUpdateResult> {
4774
+ return this.http.put(playTriggerConfigPath(playName), update);
4775
+ }
4776
+
5149
4777
  /** List one bounded page of existing Play locations; continue with cursor. */
5150
4778
  async listPlaySettingsPaths(
5151
4779
  options: { root?: 'person' | 'team'; limit?: number; cursor?: string } = {},
@@ -6028,6 +5656,17 @@ export class DeeplineClient {
6028
5656
  return event;
6029
5657
  }
6030
5658
 
5659
+ /**
5660
+ * What Deepline has billed each run so far (customer-visible credits, never
5661
+ * provider spend) and whether any of its charges is still settling — the
5662
+ * same read the dashboard's runs grid shows. `GET /api/v2/runs/billing`.
5663
+ */
5664
+ async getRunBilling(runIds: readonly string[]): Promise<RunBillingResult> {
5665
+ const params = new URLSearchParams();
5666
+ for (const runId of runIds) params.append('runId', runId);
5667
+ return this.http.get<RunBillingResult>(`/api/v2/runs/billing?${params}`);
5668
+ }
5669
+
6031
5670
  /**
6032
5671
  * Read workspace usage and recent customer-facing Deepline charges. Pass
6033
5672
  * the `job_id` from `executeTool` as `requestId` to retrieve one exact call,