deepline 0.2.13 → 0.2.15

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 (36) hide show
  1. package/dist/bundling-sources/sdk/src/index.ts +3 -0
  2. package/dist/bundling-sources/sdk/src/play.ts +150 -691
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +7 -1
  5. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +249 -51
  6. package/dist/bundling-sources/shared_libs/play-runtime/csv-rename.ts +10 -6
  7. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +32 -51
  8. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +11 -22
  9. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-policy.ts +34 -0
  10. package/dist/bundling-sources/shared_libs/play-runtime/play-call-execution.ts +2 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-projection-contract.ts +95 -0
  12. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +11 -6
  13. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +38 -9
  14. package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +23 -15
  15. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +3 -0
  16. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +2222 -0
  17. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +3 -2
  18. package/dist/bundling-sources/shared_libs/plays/compiler-manifest.ts +2 -0
  19. package/dist/bundling-sources/shared_libs/plays/contracts.ts +16 -0
  20. package/dist/bundling-sources/shared_libs/plays/input-contract-definition.ts +28 -0
  21. package/dist/bundling-sources/shared_libs/plays/input-contract.ts +3 -3
  22. package/dist/cli/index.js +5074 -829
  23. package/dist/cli/index.mjs +5019 -759
  24. package/dist/compiler-manifest-xFkbJX2B.d.mts +2517 -0
  25. package/dist/compiler-manifest-xFkbJX2B.d.ts +2517 -0
  26. package/dist/index.d.mts +36 -1011
  27. package/dist/index.d.ts +36 -1011
  28. package/dist/index.js +25 -7
  29. package/dist/index.mjs +25 -7
  30. package/dist/plays/bundle-play-file.d.mts +5 -8
  31. package/dist/plays/bundle-play-file.d.ts +5 -8
  32. package/dist/plays/bundle-play-file.mjs +3844 -3
  33. package/package.json +1 -1
  34. package/dist/bundling-sources/shared_libs/plays/source-metadata.ts +0 -240
  35. package/dist/tool-execution-error-4-rhemLQ.d.mts +0 -446
  36. package/dist/tool-execution-error-4-rhemLQ.d.ts +0 -446
@@ -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,
@@ -208,14 +220,9 @@ export interface HeartbeatRuntimeStepReceiptsInput {
208
220
  leaseIds?: string[];
209
221
  }
210
222
 
211
- export interface CsvOptions {
212
- description?: string;
213
- columns?: Record<string, string | readonly string[]>;
214
- rename?: Record<string, string | readonly string[]>;
215
- required?: readonly string[];
216
- }
223
+ export type CsvOptions = PlayAuthoringCsvOptions;
217
224
 
218
- export interface DatasetOptions<TItem = Record<string, unknown>> {
225
+ export interface RuntimeDatasetOptions<TItem = Record<string, unknown>> {
219
226
  description?: string;
220
227
  /**
221
228
  * Optional relative cache window for intentional reruns.
@@ -270,58 +277,30 @@ export interface DatasetOptions<TItem = Record<string, unknown>> {
270
277
  mode?: 'upsert' | 'net_new';
271
278
  }
272
279
 
273
- export type DatasetDefinitionOptions<TItem = Record<string, unknown>> = Omit<
274
- DatasetOptions<TItem>,
275
- 'description'
276
- >;
280
+ export type RuntimeDatasetDefinitionOptions<TItem = Record<string, unknown>> =
281
+ Omit<RuntimeDatasetOptions<TItem>, 'description'>;
277
282
 
278
- export type DatasetRunOptions<TItem = Record<string, unknown>> = Pick<
279
- DatasetOptions<TItem>,
283
+ export type RuntimeDatasetRunOptions<TItem = Record<string, unknown>> = Pick<
284
+ RuntimeDatasetOptions<TItem>,
280
285
  'description' | 'key' | 'onRowError' | 'mode'
281
286
  >;
282
287
 
283
- export interface ToolCallOptions {
284
- description?: string;
285
- force?: boolean;
286
- staleAfterSeconds?: number;
287
- timeoutMs?: number;
288
- receiptWaitMs?: number;
289
- }
288
+ export type ToolCallOptions = PlayToolCallOptions;
289
+ export type ToolExecutionRequest = PlayToolExecutionRequest;
290
290
 
291
- export interface ToolExecutionRequest {
292
- id: string;
293
- tool: string;
294
- input: Record<string, unknown>;
295
- description?: string;
296
- force?: boolean;
297
- staleAfterSeconds?: number;
298
- timeoutMs?: number;
299
- receiptWaitMs?: number;
300
- }
301
-
302
- export interface PlayCallOptions {
303
- description?: string;
304
- /**
305
- * `child-workflow` is accepted only so the checker/runtime can emit the
306
- * canonical CTX_RUN_PLAY_INLINE_ONLY migration diagnostic. It never starts a
307
- * child workflow.
308
- */
291
+ export type PlayCallOptions = Omit<
292
+ PlayAuthoringCallOptions,
293
+ 'execution' | 'timeoutMs'
294
+ > & {
295
+ /** Legacy invalid spelling retained only for the stable migration error. */
309
296
  execution?: PlayCallExecution | 'child-workflow';
310
- /**
311
- * Parsed so source preflight and an untyped runtime call can return the
312
- * canonical CTX_RUN_PLAY_INLINE_ONLY migration error. It is never honored.
313
- */
297
+ /** Legacy invalid option retained only for the stable migration error. */
314
298
  timeoutMs?: number;
315
- }
299
+ };
316
300
 
317
- export interface StepOptions {
318
- semanticKey?: string;
319
- staleAfterSeconds?: number;
320
- }
301
+ export type RuntimeStepOptions = PlayAuthoringRuntimeStepOptions;
321
302
 
322
- export interface FetchOptions {
323
- staleAfterSeconds?: number;
324
- }
303
+ export type FetchOptions = PlayAuthoringFetchOptions;
325
304
 
326
305
  export interface ResolvedPlayExecution {
327
306
  playId: string;
@@ -502,6 +481,8 @@ export type IntegrationEventWaitHandler = {
502
481
  export interface ContextOptions {
503
482
  /** Immutable logical and physical execution identity for this context. */
504
483
  executionScope?: RunExecutionScope;
484
+ /** Authoring semantics pinned by the immutable artifact. */
485
+ authoringContractEdition?: PlayAuthoringContractEdition;
505
486
  /** Error shape pinned by the immutable play artifact; missing preserves legacy schema 0. */
506
487
  toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
507
488
  /** Short-lived HMAC-signed internal token for tool callbacks. Required for cloud execution. */
@@ -589,7 +570,7 @@ export interface ContextOptions {
589
570
  staticPipeline?: PlayStaticPipeline | null;
590
571
  forceRefresh?: boolean;
591
572
  inputOffset?: number;
592
- mode?: DatasetRunOptions['mode'];
573
+ mode?: RuntimeDatasetRunOptions['mode'];
593
574
  },
594
575
  ) => Promise<MapStartResult>;
595
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
+ }
@@ -5844,17 +5844,21 @@ export async function heartbeatRuntimeWorkReceipts(
5844
5844
  JOIN unnest($3::text[]) WITH ORDINALITY AS lease_values(lease_id, ord)
5845
5845
  ON lease_values.ord = key_values.ord
5846
5846
  ),
5847
+ unique_inputs AS (
5848
+ SELECT DISTINCT key_hex, lease_id
5849
+ FROM input_keys
5850
+ ),
5847
5851
  renewed AS (
5848
5852
  UPDATE ${workReceiptTable(session)} AS target
5849
5853
  SET lease_expires_at = now() + ($4::double precision * interval '1 millisecond'),
5850
5854
  updated_at = now()
5851
- FROM input_keys
5852
- WHERE target.k = decode(input_keys.key_hex, 'hex')
5855
+ FROM unique_inputs
5856
+ WHERE target.k = decode(unique_inputs.key_hex, 'hex')
5853
5857
  AND ${workReceiptHeartbeatPredicateSql({
5854
5858
  receiptTable: 'target',
5855
5859
  ownerRunIdSql: '$2::text',
5856
5860
  ownerRunAttemptSql: '$5',
5857
- leaseIdSql: 'input_keys.lease_id',
5861
+ leaseIdSql: 'unique_inputs.lease_id',
5858
5862
  })}
5859
5863
  RETURNING target.k,
5860
5864
  target.status,
@@ -5867,8 +5871,7 @@ export async function heartbeatRuntimeWorkReceipts(
5867
5871
  target.lease_owner_run_id,
5868
5872
  target.lease_owner_attempt,
5869
5873
  target.lease_expires_at,
5870
- target.updated_at,
5871
- input_keys.ord
5874
+ target.updated_at
5872
5875
  ),
5873
5876
  returned AS (
5874
5877
  SELECT renewed.k,
@@ -5885,7 +5888,9 @@ export async function heartbeatRuntimeWorkReceipts(
5885
5888
  renewed.updated_at,
5886
5889
  input_keys.ord
5887
5890
  FROM input_keys
5888
- LEFT JOIN renewed ON renewed.ord = input_keys.ord
5891
+ LEFT JOIN renewed
5892
+ ON renewed.k = decode(input_keys.key_hex, 'hex')
5893
+ AND renewed.lease_id = input_keys.lease_id
5889
5894
  )
5890
5895
  SELECT convert_from(returned.k, 'UTF8') AS k,
5891
5896
  returned.status,
@@ -25,7 +25,10 @@ import {
25
25
  skipRuntimeStepReceiptViaAppRuntime,
26
26
  type WorkerRuntimeApiContext,
27
27
  } from './app-runtime-api';
28
- import { RuntimeReceiptWriter } from './runtime-receipt-writer';
28
+ import {
29
+ RuntimeReceiptWriter,
30
+ RuntimeReceiptWriterResultCountError,
31
+ } from './runtime-receipt-writer';
29
32
 
30
33
  type ReceiptOutput =
31
34
  | RuntimeStepReceipt
@@ -490,17 +493,43 @@ async function sendReceiptCommands(input: {
490
493
  ReceiptCommand,
491
494
  { kind: 'heartbeat' }
492
495
  >[];
493
- const leaseIds = commands.map((command) => command.input.leaseId);
496
+ const uniqueCommands: (typeof commands)[number][] = [];
497
+ const uniqueIndexByIdentity = new Map<string, number>();
498
+ const originalToUniqueIndex = commands.map((command) => {
499
+ const identity = JSON.stringify([
500
+ command.input.key,
501
+ command.input.leaseId,
502
+ ]);
503
+ const existingIndex = uniqueIndexByIdentity.get(identity);
504
+ if (existingIndex !== undefined) return existingIndex;
505
+ const uniqueIndex = uniqueCommands.length;
506
+ uniqueCommands.push(command);
507
+ uniqueIndexByIdentity.set(identity, uniqueIndex);
508
+ return uniqueIndex;
509
+ });
510
+ const leaseIds = uniqueCommands.map((command) => command.input.leaseId);
494
511
  const sharedLeaseId = leaseIds.every((leaseId) => leaseId === leaseIds[0])
495
512
  ? leaseIds[0]
496
513
  : undefined;
497
- return await heartbeatRuntimeStepReceiptsViaAppRuntime(input.context, {
498
- playName: input.playName,
499
- runId: first.input.runId,
500
- runAttempt: first.input.runAttempt,
501
- ...(sharedLeaseId ? { leaseId: sharedLeaseId } : { leaseIds }),
502
- keys: commands.map((command) => command.input.key),
503
- });
514
+ const uniqueResults = await heartbeatRuntimeStepReceiptsViaAppRuntime(
515
+ input.context,
516
+ {
517
+ playName: input.playName,
518
+ runId: first.input.runId,
519
+ runAttempt: first.input.runAttempt,
520
+ ...(sharedLeaseId ? { leaseId: sharedLeaseId } : { leaseIds }),
521
+ keys: uniqueCommands.map((command) => command.input.key),
522
+ },
523
+ );
524
+ if (uniqueResults.length !== uniqueCommands.length) {
525
+ throw new RuntimeReceiptWriterResultCountError(
526
+ uniqueCommands.length,
527
+ uniqueResults.length,
528
+ );
529
+ }
530
+ return originalToUniqueIndex.map(
531
+ (uniqueIndex) => uniqueResults[uniqueIndex]!,
532
+ );
504
533
  }
505
534
  case 'acquire_execution_lock':
506
535
  return [
@@ -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. */