deepline 0.2.12 → 0.2.14

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 (39) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +159 -3
  2. package/dist/bundling-sources/sdk/src/index.ts +3 -0
  3. package/dist/bundling-sources/sdk/src/play.ts +150 -691
  4. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  5. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +7 -1
  6. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +319 -138
  7. package/dist/bundling-sources/shared_libs/play-runtime/csv-rename.ts +10 -6
  8. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +34 -52
  9. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +11 -22
  10. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-policy.ts +34 -0
  11. package/dist/bundling-sources/shared_libs/play-runtime/play-call-execution.ts +2 -1
  12. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-projection-contract.ts +95 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +2 -1
  14. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +24 -7
  15. package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +8 -1
  16. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +7 -4
  17. package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +23 -15
  18. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +3 -0
  19. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +2222 -0
  20. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +3 -2
  21. package/dist/bundling-sources/shared_libs/plays/compiler-manifest.ts +2 -0
  22. package/dist/bundling-sources/shared_libs/plays/contracts.ts +16 -0
  23. package/dist/bundling-sources/shared_libs/plays/input-contract-definition.ts +28 -0
  24. package/dist/bundling-sources/shared_libs/plays/input-contract.ts +3 -3
  25. package/dist/cli/index.js +5231 -830
  26. package/dist/cli/index.mjs +5178 -762
  27. package/dist/compiler-manifest-xFkbJX2B.d.mts +2517 -0
  28. package/dist/compiler-manifest-xFkbJX2B.d.ts +2517 -0
  29. package/dist/index.d.mts +126 -1014
  30. package/dist/index.d.ts +126 -1014
  31. package/dist/index.js +88 -8
  32. package/dist/index.mjs +88 -8
  33. package/dist/plays/bundle-play-file.d.mts +5 -8
  34. package/dist/plays/bundle-play-file.d.ts +5 -8
  35. package/dist/plays/bundle-play-file.mjs +3844 -3
  36. package/package.json +1 -1
  37. package/dist/bundling-sources/shared_libs/plays/source-metadata.ts +0 -240
  38. package/dist/tool-execution-error-4-rhemLQ.d.mts +0 -446
  39. package/dist/tool-execution-error-4-rhemLQ.d.ts +0 -446
@@ -1,10 +1,14 @@
1
- export type CsvRenameMap = Record<string, string | readonly string[]>;
1
+ import type {
2
+ PlayAuthoringCsvOptions,
3
+ PlayAuthoringCsvRenameMap,
4
+ } from '../plays/authoring-contract';
2
5
 
3
- export type CsvRenameOptions = {
4
- columns?: CsvRenameMap;
5
- rename?: CsvRenameMap;
6
- required?: readonly string[];
7
- };
6
+ export type CsvRenameMap = PlayAuthoringCsvRenameMap;
7
+
8
+ export type CsvRenameOptions = Pick<
9
+ PlayAuthoringCsvOptions,
10
+ 'columns' | 'rename' | 'required'
11
+ >;
8
12
 
9
13
  const CSV_PROJECTED_FIELDS = Symbol.for('deepline.play.csv.projected_fields');
10
14
  const CSV_PROJECTED_FIELDS_KEY = '__deeplineCsvProjectedFields';
@@ -3,6 +3,18 @@ import type { PlayBundleArtifact } from '../plays/artifact-types';
3
3
  import type { PlayRunContractSnapshot } from '../plays/contracts';
4
4
  import type { PlayStructuredDefinition } from '../plays/definition';
5
5
  import type { PlayStaticPipeline } from '../plays/static-pipeline';
6
+ import type {
7
+ DurableCallStaleAfterSeconds,
8
+ PlayAuthoringCallOptions,
9
+ PlayAuthoringCsvOptions,
10
+ PlayAuthoringFetchOptions,
11
+ PlayAuthoringRuntimeStepOptions,
12
+ PlayAuthoringContractEdition,
13
+ PlayToolCallOptions,
14
+ PlayToolExecutionRequest,
15
+ PlayReceiptWaitMs,
16
+ PlayRuntimeTimeoutMs,
17
+ } from '../plays/authoring-contract';
6
18
  import type {
7
19
  PlayDataset,
8
20
  PlayDatasetInput,
@@ -204,17 +216,13 @@ export interface HeartbeatRuntimeStepReceiptsInput {
204
216
  keys: string[];
205
217
  runId: string;
206
218
  runAttempt?: number | null;
207
- leaseId: string;
219
+ leaseId?: string;
220
+ leaseIds?: string[];
208
221
  }
209
222
 
210
- export interface CsvOptions {
211
- description?: string;
212
- columns?: Record<string, string | readonly string[]>;
213
- rename?: Record<string, string | readonly string[]>;
214
- required?: readonly string[];
215
- }
223
+ export type CsvOptions = PlayAuthoringCsvOptions;
216
224
 
217
- export interface DatasetOptions<TItem = Record<string, unknown>> {
225
+ export interface RuntimeDatasetOptions<TItem = Record<string, unknown>> {
218
226
  description?: string;
219
227
  /**
220
228
  * Optional relative cache window for intentional reruns.
@@ -269,58 +277,30 @@ export interface DatasetOptions<TItem = Record<string, unknown>> {
269
277
  mode?: 'upsert' | 'net_new';
270
278
  }
271
279
 
272
- export type DatasetDefinitionOptions<TItem = Record<string, unknown>> = Omit<
273
- DatasetOptions<TItem>,
274
- 'description'
275
- >;
280
+ export type RuntimeDatasetDefinitionOptions<TItem = Record<string, unknown>> =
281
+ Omit<RuntimeDatasetOptions<TItem>, 'description'>;
276
282
 
277
- export type DatasetRunOptions<TItem = Record<string, unknown>> = Pick<
278
- DatasetOptions<TItem>,
283
+ export type RuntimeDatasetRunOptions<TItem = Record<string, unknown>> = Pick<
284
+ RuntimeDatasetOptions<TItem>,
279
285
  'description' | 'key' | 'onRowError' | 'mode'
280
286
  >;
281
287
 
282
- export interface ToolCallOptions {
283
- description?: string;
284
- force?: boolean;
285
- staleAfterSeconds?: number;
286
- timeoutMs?: number;
287
- receiptWaitMs?: number;
288
- }
288
+ export type ToolCallOptions = PlayToolCallOptions;
289
+ export type ToolExecutionRequest = PlayToolExecutionRequest;
289
290
 
290
- export interface ToolExecutionRequest {
291
- id: string;
292
- tool: string;
293
- input: Record<string, unknown>;
294
- description?: string;
295
- force?: boolean;
296
- staleAfterSeconds?: number;
297
- timeoutMs?: number;
298
- receiptWaitMs?: number;
299
- }
300
-
301
- export interface PlayCallOptions {
302
- description?: string;
303
- /**
304
- * `child-workflow` is accepted only so the checker/runtime can emit the
305
- * canonical CTX_RUN_PLAY_INLINE_ONLY migration diagnostic. It never starts a
306
- * child workflow.
307
- */
291
+ export type PlayCallOptions = Omit<
292
+ PlayAuthoringCallOptions,
293
+ 'execution' | 'timeoutMs'
294
+ > & {
295
+ /** Legacy invalid spelling retained only for the stable migration error. */
308
296
  execution?: PlayCallExecution | 'child-workflow';
309
- /**
310
- * Parsed so source preflight and an untyped runtime call can return the
311
- * canonical CTX_RUN_PLAY_INLINE_ONLY migration error. It is never honored.
312
- */
297
+ /** Legacy invalid option retained only for the stable migration error. */
313
298
  timeoutMs?: number;
314
- }
299
+ };
315
300
 
316
- export interface StepOptions {
317
- semanticKey?: string;
318
- staleAfterSeconds?: number;
319
- }
301
+ export type RuntimeStepOptions = PlayAuthoringRuntimeStepOptions;
320
302
 
321
- export interface FetchOptions {
322
- staleAfterSeconds?: number;
323
- }
303
+ export type FetchOptions = PlayAuthoringFetchOptions;
324
304
 
325
305
  export interface ResolvedPlayExecution {
326
306
  playId: string;
@@ -501,6 +481,8 @@ export type IntegrationEventWaitHandler = {
501
481
  export interface ContextOptions {
502
482
  /** Immutable logical and physical execution identity for this context. */
503
483
  executionScope?: RunExecutionScope;
484
+ /** Authoring semantics pinned by the immutable artifact. */
485
+ authoringContractEdition?: PlayAuthoringContractEdition;
504
486
  /** Error shape pinned by the immutable play artifact; missing preserves legacy schema 0. */
505
487
  toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
506
488
  /** Short-lived HMAC-signed internal token for tool callbacks. Required for cloud execution. */
@@ -588,7 +570,7 @@ export interface ContextOptions {
588
570
  staticPipeline?: PlayStaticPipeline | null;
589
571
  forceRefresh?: boolean;
590
572
  inputOffset?: number;
591
- mode?: DatasetRunOptions['mode'];
573
+ mode?: RuntimeDatasetRunOptions['mode'];
592
574
  },
593
575
  ) => Promise<MapStartResult>;
594
576
  /**
@@ -6,40 +6,29 @@ import {
6
6
  // packed SDK's dist/bundling-sources graph, where only relative imports
7
7
  // resolve.
8
8
  } from '../plays/row-identity';
9
+ import { resolveDurableCallCachePolicy } from './durable-call-policy';
10
+
11
+ export {
12
+ DURABLE_CALL_STALE_AFTER_SECONDS_ERROR,
13
+ resolveDurableCallCachePolicy,
14
+ } from './durable-call-policy';
15
+ export type { DurableCallCachePolicy } from './durable-call-policy';
9
16
 
10
17
  export const DURABLE_CALL_CACHE_POLICY_VERSION = 'call-cache-v1';
11
18
 
12
19
  export type DurableCallKind = 'tool' | 'step' | 'fetch';
13
20
 
14
- function validateStaleAfterSeconds(staleAfterSeconds?: number | null): void {
15
- if (staleAfterSeconds === undefined || staleAfterSeconds === null) {
16
- return;
17
- }
18
- if (
19
- !Number.isFinite(staleAfterSeconds) ||
20
- !Number.isInteger(staleAfterSeconds) ||
21
- staleAfterSeconds <= 0
22
- ) {
23
- throw new Error(
24
- 'staleAfterSeconds must be a positive whole number of seconds.',
25
- );
26
- }
27
- }
28
-
29
21
  export function durableCacheStaleBucket(input: {
30
22
  staleAfterSeconds?: number | null;
31
23
  nowMs?: number;
32
24
  }): string | null {
33
- validateStaleAfterSeconds(input.staleAfterSeconds);
34
- if (
35
- input.staleAfterSeconds === undefined ||
36
- input.staleAfterSeconds === null
37
- ) {
25
+ const policy = resolveDurableCallCachePolicy(input.staleAfterSeconds);
26
+ if (policy.staleAfterSeconds === null) {
38
27
  return null;
39
28
  }
40
29
  const nowMs = input.nowMs ?? Date.now();
41
- return `${input.staleAfterSeconds}:${Math.floor(
42
- nowMs / (input.staleAfterSeconds * 1000),
30
+ return `${policy.staleAfterSeconds}:${Math.floor(
31
+ nowMs / (policy.staleAfterSeconds * 1000),
43
32
  )}`;
44
33
  }
45
34
 
@@ -0,0 +1,34 @@
1
+ import {
2
+ PLAY_AUTHORING_FIELD_REGISTRY,
3
+ validatePlayAuthoringField,
4
+ type PlayAuthoringFieldPath,
5
+ } from '../plays/authoring-contract';
6
+
7
+ export const DURABLE_CALL_STALE_AFTER_SECONDS_ERROR =
8
+ PLAY_AUTHORING_FIELD_REGISTRY['ctx.tools.execute.staleAfterSeconds']
9
+ .errorMessage;
10
+
11
+ export type DurableCallCachePolicy = {
12
+ forceRefresh: boolean;
13
+ staleAfterSeconds: number | null;
14
+ };
15
+
16
+ /** Normalize the public freshness contract shared by durable calls. */
17
+ export function resolveDurableCallCachePolicy(
18
+ staleAfterSeconds?: number | null,
19
+ path: Extract<
20
+ PlayAuthoringFieldPath,
21
+ | 'ctx.tools.execute.staleAfterSeconds'
22
+ | 'ctx.step.staleAfterSeconds'
23
+ | 'ctx.fetch.staleAfterSeconds'
24
+ > = 'ctx.tools.execute.staleAfterSeconds',
25
+ ): DurableCallCachePolicy {
26
+ if (staleAfterSeconds === undefined || staleAfterSeconds === null) {
27
+ return { forceRefresh: false, staleAfterSeconds: null };
28
+ }
29
+ if (staleAfterSeconds === 0) {
30
+ return { forceRefresh: true, staleAfterSeconds: null };
31
+ }
32
+ validatePlayAuthoringField(path, staleAfterSeconds);
33
+ return { forceRefresh: false, staleAfterSeconds };
34
+ }
@@ -3,4 +3,5 @@
3
3
  * recognizes the historical `child-workflow` spelling so preflight can return
4
4
  * CTX_RUN_PLAY_INLINE_ONLY, but it is no longer a supported runtime option.
5
5
  */
6
- export type PlayCallExecution = 'inline';
6
+ export type PlayCallExecution = Extract<PlayAuthoringCallExecution, 'inline'>;
7
+ import type { PlayAuthoringCallExecution } from '../plays/authoring-contract';
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Wire contract for idempotent Runtime Postgres -> Convex Run Ledger delivery.
3
+ *
4
+ * Producers must use these builders and API boundaries must use these
5
+ * validators. Keeping the format here prevents the scheduler and runtime route
6
+ * from admitting different lifecycle-event keys.
7
+ */
8
+
9
+ const UUID_PATTERN =
10
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
11
+ const SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/i;
12
+
13
+ function requireRunId(runId: string): void {
14
+ if (!runId.trim()) {
15
+ throw new Error('Run Ledger projection idempotency key requires a run id.');
16
+ }
17
+ }
18
+
19
+ function requireDeliveryKey(deliveryKey: string): void {
20
+ if (!UUID_PATTERN.test(deliveryKey)) {
21
+ throw new Error(
22
+ 'Run Ledger projection delivery key must be a canonical UUID.',
23
+ );
24
+ }
25
+ }
26
+
27
+ export function buildRunLedgerStartIdempotencyKey(input: {
28
+ runId: string;
29
+ deliveryKey: string;
30
+ }): string {
31
+ requireRunId(input.runId);
32
+ requireDeliveryKey(input.deliveryKey);
33
+ return `run-started:${input.runId}:${input.deliveryKey}`;
34
+ }
35
+
36
+ export function buildRunLedgerTerminalIdempotencyKey(input: {
37
+ runId: string;
38
+ deliveryKey: string;
39
+ }): string {
40
+ requireRunId(input.runId);
41
+ requireDeliveryKey(input.deliveryKey);
42
+ return `run-terminal:${input.runId}:${input.deliveryKey}`;
43
+ }
44
+
45
+ /**
46
+ * Compatibility key for the one-row projector. The `run-terminal` prefix was
47
+ * historically used for every non-start row, including lifecycle events, so
48
+ * changing it during a retry could append the same fact twice across deploys.
49
+ */
50
+ export function buildRunLedgerSingleEventIdempotencyKey(input: {
51
+ runId: string;
52
+ deliveryKey: string;
53
+ }): string {
54
+ return buildRunLedgerTerminalIdempotencyKey(input);
55
+ }
56
+
57
+ export function buildRunLedgerEventsIdempotencyKey(input: {
58
+ runId: string;
59
+ deliveryDigest: string;
60
+ }): string {
61
+ requireRunId(input.runId);
62
+ if (!SHA256_HEX_PATTERN.test(input.deliveryDigest)) {
63
+ throw new Error(
64
+ 'Run Ledger projection delivery digest must be a SHA-256 hex value.',
65
+ );
66
+ }
67
+ return `run-events:${input.runId}:${input.deliveryDigest}`;
68
+ }
69
+
70
+ export function isValidRunLedgerStartIdempotencyKey(input: {
71
+ runId: string;
72
+ idempotencyKey: string;
73
+ }): boolean {
74
+ const prefix = `run-started:${input.runId}:`;
75
+ return (
76
+ input.idempotencyKey.startsWith(prefix) &&
77
+ UUID_PATTERN.test(input.idempotencyKey.slice(prefix.length))
78
+ );
79
+ }
80
+
81
+ export function isValidRunLedgerAppendIdempotencyKey(input: {
82
+ runId: string;
83
+ idempotencyKey: string;
84
+ }): boolean {
85
+ const terminalPrefix = `run-terminal:${input.runId}:`;
86
+ if (input.idempotencyKey.startsWith(terminalPrefix)) {
87
+ return UUID_PATTERN.test(input.idempotencyKey.slice(terminalPrefix.length));
88
+ }
89
+
90
+ const eventsPrefix = `run-events:${input.runId}:`;
91
+ return (
92
+ input.idempotencyKey.startsWith(eventsPrefix) &&
93
+ SHA256_HEX_PATTERN.test(input.idempotencyKey.slice(eventsPrefix.length))
94
+ );
95
+ }
@@ -215,7 +215,8 @@ export type RuntimeReceiptAction =
215
215
  playName: string;
216
216
  runId: string;
217
217
  runAttempt?: number | null;
218
- leaseId: string;
218
+ leaseId?: string;
219
+ leaseIds?: string[];
219
220
  keys: string[];
220
221
  };
221
222
 
@@ -5799,15 +5799,30 @@ export async function heartbeatRuntimeWorkReceipts(
5799
5799
  playName: string;
5800
5800
  runId: string;
5801
5801
  runAttempt?: number | null;
5802
- leaseId: string;
5802
+ leaseId?: string;
5803
+ leaseIds?: string[];
5803
5804
  keys: string[];
5804
5805
  leaseTtlMs?: number | null;
5805
5806
  },
5806
5807
  ): Promise<Array<WorkReceipt | null>> {
5807
- const keys = input.keys.map((key) => key.trim()).filter(Boolean);
5808
+ if (
5809
+ input.leaseIds !== undefined &&
5810
+ input.leaseIds.length !== input.keys.length
5811
+ ) {
5812
+ throw new Error(
5813
+ `Runtime receipt bulk heartbeat requires one lease ID per key. Received ${input.leaseIds.length} lease IDs for ${input.keys.length} keys.`,
5814
+ );
5815
+ }
5816
+ const entries = input.keys
5817
+ .map((key, index) => ({
5818
+ key: key.trim(),
5819
+ leaseId: input.leaseIds?.[index]?.trim() || input.leaseId?.trim() || '',
5820
+ }))
5821
+ .filter((entry) => Boolean(entry.key));
5822
+ const keys = entries.map((entry) => entry.key);
5808
5823
  if (keys.length === 0) return [];
5809
- const leaseId = input.leaseId.trim();
5810
- if (!leaseId) return keys.map(() => null);
5824
+ const leaseIds = entries.map((entry) => entry.leaseId);
5825
+ if (leaseIds.some((leaseId) => !leaseId)) return keys.map(() => null);
5811
5826
  const runAttempt = normalizeRuntimeRunAttempt(input.runAttempt);
5812
5827
  const leaseTtlMs = normalizeRuntimeLeaseTtlMs(
5813
5828
  input.leaseTtlMs,
@@ -5824,8 +5839,10 @@ export async function heartbeatRuntimeWorkReceipts(
5824
5839
  const { rows } = await client.query<Record<string, unknown>>(
5825
5840
  `
5826
5841
  WITH input_keys AS (
5827
- SELECT key_values.key_hex, key_values.ord
5842
+ SELECT key_values.key_hex, lease_values.lease_id, key_values.ord
5828
5843
  FROM unnest($1::text[]) WITH ORDINALITY AS key_values(key_hex, ord)
5844
+ JOIN unnest($3::text[]) WITH ORDINALITY AS lease_values(lease_id, ord)
5845
+ ON lease_values.ord = key_values.ord
5829
5846
  ),
5830
5847
  renewed AS (
5831
5848
  UPDATE ${workReceiptTable(session)} AS target
@@ -5837,7 +5854,7 @@ export async function heartbeatRuntimeWorkReceipts(
5837
5854
  receiptTable: 'target',
5838
5855
  ownerRunIdSql: '$2::text',
5839
5856
  ownerRunAttemptSql: '$5',
5840
- leaseIdSql: '$3::text',
5857
+ leaseIdSql: 'input_keys.lease_id',
5841
5858
  })}
5842
5859
  RETURNING target.k,
5843
5860
  target.status,
@@ -5888,7 +5905,7 @@ export async function heartbeatRuntimeWorkReceipts(
5888
5905
  [
5889
5906
  keys.map(workReceiptKeyHex),
5890
5907
  input.runId,
5891
- leaseId,
5908
+ leaseIds,
5892
5909
  leaseTtlMs,
5893
5910
  runAttempt,
5894
5911
  ],
@@ -1,4 +1,4 @@
1
- export const PLAY_RUNTIME_CONTRACT = 3;
1
+ export const PLAY_RUNTIME_CONTRACT = 4;
2
2
  export const PLAY_RUNTIME_CONTRACT_MIN_SUPPORTED = 1;
3
3
  export const PLAY_RUNTIME_CONTRACT_HEADER = 'x-deepline-runtime-contract';
4
4
  /**
@@ -25,6 +25,13 @@ export function resolvePlayRuntimeTransportAttemptId(
25
25
  }
26
26
 
27
27
  export const RUNTIME_CONTRACT_CHANGELOG = [
28
+ {
29
+ contract: 4,
30
+ changed:
31
+ 'Runtime receipt heartbeat requests can carry one positional lease ID per receipt key.',
32
+ compatOwner: 'runtime',
33
+ compatRemoval: 'contract 3 runtime lane drain',
34
+ },
28
35
  {
29
36
  contract: 3,
30
37
  changed:
@@ -236,13 +236,13 @@ export class RuntimeReceiptStoreAdapter {
236
236
  ),
237
237
  heartbeatRuntimeStepReceipts: (input) =>
238
238
  writeMany(
239
- input.keys.map((key) => ({
239
+ input.keys.map((key, index) => ({
240
240
  kind: 'heartbeat' as const,
241
241
  input: {
242
242
  key,
243
243
  runId: input.runId,
244
244
  runAttempt: input.runAttempt,
245
- leaseId: input.leaseId,
245
+ leaseId: input.leaseIds?.[index] ?? input.leaseId ?? '',
246
246
  },
247
247
  })),
248
248
  ),
@@ -387,7 +387,6 @@ function receiptCommandBatchKey(command: ReceiptCommand): string {
387
387
  command.kind,
388
388
  command.input.runId,
389
389
  command.input.runAttempt ?? null,
390
- command.input.leaseId,
391
390
  ]);
392
391
  case 'acquire_execution_lock':
393
392
  case 'release_execution_lock':
@@ -491,11 +490,15 @@ async function sendReceiptCommands(input: {
491
490
  ReceiptCommand,
492
491
  { kind: 'heartbeat' }
493
492
  >[];
493
+ const leaseIds = commands.map((command) => command.input.leaseId);
494
+ const sharedLeaseId = leaseIds.every((leaseId) => leaseId === leaseIds[0])
495
+ ? leaseIds[0]
496
+ : undefined;
494
497
  return await heartbeatRuntimeStepReceiptsViaAppRuntime(input.context, {
495
498
  playName: input.playName,
496
499
  runId: first.input.runId,
497
500
  runAttempt: first.input.runAttempt,
498
- leaseId: first.input.leaseId,
501
+ ...(sharedLeaseId ? { leaseId: sharedLeaseId } : { leaseIds }),
499
502
  keys: commands.map((command) => command.input.key),
500
503
  });
501
504
  }
@@ -1,28 +1,36 @@
1
+ import type {
2
+ PlaySecretAuth,
3
+ PlaySecretAwareRequestInit,
4
+ PlaySecretHandle,
5
+ } from '../plays/authoring-contract';
6
+
1
7
  const SECRET_HANDLE_BRAND = Symbol.for('deepline.secret.handle');
2
8
  const SECRET_AUTH_BRAND = Symbol.for('deepline.secret.auth');
3
9
  const SECRET_HANDLE_MARKER_RE = /\[secret:[A-Z0-9_ -]+\]/i;
4
10
 
5
- export type SecretHandle = {
11
+ export type SecretHandle = PlaySecretHandle & {
6
12
  readonly [SECRET_HANDLE_BRAND]: true;
7
13
  readonly name: string;
8
14
  toString(): string;
9
15
  toJSON(): never;
10
16
  };
11
17
 
12
- export type SecretAuth =
13
- | {
14
- readonly [SECRET_AUTH_BRAND]: true;
15
- readonly kind: 'bearer';
16
- readonly secret: SecretHandle;
17
- }
18
- | {
19
- readonly [SECRET_AUTH_BRAND]: true;
20
- readonly kind: 'header';
21
- readonly header: string;
22
- readonly secret: SecretHandle;
23
- };
18
+ export type SecretAuth = PlaySecretAuth &
19
+ (
20
+ | {
21
+ readonly [SECRET_AUTH_BRAND]: true;
22
+ readonly kind: 'bearer';
23
+ readonly secret: SecretHandle;
24
+ }
25
+ | {
26
+ readonly [SECRET_AUTH_BRAND]: true;
27
+ readonly kind: 'header';
28
+ readonly header: string;
29
+ readonly secret: SecretHandle;
30
+ }
31
+ );
24
32
 
25
- export type SecretAwareRequestInit = RequestInit & {
33
+ export type SecretAwareRequestInit = PlaySecretAwareRequestInit & {
26
34
  auth?: SecretAuth;
27
35
  };
28
36
 
@@ -70,7 +78,7 @@ export function createSecretHandle(name: string): SecretHandle {
70
78
  `Secret ${name} cannot be serialized. Use an approved ctx.secrets helper.`,
71
79
  );
72
80
  },
73
- };
81
+ } as unknown as SecretHandle;
74
82
  }
75
83
 
76
84
  export function createBearerSecretAuth(secret: SecretHandle): SecretAuth {
@@ -1,4 +1,5 @@
1
1
  import type { ToolExecutionErrorSchemaVersion } from '../tool-execution-error';
2
+ import type { PlayAuthoringContractEdition } from './authoring-contract';
2
3
 
3
4
  export type PlayPackageImport = {
4
5
  name: string;
@@ -25,6 +26,8 @@ export type PlayArtifactCompatibility = {
25
26
  runtimeBackend?: string | null;
26
27
  /** Missing preserves the legacy schema used before this field existed. */
27
28
  toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
29
+ /** Missing preserves edition 1 for artifacts created before authoring contracts were pinned. */
30
+ authoringContractEdition?: PlayAuthoringContractEdition;
28
31
  };
29
32
 
30
33
  /** The only executable Play artifact contract. */