deepline 0.2.13 → 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 (34) 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/secret-capability.ts +23 -15
  13. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +3 -0
  14. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +2222 -0
  15. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +3 -2
  16. package/dist/bundling-sources/shared_libs/plays/compiler-manifest.ts +2 -0
  17. package/dist/bundling-sources/shared_libs/plays/contracts.ts +16 -0
  18. package/dist/bundling-sources/shared_libs/plays/input-contract-definition.ts +28 -0
  19. package/dist/bundling-sources/shared_libs/plays/input-contract.ts +3 -3
  20. package/dist/cli/index.js +5074 -829
  21. package/dist/cli/index.mjs +5019 -759
  22. package/dist/compiler-manifest-xFkbJX2B.d.mts +2517 -0
  23. package/dist/compiler-manifest-xFkbJX2B.d.ts +2517 -0
  24. package/dist/index.d.mts +36 -1011
  25. package/dist/index.d.ts +36 -1011
  26. package/dist/index.js +25 -7
  27. package/dist/index.mjs +25 -7
  28. package/dist/plays/bundle-play-file.d.mts +5 -8
  29. package/dist/plays/bundle-play-file.d.ts +5 -8
  30. package/dist/plays/bundle-play-file.mjs +3844 -3
  31. package/package.json +1 -1
  32. package/dist/bundling-sources/shared_libs/plays/source-metadata.ts +0 -240
  33. package/dist/tool-execution-error-4-rhemLQ.d.mts +0 -446
  34. package/dist/tool-execution-error-4-rhemLQ.d.ts +0 -446
@@ -0,0 +1,2222 @@
1
+ import { Type, type Static, type TSchema } from '@sinclair/typebox';
2
+ import { Value } from '@sinclair/typebox/value';
3
+ import type { PreviousCell } from '../play-runtime/cell-staleness';
4
+ import type { PlaySandboxRuntimeLimits } from '../play-runtime/sandbox-runtime-limits';
5
+ import type { ToolExecuteResult } from '../play-runtime/tool-result-types';
6
+ import type { ToolExecutionErrorSchemaVersion } from '../tool-execution-error';
7
+ import type { PlayDataset, PlayDatasetInput, PlayDatasetRow } from './dataset';
8
+
9
+ export const LEGACY_PLAY_AUTHORING_CONTRACT_EDITION = 1 as const;
10
+ export const PLAY_AUTHORING_CONTRACT_EDITION = 3 as const;
11
+ export const PLAY_AUTHORING_INPUT_SCHEMA_SNAPSHOT_EDITION = 3 as const;
12
+ export const SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS = [1, 2, 3] as const;
13
+
14
+ export type PlayAuthoringContractEdition =
15
+ (typeof SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS)[number];
16
+
17
+ export const PLAY_AUTHORING_CONTRACT_CHANGELOG = [
18
+ {
19
+ edition: 1,
20
+ changed:
21
+ 'Historical extraction semantics. Invalid or unresolved optional authoring fields may normalize to absence.',
22
+ compatibilityOwner: 'Plays Runtime',
23
+ newWritesEnd: '2026-11-03',
24
+ readerRemoval:
25
+ 'After every retained edition 1 artifact has a materialized admitted snapshot.',
26
+ },
27
+ {
28
+ edition: 2,
29
+ changed:
30
+ 'Pins admitted authoring snapshots and rejects ambiguous billing, secret, webhook, fetch, timeout, receipt-wait, and freshness contracts.',
31
+ compatibilityOwner: 'Plays Runtime',
32
+ newWritesEnd: '2026-08-03',
33
+ readerRemoval:
34
+ 'After every retained edition 2 artifact has an admitted input schema or has been republished.',
35
+ },
36
+ {
37
+ edition: 3,
38
+ changed:
39
+ 'Materializes the declared input schema in the admitted snapshot so launch never reparses current source.',
40
+ compatibilityOwner: 'Plays Runtime',
41
+ newWritesEnd: null,
42
+ readerRemoval: null,
43
+ },
44
+ ] as const;
45
+
46
+ export const PLAY_AUTHORING_CONTRACT_ISSUE_CODES = [
47
+ 'sql_listener_unknown_tool',
48
+ 'sql_listener_unknown_stream',
49
+ 'sql_listener_where_unknown_field',
50
+ 'sql_listener_where_invalid_operator',
51
+ 'sql_listener_binding_shape',
52
+ 'invalid_cron_expression',
53
+ 'invalid_cron_timezone',
54
+ 'unknown_type_member',
55
+ 'untyped_monitor_event',
56
+ 'play_authoring_billing_limit_invalid',
57
+ 'play_authoring_billing_limit_unresolved',
58
+ 'play_authoring_webhook_hmac_invalid',
59
+ 'play_authoring_secret_invalid',
60
+ 'play_authoring_cron_timezone_invalid',
61
+ 'play_authoring_tool_request_invalid',
62
+ 'play_authoring_durable_policy_invalid',
63
+ 'play_authoring_csv_option_invalid',
64
+ 'play_authoring_dataset_option_invalid',
65
+ 'play_authoring_step_option_invalid',
66
+ 'play_authoring_run_play_option_invalid',
67
+ 'play_authoring_dynamic_identity_unvalidated',
68
+ 'play_authoring_fetch_secret_requires_tls',
69
+ 'play_authoring_fetch_idempotency_required',
70
+ 'play_authoring_binding_invalid',
71
+ 'play_authoring_input_schema_unresolved',
72
+ ] as const;
73
+
74
+ export type PlayAuthoringContractIssueCode =
75
+ (typeof PLAY_AUTHORING_CONTRACT_ISSUE_CODES)[number];
76
+
77
+ export type PlayAuthoringContractIssue = {
78
+ code: PlayAuthoringContractIssueCode;
79
+ severity: 'error' | 'warning';
80
+ path: string;
81
+ message: string;
82
+ hint?: string;
83
+ };
84
+
85
+ export type PlaySqlListenerOperation = 'INSERT' | 'UPDATE' | 'DELETE';
86
+ export const PLAY_SQL_LISTENER_WHERE_OPERATORS = [
87
+ 'eq',
88
+ 'neq',
89
+ 'in',
90
+ 'notIn',
91
+ 'isNull',
92
+ 'isNotNull',
93
+ 'ilike',
94
+ ] as const;
95
+ export const PLAY_SQL_LISTENER_ID_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
96
+ export const PLAY_SQL_LISTENER_TOOL_PATTERN =
97
+ /^[a-zA-Z][a-zA-Z0-9_-]*\.[a-zA-Z][a-zA-Z0-9_-]*$/;
98
+ export type PlaySqlListenerFilterScalar = string | number | boolean | null;
99
+ export type PlaySqlListenerFilterOperator = {
100
+ eq?: PlaySqlListenerFilterScalar;
101
+ neq?: PlaySqlListenerFilterScalar;
102
+ in?: PlaySqlListenerFilterScalar[];
103
+ notIn?: PlaySqlListenerFilterScalar[];
104
+ isNull?: true;
105
+ isNotNull?: true;
106
+ ilike?: string;
107
+ };
108
+ export type PlaySqlListenerWhere = {
109
+ before?: Record<string, PlaySqlListenerFilterOperator>;
110
+ after?: Record<string, PlaySqlListenerFilterOperator>;
111
+ };
112
+
113
+ const PLAY_SQL_LISTENER_FIELD_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
114
+ const PLAY_SQL_LISTENER_WHERE_OPERATOR_SET = new Set<string>(
115
+ PLAY_SQL_LISTENER_WHERE_OPERATORS,
116
+ );
117
+
118
+ function isPlaySqlListenerFilterScalar(
119
+ value: unknown,
120
+ ): value is PlaySqlListenerFilterScalar {
121
+ return (
122
+ value === null ||
123
+ typeof value === 'string' ||
124
+ typeof value === 'number' ||
125
+ typeof value === 'boolean'
126
+ );
127
+ }
128
+
129
+ /** Normalize only an already-admitted filter snapshot at the contract seam. */
130
+ export function normalizeAdmittedSqlListenerWhere(
131
+ where: unknown,
132
+ ): PlaySqlListenerWhere {
133
+ if (!isPlainRecord(where)) return {};
134
+ const normalized: PlaySqlListenerWhere = {};
135
+ for (const scope of ['before', 'after'] as const) {
136
+ const scopeValue = where[scope];
137
+ if (!isPlainRecord(scopeValue)) continue;
138
+ const normalizedScope: Record<string, PlaySqlListenerFilterOperator> = {};
139
+ for (const [field, operators] of Object.entries(scopeValue)) {
140
+ if (
141
+ !PLAY_SQL_LISTENER_FIELD_PATTERN.test(field) ||
142
+ !isPlainRecord(operators)
143
+ ) {
144
+ continue;
145
+ }
146
+ const normalizedOperators: PlaySqlListenerFilterOperator = {};
147
+ for (const [operator, value] of Object.entries(operators)) {
148
+ if (!PLAY_SQL_LISTENER_WHERE_OPERATOR_SET.has(operator)) continue;
149
+ if (
150
+ (operator === 'in' || operator === 'notIn') &&
151
+ Array.isArray(value) &&
152
+ value.length > 0 &&
153
+ value.every(isPlaySqlListenerFilterScalar)
154
+ ) {
155
+ normalizedOperators[operator] = value;
156
+ } else if (
157
+ (operator === 'isNull' || operator === 'isNotNull') &&
158
+ value === true
159
+ ) {
160
+ normalizedOperators[operator] = true;
161
+ } else if (operator === 'ilike' && typeof value === 'string') {
162
+ normalizedOperators.ilike = value;
163
+ } else if (
164
+ (operator === 'eq' || operator === 'neq') &&
165
+ isPlaySqlListenerFilterScalar(value)
166
+ ) {
167
+ normalizedOperators[operator] = value;
168
+ }
169
+ }
170
+ if (Object.keys(normalizedOperators).length > 0) {
171
+ normalizedScope[field] = normalizedOperators;
172
+ }
173
+ }
174
+ if (Object.keys(normalizedScope).length > 0) {
175
+ normalized[scope] = normalizedScope;
176
+ }
177
+ }
178
+ return normalized;
179
+ }
180
+ export type PlaySqlListenerDeclaration = {
181
+ id: string;
182
+ tool: string;
183
+ stream: string;
184
+ operations?: PlaySqlListenerOperation[];
185
+ where?: PlaySqlListenerWhere;
186
+ };
187
+ export type PlaySqlListenerEvent<T extends object = Record<string, unknown>> = {
188
+ tool: string;
189
+ stream: string;
190
+ operation: PlaySqlListenerOperation;
191
+ before: T | null;
192
+ after: T | null;
193
+ changedAt: string;
194
+ metadata: {
195
+ outboxId: string;
196
+ listenerId: string;
197
+ table: string;
198
+ };
199
+ };
200
+ export type PlayTriggerSqlListenerSummary = {
201
+ id: string;
202
+ tool?: string;
203
+ stream?: string;
204
+ operations: string[];
205
+ where?: PlaySqlListenerWhere;
206
+ };
207
+ export type PlayTriggersSummary = {
208
+ sqlListeners?: PlayTriggerSqlListenerSummary[];
209
+ cron?: { schedule: string; timezone?: string };
210
+ webhook?: true;
211
+ };
212
+
213
+ /** Derive the recognized trigger projection from an already-admitted snapshot. */
214
+ export function derivePlayTriggersSummary(
215
+ bindings: PlayAuthoringAstBindings | null | undefined,
216
+ ): PlayTriggersSummary | null {
217
+ if (!bindings) return null;
218
+ const summary: PlayTriggersSummary = {};
219
+ if (bindings.sqlListeners && bindings.sqlListeners.length > 0) {
220
+ summary.sqlListeners = bindings.sqlListeners.map((listener) => ({
221
+ id: listener.id,
222
+ ...(listener.tool ? { tool: listener.tool } : {}),
223
+ ...(listener.stream ? { stream: listener.stream } : {}),
224
+ operations: listener.operations,
225
+ ...(isPlainRecord(listener.where)
226
+ ? { where: listener.where as PlaySqlListenerWhere }
227
+ : {}),
228
+ }));
229
+ }
230
+ if (bindings.cron?.schedule) {
231
+ summary.cron = bindings.cron.timezone
232
+ ? { schedule: bindings.cron.schedule, timezone: bindings.cron.timezone }
233
+ : { schedule: bindings.cron.schedule };
234
+ }
235
+ if (bindings.webhook) summary.webhook = true;
236
+ return summary.sqlListeners || summary.cron || summary.webhook
237
+ ? summary
238
+ : null;
239
+ }
240
+
241
+ function isPlainRecord(value: unknown): value is Record<string, unknown> {
242
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
243
+ }
244
+ /** Internal AST Adapter shape. Invalid legacy fields exist only until admission rejects them. */
245
+ export type PlayAuthoringAstSqlListenerDeclaration = {
246
+ id: string;
247
+ tool?: string;
248
+ stream?: string;
249
+ where?: unknown;
250
+ monitor?: string;
251
+ output?: string;
252
+ table?: `${string}.${string}` | string;
253
+ operations: string[];
254
+ };
255
+ export type PlayAuthoringAstBindings = {
256
+ webhook?: {
257
+ hmac?: {
258
+ algorithm?: 'sha256';
259
+ header?: string;
260
+ secretEnv: string;
261
+ };
262
+ };
263
+ cron?: { schedule: string; timezone?: string };
264
+ sqlListeners?: PlayAuthoringAstSqlListenerDeclaration[];
265
+ invalidSqlListenerSingular?: boolean;
266
+ invalidSqlListenerShape?: boolean;
267
+ secrets?: string[];
268
+ };
269
+
270
+ /** The one public type for options accepted by definePlay. */
271
+ export type PlayAuthoringBindings = {
272
+ description?: string;
273
+ compatibility?: {
274
+ toolErrorSchemaVersion: ToolExecutionErrorSchemaVersion;
275
+ };
276
+ inline?: boolean;
277
+ billing?: {
278
+ maxCreditsPerRun?: number;
279
+ };
280
+ runtime?: {
281
+ timeout?: string;
282
+ size?: 'standard';
283
+ };
284
+ webhook?: {
285
+ hmac?: {
286
+ algorithm?: 'sha256';
287
+ header?: string;
288
+ secretEnv: string;
289
+ };
290
+ };
291
+ cron?: {
292
+ schedule: string;
293
+ timezone?: string;
294
+ };
295
+ sqlListeners?: PlaySqlListenerDeclaration[];
296
+ secrets?: readonly string[];
297
+ };
298
+
299
+ /** The one public type for durable managed-tool calls. */
300
+ export type PlayToolExecutionRequest = {
301
+ id: string;
302
+ tool: string;
303
+ input: Record<string, unknown>;
304
+ description?: string;
305
+ force?: boolean;
306
+ staleAfterSeconds?: DurableCallStaleAfterSeconds;
307
+ timeoutMs?: PlayRuntimeTimeoutMs;
308
+ receiptWaitMs?: PlayReceiptWaitMs;
309
+ };
310
+ export type PlayToolCallOptions = Omit<
311
+ PlayToolExecutionRequest,
312
+ 'id' | 'tool' | 'input'
313
+ >;
314
+
315
+ /** @deprecated Pass a SQL string directly to ctx.customerDb.query. */
316
+ export type PlaySqlQuery = {
317
+ readonly kind: 'sql.query';
318
+ readonly text: string;
319
+ readonly values: readonly unknown[];
320
+ };
321
+
322
+ declare const PLAY_SECRET_HANDLE_BRAND: unique symbol;
323
+ export type PlaySecretHandle = {
324
+ readonly [PLAY_SECRET_HANDLE_BRAND]: never;
325
+ readonly name: string;
326
+ toString(): string;
327
+ toJSON(): never;
328
+ };
329
+ export type PlaySecretAuth = {
330
+ readonly kind: 'bearer' | 'header';
331
+ readonly secret: PlaySecretHandle;
332
+ readonly header?: string;
333
+ };
334
+ export type PlaySecretAwareRequestInit = Omit<RequestInit, 'headers'> & {
335
+ headers?: HeadersInit;
336
+ auth?: PlaySecretAuth;
337
+ };
338
+ export type PlayLooseObject = { [key: string]: PlayLooseObject };
339
+
340
+ /** The one public return-object constraint for authored Plays. */
341
+ export type PlayReturnObject = Record<string, unknown> & {
342
+ readonly _metadata?: never;
343
+ };
344
+
345
+ /** The one public input-contract carrier for object-form Play definitions. */
346
+ export type PlayAuthoringInputContract<TInput> = {
347
+ readonly schema: Record<string, unknown>;
348
+ readonly __inputType?: TInput;
349
+ };
350
+
351
+ /** Shared object-form `definePlay(config)` contract. */
352
+ export type PlayAuthoringDefineConfig<
353
+ TInput,
354
+ TOutput extends PlayReturnObject,
355
+ TContext,
356
+ > = {
357
+ id: string;
358
+ description?: string;
359
+ input: PlayAuthoringInputContract<TInput>;
360
+ run: (ctx: TContext, input: TInput) => Promise<TOutput>;
361
+ bindings?: PlayAuthoringBindings;
362
+ billing?: PlayAuthoringBindings['billing'];
363
+ runtime?: PlayAuthoringBindings['runtime'];
364
+ compatibility?: PlayAuthoringBindings['compatibility'];
365
+ };
366
+
367
+ /** Shared callable-plus-handle shape returned by `definePlay`. */
368
+ export type PlayAuthoringDefinedPlay<
369
+ TInput,
370
+ TOutput extends PlayReturnObject,
371
+ TContext,
372
+ THandle extends object,
373
+ > = ((ctx: TContext, input: TInput) => Promise<TOutput>) &
374
+ THandle & {
375
+ readonly bindings?: PlayAuthoringBindings;
376
+ readonly runtime?: PlayAuthoringBindings['runtime'];
377
+ readonly compatibility?: PlayAuthoringBindings['compatibility'];
378
+ readonly playName: string;
379
+ };
380
+
381
+ /** Canonical resolver shape for a customer-authored durable step. */
382
+ export type PlayAuthoringStepResolver<Row, Value, TContext> = (
383
+ row: Row,
384
+ ctx: TContext,
385
+ index: number,
386
+ previousCell?: PreviousCell<Value>,
387
+ ) => Value | Promise<Value>;
388
+
389
+ export type PlayAuthoringDatasetColumnRunInput<Row, Value, TContext> = {
390
+ /** Current row, including previously computed columns. */
391
+ readonly row: Row;
392
+ /** Runtime context for tool, Play, fetch, and log calls. */
393
+ readonly ctx: TContext;
394
+ /** Zero-based row index for this dataset run. */
395
+ readonly index: number;
396
+ /** Prior stored cell value and freshness metadata when this cell reruns. */
397
+ readonly previousCell?: PreviousCell<Value>;
398
+ };
399
+
400
+ export type PlayAuthoringDatasetColumnDefinition<Row, Value, TContext> = {
401
+ /** Compute one cell value. Receives the previous stored value when rerunning. */
402
+ readonly run: (
403
+ input: PlayAuthoringDatasetColumnRunInput<Row, Value, TContext>,
404
+ ) => Value | Promise<Value>;
405
+ /** Optional row-level gate. Skipped rows produce `null` for this column. */
406
+ readonly runIf?: (row: Row, index: number) => boolean | Promise<boolean>;
407
+ };
408
+
409
+ export type PlayAuthoringConditionalStepResolver<
410
+ Row,
411
+ Value,
412
+ TContext,
413
+ Else = null,
414
+ > = {
415
+ readonly kind: 'conditional';
416
+ readonly when: (row: Row, index: number) => boolean | Promise<boolean>;
417
+ readonly run: PlayAuthoringStepResolver<Row, Value, TContext>;
418
+ readonly elseValue: Else;
419
+ else<ValueElse>(
420
+ value: ValueElse,
421
+ ): PlayAuthoringConditionalStepResolver<Row, Value, TContext, ValueElse>;
422
+ };
423
+
424
+ export type PlayAuthoringStepOptions<Row, Value = unknown> = {
425
+ /** Optional row-level gate. Skipped rows produce `null` for this column. */
426
+ readonly runIf?: (row: Row, index: number) => boolean | Promise<boolean>;
427
+ /** Legacy dataset-column flag. Prefer freshness on the reusable call. */
428
+ readonly recompute?: boolean;
429
+ /** Legacy error-recompute flag accepted for older authored Plays. */
430
+ readonly recomputeOnError?: boolean;
431
+ /** Legacy cell staleness metadata accepted for older authored Plays. */
432
+ readonly staleAfterSeconds?: number;
433
+ };
434
+
435
+ export type PlayAuthoringStepProgram<
436
+ Input,
437
+ Output,
438
+ TContext,
439
+ Return = Output,
440
+ > = {
441
+ readonly kind: 'steps';
442
+ readonly steps: readonly PlayAuthoringStepProgramStep<TContext>[];
443
+ readonly returnResolver?: PlayAuthoringStepResolver<Output, Return, TContext>;
444
+ readonly __inputType?: (input: Input) => void;
445
+ step<Name extends string, Value>(
446
+ name: Name,
447
+ resolver:
448
+ | PlayAuthoringStepResolver<Output, Value, TContext>
449
+ | PlayAuthoringConditionalStepResolver<Output, Value, TContext>
450
+ | PlayAuthoringStepProgramResolver<Output, Value, TContext>,
451
+ ): PlayAuthoringStepProgram<
452
+ Input,
453
+ Output & Record<Name, Value>,
454
+ TContext,
455
+ Return
456
+ >;
457
+ step<Name extends string, Value>(
458
+ name: Name,
459
+ resolver:
460
+ | PlayAuthoringStepResolver<Output, Value, TContext>
461
+ | PlayAuthoringStepProgramResolver<Output, Value, TContext>,
462
+ options: PlayAuthoringStepOptions<Output, Value>,
463
+ ): PlayAuthoringStepProgram<
464
+ Input,
465
+ Output & Record<Name, Value | null>,
466
+ TContext,
467
+ Return
468
+ >;
469
+ return<Value>(
470
+ resolver: PlayAuthoringStepResolver<Output, Value, TContext>,
471
+ ): PlayAuthoringStepProgram<Input, Output, TContext, Value>;
472
+ };
473
+
474
+ export type PlayAuthoringStepProgramResolver<Input, Return, TContext> = {
475
+ readonly kind: 'steps';
476
+ readonly steps: readonly PlayAuthoringStepProgramStep<TContext>[];
477
+ readonly returnResolver?: PlayAuthoringStepResolver<never, Return, TContext>;
478
+ readonly __inputType?: (input: Input) => void;
479
+ };
480
+
481
+ export type PlayAuthoringRunnableStepProgram<Return, TContext> = Pick<
482
+ PlayAuthoringStepProgram<unknown, never, TContext, Return>,
483
+ 'kind' | 'steps' | 'returnResolver'
484
+ >;
485
+
486
+ export type PlayAuthoringStepProgramStep<TContext> = {
487
+ readonly name: string;
488
+ readonly recompute?: boolean;
489
+ readonly recomputeOnError?: boolean;
490
+ readonly staleAfterSeconds?: number;
491
+ readonly resolver:
492
+ | PlayAuthoringStepResolver<Record<string, unknown>, unknown, TContext>
493
+ | PlayAuthoringConditionalStepResolver<
494
+ Record<string, unknown>,
495
+ unknown,
496
+ TContext
497
+ >
498
+ | PlayAuthoringStepProgramResolver<
499
+ Record<string, unknown>,
500
+ unknown,
501
+ TContext
502
+ >;
503
+ };
504
+
505
+ export type PlayAuthoringColumnResolver<Row, Value, TContext> =
506
+ | PlayAuthoringStepResolver<Row, Value, TContext>
507
+ | PlayAuthoringConditionalStepResolver<Row, Value, TContext>
508
+ | PlayAuthoringRunnableStepProgram<Value, TContext>;
509
+
510
+ export type PlayAuthoringStepProgramOutput<TProgram> =
511
+ TProgram extends PlayAuthoringStepProgram<
512
+ unknown,
513
+ infer Output,
514
+ unknown,
515
+ unknown
516
+ >
517
+ ? Output
518
+ : never;
519
+
520
+ export type PlayAuthoringDatasetRowKey<InputRow extends object> =
521
+ | (keyof InputRow & string)
522
+ | readonly (keyof InputRow & string)[]
523
+ | ((row: InputRow, index: number) => string | number | readonly unknown[]);
524
+
525
+ export type PlayAuthoringDatasetDefinitionOptions<InputRow extends object> = {
526
+ key?: PlayAuthoringDatasetRowKey<InputRow>;
527
+ };
528
+
529
+ export type PlayAuthoringDatasetRunOptions<InputRow extends object> = {
530
+ description?: string;
531
+ key?: PlayAuthoringDatasetRowKey<InputRow>;
532
+ onRowError?: 'isolate' | 'fail';
533
+ mode?: 'upsert' | 'net_new';
534
+ };
535
+
536
+ export const PLAY_AUTHORING_DATASET_RUN_OPTION_FIELDS = [
537
+ 'description',
538
+ 'key',
539
+ 'onRowError',
540
+ 'mode',
541
+ ] as const;
542
+
543
+ export type PlayAuthoringDatasetBuilder<
544
+ InputRow extends object,
545
+ OutputRow extends object,
546
+ TContext,
547
+ > = {
548
+ /** Define one output column for every row in this dataset. */
549
+ withColumn<Name extends string, Value>(
550
+ name: Name,
551
+ resolver: PlayAuthoringColumnResolver<OutputRow, Value, TContext>,
552
+ ): PlayAuthoringDatasetBuilder<
553
+ InputRow,
554
+ OutputRow & Record<Name, Value>,
555
+ TContext
556
+ >;
557
+ /** Define a nullable output column with object-form authoring and a row gate. */
558
+ withColumn<Name extends string, Value>(
559
+ name: Name,
560
+ definition: PlayAuthoringDatasetColumnDefinition<
561
+ OutputRow,
562
+ Value,
563
+ TContext
564
+ > & {
565
+ readonly runIf: (
566
+ row: OutputRow,
567
+ index: number,
568
+ ) => boolean | Promise<boolean>;
569
+ },
570
+ ): PlayAuthoringDatasetBuilder<
571
+ InputRow,
572
+ OutputRow & Record<Name, Value | null>,
573
+ TContext
574
+ >;
575
+ /** Define an output column with object-form authoring and typed previous-cell access. */
576
+ withColumn<Name extends string, Value>(
577
+ name: Name,
578
+ definition: PlayAuthoringDatasetColumnDefinition<
579
+ OutputRow,
580
+ Value,
581
+ TContext
582
+ >,
583
+ ): PlayAuthoringDatasetBuilder<
584
+ InputRow,
585
+ OutputRow & Record<Name, Value>,
586
+ TContext
587
+ >;
588
+ /** Define a nullable output column with a resolver and row-level options. */
589
+ withColumn<Name extends string, Value>(
590
+ name: Name,
591
+ resolver:
592
+ | PlayAuthoringStepResolver<OutputRow, Value, TContext>
593
+ | PlayAuthoringRunnableStepProgram<Value, TContext>,
594
+ options: PlayAuthoringStepOptions<OutputRow, Value>,
595
+ ): PlayAuthoringDatasetBuilder<
596
+ InputRow,
597
+ OutputRow & Record<Name, Value | null>,
598
+ TContext
599
+ >;
600
+ /** Add all columns declared by one reusable step program. */
601
+ withColumns<
602
+ Program extends PlayAuthoringStepProgram<
603
+ OutputRow,
604
+ object,
605
+ TContext,
606
+ unknown
607
+ >,
608
+ >(
609
+ program: Program,
610
+ ): PlayAuthoringDatasetBuilder<
611
+ InputRow,
612
+ PlayAuthoringStepProgramOutput<Program>,
613
+ TContext
614
+ >;
615
+ /** @deprecated Dataset `.step(...)` was replaced by `.withColumn(...)`. */
616
+ step<Name extends string, Value>(
617
+ name: Name,
618
+ resolver: PlayAuthoringColumnResolver<OutputRow, Value, TContext>,
619
+ ): never;
620
+ /**
621
+ * Execute the row-column program and return a durable dataset handle.
622
+ * `upsert` preserves row-by-row enrichment. `net_new` admits and returns only
623
+ * unseen stable keys. `isolate` records failed rows while siblings continue;
624
+ * `fail` opts into fail-fast behavior.
625
+ */
626
+ run(
627
+ options?: PlayAuthoringDatasetRunOptions<InputRow>,
628
+ ): Promise<PlayDataset<OutputRow>>;
629
+ };
630
+
631
+ export type PlayAuthoringReferenceLike =
632
+ | { readonly playName: string; readonly name?: string }
633
+ | { readonly name: string; readonly playName?: string };
634
+
635
+ /** Discoverable, non-deprecated Runtime Context members shown to Play authors. */
636
+ export const PLAY_AUTHORING_RUNTIME_CONTEXT_MEMBERS = [
637
+ 'csv',
638
+ 'customerDb',
639
+ 'dataset',
640
+ 'fetch',
641
+ 'log',
642
+ 'runPlay',
643
+ 'runSteps',
644
+ 'secrets',
645
+ 'sleep',
646
+ 'tool',
647
+ 'tools',
648
+ ] as const;
649
+
650
+ /** Runtime Context compatibility members that must not be suggested to authors. */
651
+ export const PLAY_AUTHORING_RUNTIME_CONTEXT_OMITTED_MEMBERS = [
652
+ 'map',
653
+ 'step',
654
+ ] as const;
655
+
656
+ /** Discoverable, non-deprecated Dataset Builder members shown to Play authors. */
657
+ export const PLAY_AUTHORING_DATASET_BUILDER_MEMBERS = [
658
+ 'run',
659
+ 'withColumn',
660
+ 'withColumns',
661
+ ] as const;
662
+
663
+ /** Dataset Builder compatibility members that must not be suggested to authors. */
664
+ export const PLAY_AUTHORING_DATASET_BUILDER_OMITTED_MEMBERS = ['step'] as const;
665
+
666
+ export type PlayAuthoringCsvRenameMap = Record<
667
+ string,
668
+ string | readonly string[]
669
+ >;
670
+
671
+ export type PlayAuthoringFileInput<TMetadata = unknown> = string & {
672
+ readonly __deeplineFileInputMetadata?: TMetadata;
673
+ };
674
+
675
+ export type PlayAuthoringCsvInput<
676
+ TRow extends object = Record<string, unknown>,
677
+ > = PlayAuthoringFileInput<{
678
+ readonly kind: 'csv';
679
+ readonly row: TRow;
680
+ }>;
681
+
682
+ export type PlayAuthoringColumnMap<TRow extends object> = Partial<
683
+ Record<Extract<keyof TRow, string>, string | readonly string[]>
684
+ >;
685
+
686
+ export type PlayAuthoringCsvOptions = {
687
+ /** Human-readable description for runtime logs and inspection. */
688
+ description?: string;
689
+ /** Canonical field-to-header aliases. */
690
+ columns?: PlayAuthoringCsvRenameMap;
691
+ /** Header rename map; use `columns` for new code. */
692
+ rename?: PlayAuthoringCsvRenameMap;
693
+ /** Canonical fields required after header normalization. */
694
+ required?: readonly string[];
695
+ };
696
+
697
+ export type PlayAuthoringCallExecution = 'inline';
698
+
699
+ export type PlayAuthoringCallOptions = {
700
+ description: string;
701
+ execution?: PlayAuthoringCallExecution;
702
+ timeoutMs?: never;
703
+ };
704
+
705
+ export type PlayAuthoringRuntimeStepOptions = {
706
+ semanticKey?: string;
707
+ staleAfterSeconds?: DurableCallStaleAfterSeconds;
708
+ };
709
+
710
+ export type PlayAuthoringFetchOptions = {
711
+ staleAfterSeconds?: DurableCallStaleAfterSeconds;
712
+ };
713
+
714
+ export type PlayAuthoringFetchResponse = {
715
+ ok: boolean;
716
+ status: number;
717
+ statusText: string;
718
+ url: string;
719
+ headers: Record<string, string>;
720
+ bodyText: string;
721
+ json: unknown | null;
722
+ };
723
+
724
+ export type PlayAuthoringCustomerDbQueryOptions = {
725
+ maxRows?: number;
726
+ timeoutMs?: number;
727
+ };
728
+
729
+ export type PlayAuthoringRunStepsOptions = {
730
+ description?: string;
731
+ };
732
+
733
+ /** The complete customer-authored `ctx` Interface shared by every Adapter. */
734
+ export interface PlayAuthoringRuntimeContext {
735
+ /**
736
+ * Load a staged CSV file as a durable dataset handle.
737
+ * @sdkReference runtime 040 ctx.csv(path, options)
738
+ */
739
+ csv<T = Record<string, unknown>>(
740
+ path: string | PlayAuthoringCsvInput<T & object>,
741
+ options?: PlayAuthoringCsvOptions,
742
+ ): Promise<PlayDataset<T>>;
743
+
744
+ /**
745
+ * Create a persisted row dataset and define durable output columns.
746
+ * @sdkReference runtime 060 ctx.dataset(key, items)
747
+ */
748
+ dataset<TSource extends PlayDatasetInput<object>>(
749
+ key: string,
750
+ items: TSource,
751
+ ): PlayAuthoringDatasetBuilder<
752
+ PlayDatasetRow<TSource> & object,
753
+ PlayDatasetRow<TSource> & object,
754
+ PlayAuthoringRuntimeContext
755
+ >;
756
+
757
+ /** @deprecated `ctx.map(...)` was replaced by `ctx.dataset(...)`. */
758
+ map<TSource extends PlayDatasetInput<object>>(
759
+ key: string,
760
+ items: TSource,
761
+ options?: PlayAuthoringDatasetDefinitionOptions<
762
+ PlayDatasetRow<TSource> & object
763
+ >,
764
+ ): never;
765
+
766
+ tools: {
767
+ /**
768
+ * Execute a provider tool through the durable receipt contract.
769
+ * @sdkReference runtime 150 ctx.tools.execute(request)
770
+ */
771
+ execute<TOutput = PlayLooseObject>(
772
+ request: PlayToolExecutionRequest,
773
+ ): Promise<ToolExecuteResult<TOutput>>;
774
+ };
775
+
776
+ customerDb: {
777
+ query<TRow extends object = Record<string, unknown>>(
778
+ statement: PlaySqlQuery | string,
779
+ options?: PlayAuthoringCustomerDbQueryOptions,
780
+ ): Promise<TRow[]>;
781
+ };
782
+
783
+ /** Shorthand for one managed tool call. */
784
+ tool<TOutput = PlayLooseObject>(
785
+ key: string,
786
+ toolId: string,
787
+ input: Record<string, unknown>,
788
+ options?: { description?: string },
789
+ ): Promise<ToolExecuteResult<TOutput>>;
790
+
791
+ /**
792
+ * Execute one reusable step program against a scalar input.
793
+ * @sdkReference runtime 180 ctx.runSteps(program, input, options)
794
+ */
795
+ runSteps<TInput extends Record<string, unknown>, TOutput>(
796
+ program: PlayAuthoringRunnableStepProgram<
797
+ TOutput,
798
+ PlayAuthoringRuntimeContext
799
+ > & { readonly __inputType?: (input: TInput) => void },
800
+ input: TInput,
801
+ options?: PlayAuthoringRunStepsOptions,
802
+ ): Promise<TOutput>;
803
+
804
+ /**
805
+ * Create one scalar durable checkpoint.
806
+ * @sdkReference runtime 130 ctx.step(id, fn)
807
+ */
808
+ step<T>(
809
+ id: string,
810
+ run: () => T | Promise<T>,
811
+ options?: PlayAuthoringRuntimeStepOptions,
812
+ ): Promise<T>;
813
+
814
+ /**
815
+ * Execute a durable, replay-safe HTTP request.
816
+ * @sdkReference runtime 170 ctx.fetch(key, url, init)
817
+ */
818
+ fetch(
819
+ key: string,
820
+ url: string | URL,
821
+ init?: PlaySecretAwareRequestInit,
822
+ options?: PlayAuthoringFetchOptions,
823
+ ): Promise<PlayAuthoringFetchResponse>;
824
+
825
+ secrets: {
826
+ get(name: string): PlaySecretHandle;
827
+ bearer(secret: PlaySecretHandle): PlaySecretAuth;
828
+ header(header: string, secret: PlaySecretHandle): PlaySecretAuth;
829
+ };
830
+
831
+ /**
832
+ * Compose another Play inline under a stable call key.
833
+ * @sdkReference runtime 140 ctx.runPlay(key, playRef, input, options)
834
+ */
835
+ runPlay<TOutput = unknown>(
836
+ key: string,
837
+ playRef: string | PlayAuthoringReferenceLike,
838
+ input: Record<string, unknown>,
839
+ options: PlayAuthoringCallOptions,
840
+ ): Promise<TOutput>;
841
+
842
+ log(message: string): void;
843
+ sleep(ms: number): Promise<void>;
844
+ }
845
+
846
+ const SecretEnvironmentNameSchema = Type.String({
847
+ pattern: '^[A-Z][A-Z0-9_]{1,63}$',
848
+ description:
849
+ 'An uppercase environment variable name beginning with a letter.',
850
+ });
851
+ const SqlListenerFilterScalarSchema = Type.Union([
852
+ Type.String(),
853
+ Type.Number(),
854
+ Type.Boolean(),
855
+ Type.Null(),
856
+ ]);
857
+
858
+ export const PLAY_AUTHORING_FIELD_REGISTRY = {
859
+ description: {
860
+ schema: Type.String({ minLength: 1 }),
861
+ fixtures: {
862
+ valid: 'Enrich a company.',
863
+ invalid: '',
864
+ absent: undefined,
865
+ unresolved: { expression: 'description' },
866
+ edition1: 'Legacy play.',
867
+ },
868
+ referenceType: 'string',
869
+ required: false,
870
+ resolution: 'static-required',
871
+ issueCode: 'play_authoring_binding_invalid',
872
+ description: 'Optional non-empty human-readable summary of the Play.',
873
+ errorMessage: 'description must be a non-empty static string.',
874
+ },
875
+ 'compatibility.toolErrorSchemaVersion': {
876
+ schema: Type.Union([Type.Literal(0), Type.Literal(1)]),
877
+ fixtures: {
878
+ valid: 1,
879
+ invalid: 2,
880
+ absent: undefined,
881
+ unresolved: { expression: 'version' },
882
+ edition1: 0,
883
+ },
884
+ referenceType: '0 | 1',
885
+ required: false,
886
+ resolution: 'static-required',
887
+ issueCode: 'play_authoring_binding_invalid',
888
+ description: 'Artifact-pinned tool error behavior, either 0 or 1.',
889
+ errorMessage:
890
+ 'compatibility.toolErrorSchemaVersion must be the static literal 0 or 1.',
891
+ },
892
+ inline: {
893
+ schema: Type.Boolean(),
894
+ fixtures: {
895
+ valid: true,
896
+ invalid: 'true',
897
+ absent: undefined,
898
+ unresolved: { expression: 'inline' },
899
+ edition1: false,
900
+ },
901
+ referenceType: 'boolean',
902
+ required: false,
903
+ resolution: 'static-required',
904
+ issueCode: 'play_authoring_binding_invalid',
905
+ description: 'Compiler hint for an inline named Play handler.',
906
+ errorMessage: 'inline must be a static boolean.',
907
+ },
908
+ 'billing.maxCreditsPerRun': {
909
+ schema: Type.Number({ exclusiveMinimum: 0 }),
910
+ fixtures: {
911
+ valid: 1,
912
+ invalid: 0,
913
+ absent: undefined,
914
+ unresolved: { expression: 'cap' },
915
+ edition1: 1,
916
+ },
917
+ referenceType: 'number',
918
+ required: false,
919
+ resolution: 'static-required',
920
+ issueCode: 'play_authoring_billing_limit_invalid',
921
+ description: 'Maximum Deepline credits permitted for one Play Run.',
922
+ errorMessage:
923
+ 'billing.maxCreditsPerRun must be a static number greater than 0. Remove it for no run cap.',
924
+ },
925
+ 'bindings.webhook.hmac.secretEnv': {
926
+ schema: SecretEnvironmentNameSchema,
927
+ fixtures: {
928
+ valid: 'WEBHOOK_SECRET',
929
+ invalid: 'webhook_secret',
930
+ absent: undefined,
931
+ unresolved: { expression: 'secretEnv' },
932
+ edition1: 'WEBHOOK_SECRET',
933
+ },
934
+ referenceType: 'string',
935
+ required: true,
936
+ resolution: 'static-required',
937
+ issueCode: 'play_authoring_webhook_hmac_invalid',
938
+ description: 'Environment variable containing the webhook HMAC secret.',
939
+ errorMessage:
940
+ 'bindings.webhook.hmac.secretEnv must be an uppercase environment variable name beginning with a letter.',
941
+ },
942
+ 'bindings.webhook.hmac.algorithm': {
943
+ schema: Type.Literal('sha256'),
944
+ fixtures: {
945
+ valid: 'sha256',
946
+ invalid: 'sha1',
947
+ absent: undefined,
948
+ unresolved: { expression: 'algorithm' },
949
+ edition1: 'sha256',
950
+ },
951
+ referenceType: "'sha256'",
952
+ required: false,
953
+ resolution: 'static-required',
954
+ issueCode: 'play_authoring_webhook_hmac_invalid',
955
+ description: 'Webhook signature hash algorithm. Only sha256 is supported.',
956
+ errorMessage:
957
+ 'bindings.webhook.hmac.algorithm must be the static literal "sha256".',
958
+ },
959
+ 'bindings.webhook.hmac.header': {
960
+ schema: Type.String({ minLength: 1 }),
961
+ fixtures: {
962
+ valid: 'x-signature',
963
+ invalid: '',
964
+ absent: undefined,
965
+ unresolved: { expression: 'header' },
966
+ edition1: 'x-signature',
967
+ },
968
+ referenceType: 'string',
969
+ required: false,
970
+ resolution: 'static-required',
971
+ issueCode: 'play_authoring_webhook_hmac_invalid',
972
+ description: 'HTTP header containing the webhook signature.',
973
+ errorMessage:
974
+ 'bindings.webhook.hmac.header must be a non-empty static string.',
975
+ },
976
+ 'bindings.cron.schedule': {
977
+ schema: Type.String({ minLength: 1 }),
978
+ fixtures: {
979
+ valid: '0 9 * * *',
980
+ invalid: '',
981
+ absent: undefined,
982
+ unresolved: { expression: 'schedule' },
983
+ edition1: '0 9 * * *',
984
+ },
985
+ referenceType: 'string',
986
+ required: true,
987
+ resolution: 'static-required',
988
+ issueCode: 'play_authoring_binding_invalid',
989
+ description: 'Five-field cron expression.',
990
+ errorMessage: 'bindings.cron.schedule must be a non-empty static string.',
991
+ },
992
+ 'bindings.cron.timezone': {
993
+ schema: Type.String({ minLength: 1 }),
994
+ fixtures: {
995
+ valid: 'UTC',
996
+ invalid: '',
997
+ absent: undefined,
998
+ unresolved: { expression: 'timezone' },
999
+ edition1: 'UTC',
1000
+ },
1001
+ referenceType: 'string',
1002
+ required: false,
1003
+ resolution: 'static-required',
1004
+ issueCode: 'play_authoring_cron_timezone_invalid',
1005
+ description: 'IANA timezone. Omitted means UTC.',
1006
+ errorMessage:
1007
+ 'bindings.cron.timezone must be a valid non-empty IANA timezone string.',
1008
+ },
1009
+ 'bindings.sqlListeners': {
1010
+ schema: Type.Array(Type.Object({}, { additionalProperties: true })),
1011
+ fixtures: {
1012
+ valid: [],
1013
+ invalid: 'listeners',
1014
+ absent: undefined,
1015
+ unresolved: { expression: 'listeners' },
1016
+ edition1: [],
1017
+ },
1018
+ referenceType: 'SqlListener[]',
1019
+ required: false,
1020
+ resolution: 'static-required',
1021
+ issueCode: 'play_authoring_binding_invalid',
1022
+ description: 'Static provider-monitor listener declarations.',
1023
+ errorMessage: 'bindings.sqlListeners must be a static array of objects.',
1024
+ },
1025
+ 'bindings.sqlListeners[].id': {
1026
+ schema: Type.String({ pattern: PLAY_SQL_LISTENER_ID_PATTERN.source }),
1027
+ fixtures: {
1028
+ valid: 'job-openings',
1029
+ invalid: '1-job-openings',
1030
+ absent: undefined,
1031
+ unresolved: { expression: 'listenerId' },
1032
+ edition1: 'job-openings',
1033
+ },
1034
+ referenceType: 'string',
1035
+ required: true,
1036
+ resolution: 'static-required',
1037
+ issueCode: 'sql_listener_binding_shape',
1038
+ description: 'Unique static listener identifier within one Play.',
1039
+ errorMessage:
1040
+ 'bindings.sqlListeners[].id must begin with a letter and contain only letters, numbers, underscores, or hyphens.',
1041
+ },
1042
+ 'bindings.sqlListeners[].tool': {
1043
+ schema: Type.String({ pattern: PLAY_SQL_LISTENER_TOOL_PATTERN.source }),
1044
+ fixtures: {
1045
+ valid: 'deepline_native.company_radar',
1046
+ invalid: 'company_radar',
1047
+ absent: undefined,
1048
+ unresolved: { expression: 'toolId' },
1049
+ edition1: 'deepline_native.company_radar',
1050
+ },
1051
+ referenceType: 'string',
1052
+ required: true,
1053
+ resolution: 'static-required',
1054
+ issueCode: 'sql_listener_binding_shape',
1055
+ description: 'Modeled provider monitor tool id in provider.tool form.',
1056
+ errorMessage:
1057
+ 'bindings.sqlListeners[].tool must use static provider.tool syntax.',
1058
+ },
1059
+ 'bindings.sqlListeners[].stream': {
1060
+ schema: Type.String({ pattern: PLAY_SQL_LISTENER_ID_PATTERN.source }),
1061
+ fixtures: {
1062
+ valid: 'company_job_openings',
1063
+ invalid: '1-company-job-openings',
1064
+ absent: undefined,
1065
+ unresolved: { expression: 'stream' },
1066
+ edition1: 'company_job_openings',
1067
+ },
1068
+ referenceType: 'string',
1069
+ required: true,
1070
+ resolution: 'static-required',
1071
+ issueCode: 'sql_listener_binding_shape',
1072
+ description: 'Static output stream key exposed by the monitor tool.',
1073
+ errorMessage:
1074
+ 'bindings.sqlListeners[].stream must be a static stream identifier.',
1075
+ },
1076
+ 'bindings.sqlListeners[].operations[]': {
1077
+ schema: Type.Union([
1078
+ Type.Literal('INSERT'),
1079
+ Type.Literal('UPDATE'),
1080
+ Type.Literal('DELETE'),
1081
+ ]),
1082
+ fixtures: {
1083
+ valid: 'INSERT',
1084
+ invalid: 'UPSERT',
1085
+ absent: undefined,
1086
+ unresolved: { expression: 'operation' },
1087
+ edition1: 'UPDATE',
1088
+ },
1089
+ referenceType: "'INSERT' | 'UPDATE' | 'DELETE'",
1090
+ required: false,
1091
+ resolution: 'static-required',
1092
+ issueCode: 'sql_listener_binding_shape',
1093
+ description: 'Database operation that wakes the listener.',
1094
+ errorMessage:
1095
+ 'bindings.sqlListeners[].operations entries must be INSERT, UPDATE, or DELETE.',
1096
+ },
1097
+ 'bindings.sqlListeners[].where.before': {
1098
+ schema: Type.Record(Type.String(), Type.Unknown()),
1099
+ fixtures: {
1100
+ valid: { status: { eq: 'open' } },
1101
+ invalid: 'status=open',
1102
+ absent: undefined,
1103
+ unresolved: 'beforeFilter',
1104
+ edition1: { status: { eq: 'open' } },
1105
+ },
1106
+ referenceType: 'Record<string, SqlListenerFilterOperator>',
1107
+ required: false,
1108
+ resolution: 'static-required',
1109
+ issueCode: 'sql_listener_binding_shape',
1110
+ description: 'Column filters evaluated against the row before mutation.',
1111
+ errorMessage:
1112
+ 'bindings.sqlListeners[].where.before must be a static object keyed by column.',
1113
+ },
1114
+ 'bindings.sqlListeners[].where.after': {
1115
+ schema: Type.Record(Type.String(), Type.Unknown()),
1116
+ fixtures: {
1117
+ valid: { status: { eq: 'open' } },
1118
+ invalid: 'status=open',
1119
+ absent: undefined,
1120
+ unresolved: 'afterFilter',
1121
+ edition1: { status: { eq: 'open' } },
1122
+ },
1123
+ referenceType: 'Record<string, SqlListenerFilterOperator>',
1124
+ required: false,
1125
+ resolution: 'static-required',
1126
+ issueCode: 'sql_listener_binding_shape',
1127
+ description: 'Column filters evaluated against the row after mutation.',
1128
+ errorMessage:
1129
+ 'bindings.sqlListeners[].where.after must be a static object keyed by column.',
1130
+ },
1131
+ 'bindings.sqlListeners[].where.*.*.eq': {
1132
+ schema: SqlListenerFilterScalarSchema,
1133
+ fixtures: {
1134
+ valid: 'open',
1135
+ invalid: { nested: true },
1136
+ absent: undefined,
1137
+ unresolved: { expression: 'equalsValue' },
1138
+ edition1: 'open',
1139
+ },
1140
+ referenceType: 'SqlListenerFilterScalar',
1141
+ required: false,
1142
+ resolution: 'static-required',
1143
+ issueCode: 'sql_listener_binding_shape',
1144
+ description: 'Scalar equality condition.',
1145
+ errorMessage: 'SQL listener eq must compare a scalar value.',
1146
+ },
1147
+ 'bindings.sqlListeners[].where.*.*.neq': {
1148
+ schema: SqlListenerFilterScalarSchema,
1149
+ fixtures: {
1150
+ valid: 'closed',
1151
+ invalid: { nested: true },
1152
+ absent: undefined,
1153
+ unresolved: { expression: 'notEqualsValue' },
1154
+ edition1: 'closed',
1155
+ },
1156
+ referenceType: 'SqlListenerFilterScalar',
1157
+ required: false,
1158
+ resolution: 'static-required',
1159
+ issueCode: 'sql_listener_binding_shape',
1160
+ description: 'Scalar inequality condition.',
1161
+ errorMessage: 'SQL listener neq must compare a scalar value.',
1162
+ },
1163
+ 'bindings.sqlListeners[].where.*.*.in': {
1164
+ schema: Type.Array(SqlListenerFilterScalarSchema, { minItems: 1 }),
1165
+ fixtures: {
1166
+ valid: ['open', 'pending'],
1167
+ invalid: [],
1168
+ absent: undefined,
1169
+ unresolved: { expression: 'acceptedValues' },
1170
+ edition1: ['open'],
1171
+ },
1172
+ referenceType: 'readonly SqlListenerFilterScalar[]',
1173
+ required: false,
1174
+ resolution: 'static-required',
1175
+ issueCode: 'sql_listener_binding_shape',
1176
+ description: 'Non-empty scalar membership condition.',
1177
+ errorMessage: 'SQL listener in must contain at least one scalar value.',
1178
+ },
1179
+ 'bindings.sqlListeners[].where.*.*.notIn': {
1180
+ schema: Type.Array(SqlListenerFilterScalarSchema, { minItems: 1 }),
1181
+ fixtures: {
1182
+ valid: ['closed'],
1183
+ invalid: [],
1184
+ absent: undefined,
1185
+ unresolved: { expression: 'rejectedValues' },
1186
+ edition1: ['closed'],
1187
+ },
1188
+ referenceType: 'readonly SqlListenerFilterScalar[]',
1189
+ required: false,
1190
+ resolution: 'static-required',
1191
+ issueCode: 'sql_listener_binding_shape',
1192
+ description: 'Non-empty scalar exclusion condition.',
1193
+ errorMessage: 'SQL listener notIn must contain at least one scalar value.',
1194
+ },
1195
+ 'bindings.sqlListeners[].where.*.*.isNull': {
1196
+ schema: Type.Literal(true),
1197
+ fixtures: {
1198
+ valid: true,
1199
+ invalid: false,
1200
+ absent: undefined,
1201
+ unresolved: { expression: 'isNull' },
1202
+ edition1: true,
1203
+ },
1204
+ referenceType: 'true',
1205
+ required: false,
1206
+ resolution: 'static-required',
1207
+ issueCode: 'sql_listener_binding_shape',
1208
+ description: 'Matches null values when set to true.',
1209
+ errorMessage: 'SQL listener isNull must be the static literal true.',
1210
+ },
1211
+ 'bindings.sqlListeners[].where.*.*.isNotNull': {
1212
+ schema: Type.Literal(true),
1213
+ fixtures: {
1214
+ valid: true,
1215
+ invalid: false,
1216
+ absent: undefined,
1217
+ unresolved: { expression: 'isNotNull' },
1218
+ edition1: true,
1219
+ },
1220
+ referenceType: 'true',
1221
+ required: false,
1222
+ resolution: 'static-required',
1223
+ issueCode: 'sql_listener_binding_shape',
1224
+ description: 'Matches non-null values when set to true.',
1225
+ errorMessage: 'SQL listener isNotNull must be the static literal true.',
1226
+ },
1227
+ 'bindings.sqlListeners[].where.*.*.ilike': {
1228
+ schema: Type.String(),
1229
+ fixtures: {
1230
+ valid: '%software%',
1231
+ invalid: 1,
1232
+ absent: undefined,
1233
+ unresolved: { expression: 'pattern' },
1234
+ edition1: '%software%',
1235
+ },
1236
+ referenceType: 'string',
1237
+ required: false,
1238
+ resolution: 'static-required',
1239
+ issueCode: 'sql_listener_binding_shape',
1240
+ description: 'Case-insensitive SQL pattern condition.',
1241
+ errorMessage: 'SQL listener ilike must be a string pattern.',
1242
+ },
1243
+ 'bindings.secrets[]': {
1244
+ schema: SecretEnvironmentNameSchema,
1245
+ fixtures: {
1246
+ valid: 'API_TOKEN',
1247
+ invalid: 'api_token',
1248
+ absent: undefined,
1249
+ unresolved: { expression: 'secret' },
1250
+ edition1: 'API_TOKEN',
1251
+ },
1252
+ referenceType: 'string',
1253
+ required: false,
1254
+ resolution: 'static-required',
1255
+ issueCode: 'play_authoring_secret_invalid',
1256
+ description: 'Environment variable made available to the Play.',
1257
+ errorMessage:
1258
+ 'bindings.secrets entries must be uppercase environment variable names beginning with a letter.',
1259
+ },
1260
+ 'ctx.tools.execute.staleAfterSeconds': {
1261
+ schema: Type.Union([Type.Null(), Type.Integer({ minimum: 0 })]),
1262
+ fixtures: {
1263
+ valid: 0,
1264
+ invalid: -1,
1265
+ absent: undefined,
1266
+ unresolved: { expression: 'ttl' },
1267
+ edition1: null,
1268
+ },
1269
+ referenceType: 'number | null',
1270
+ required: false,
1271
+ resolution: 'runtime-allowed',
1272
+ issueCode: 'play_authoring_durable_policy_invalid',
1273
+ description:
1274
+ '`0` always executes; `null`/omitted never expires; a positive integer is a TTL in seconds.',
1275
+ errorMessage:
1276
+ 'staleAfterSeconds must be null, 0 (always execute), or a positive whole number of seconds.',
1277
+ },
1278
+ 'ctx.tools.execute.id': {
1279
+ schema: Type.String({ pattern: '\\S' }),
1280
+ fixtures: {
1281
+ valid: 'company-enrichment',
1282
+ invalid: '',
1283
+ absent: undefined,
1284
+ unresolved: { expression: 'receiptId' },
1285
+ edition1: 'company-enrichment',
1286
+ },
1287
+ referenceType: 'string',
1288
+ required: true,
1289
+ resolution: 'runtime-allowed',
1290
+ issueCode: 'play_authoring_tool_request_invalid',
1291
+ description: 'Stable durable receipt identity within one execution scope.',
1292
+ errorMessage: 'ctx.tools.execute id must be a non-empty string.',
1293
+ },
1294
+ 'ctx.tools.execute.tool': {
1295
+ schema: Type.String({ pattern: '\\S' }),
1296
+ fixtures: {
1297
+ valid: 'openmart_enrich_company',
1298
+ invalid: '',
1299
+ absent: undefined,
1300
+ unresolved: { expression: 'toolId' },
1301
+ edition1: 'openmart_enrich_company',
1302
+ },
1303
+ referenceType: 'K',
1304
+ required: true,
1305
+ resolution: 'runtime-allowed',
1306
+ issueCode: 'play_authoring_tool_request_invalid',
1307
+ description: 'Integration tool id resolved against the generated ToolMap.',
1308
+ errorMessage: 'ctx.tools.execute tool must be a non-empty tool id.',
1309
+ },
1310
+ 'ctx.tools.execute.input': {
1311
+ schema: Type.Record(Type.String(), Type.Unknown()),
1312
+ fixtures: {
1313
+ valid: { domain: 'example.com' },
1314
+ invalid: 'example.com',
1315
+ absent: undefined,
1316
+ unresolved: 'toolInput',
1317
+ edition1: {},
1318
+ },
1319
+ referenceType:
1320
+ "K extends keyof ToolMap ? ToolMap[K]['input'] : Record<string, unknown>",
1321
+ required: true,
1322
+ resolution: 'runtime-allowed',
1323
+ issueCode: 'play_authoring_tool_request_invalid',
1324
+ description: 'Tool-specific input object.',
1325
+ errorMessage: 'ctx.tools.execute input must be an object.',
1326
+ },
1327
+ 'ctx.tools.execute.description': {
1328
+ schema: Type.String(),
1329
+ fixtures: {
1330
+ valid: 'Enrich the company.',
1331
+ invalid: 1,
1332
+ absent: undefined,
1333
+ unresolved: { expression: 'description' },
1334
+ edition1: 'Enrich the company.',
1335
+ },
1336
+ referenceType: 'string',
1337
+ required: false,
1338
+ resolution: 'runtime-allowed',
1339
+ issueCode: 'play_authoring_tool_request_invalid',
1340
+ description: 'Human-readable purpose of the durable tool call.',
1341
+ errorMessage: 'ctx.tools.execute description must be a string.',
1342
+ },
1343
+ 'ctx.tools.execute.force': {
1344
+ schema: Type.Boolean(),
1345
+ fixtures: {
1346
+ valid: true,
1347
+ invalid: 'true',
1348
+ absent: undefined,
1349
+ unresolved: { expression: 'force' },
1350
+ edition1: false,
1351
+ },
1352
+ referenceType: 'boolean',
1353
+ required: false,
1354
+ resolution: 'runtime-allowed',
1355
+ issueCode: 'play_authoring_tool_request_invalid',
1356
+ description: 'Explicitly bypasses a completed durable tool receipt.',
1357
+ errorMessage: 'ctx.tools.execute force must be a boolean.',
1358
+ },
1359
+ 'ctx.tools.execute.timeoutMs': {
1360
+ schema: Type.Integer({ minimum: 1 }),
1361
+ fixtures: {
1362
+ valid: 1,
1363
+ invalid: 0,
1364
+ absent: undefined,
1365
+ unresolved: { expression: 'timeout' },
1366
+ edition1: 1,
1367
+ },
1368
+ referenceType: 'number',
1369
+ required: false,
1370
+ resolution: 'runtime-allowed',
1371
+ issueCode: 'play_authoring_durable_policy_invalid',
1372
+ description:
1373
+ 'Positive whole-number runtime transport timeout in milliseconds.',
1374
+ errorMessage: 'timeoutMs must be a positive whole number of milliseconds.',
1375
+ },
1376
+ 'ctx.tools.execute.receiptWaitMs': {
1377
+ schema: Type.Integer({ minimum: 1 }),
1378
+ fixtures: {
1379
+ valid: 1,
1380
+ invalid: 0,
1381
+ absent: undefined,
1382
+ unresolved: { expression: 'receiptWait' },
1383
+ edition1: 1,
1384
+ },
1385
+ referenceType: 'number',
1386
+ required: false,
1387
+ resolution: 'runtime-allowed',
1388
+ issueCode: 'play_authoring_durable_policy_invalid',
1389
+ description:
1390
+ 'Positive whole-number durable receipt wait budget in milliseconds.',
1391
+ errorMessage:
1392
+ 'receiptWaitMs must be a positive whole number of milliseconds.',
1393
+ },
1394
+ 'ctx.csv.options.description': {
1395
+ schema: Type.String({ minLength: 1 }),
1396
+ fixtures: {
1397
+ valid: 'Load account rows.',
1398
+ invalid: '',
1399
+ absent: undefined,
1400
+ unresolved: { expression: 'description' },
1401
+ edition1: 'Load rows.',
1402
+ },
1403
+ referenceType: 'string',
1404
+ required: false,
1405
+ resolution: 'static-when-present',
1406
+ issueCode: 'play_authoring_csv_option_invalid',
1407
+ description: 'Non-empty description for a staged CSV load.',
1408
+ errorMessage: 'ctx.csv options.description must be non-empty.',
1409
+ },
1410
+ 'ctx.csv.options.columns': {
1411
+ schema: Type.Record(
1412
+ Type.String(),
1413
+ Type.Union([
1414
+ Type.String({ minLength: 1 }),
1415
+ Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
1416
+ ]),
1417
+ ),
1418
+ fixtures: {
1419
+ valid: { domain: ['domain', 'Company Domain'] },
1420
+ invalid: { domain: [] },
1421
+ absent: undefined,
1422
+ unresolved: { expression: { dynamic: true } },
1423
+ edition1: { domain: 'domain' },
1424
+ },
1425
+ referenceType: 'CsvRenameMap',
1426
+ required: false,
1427
+ resolution: 'runtime-allowed',
1428
+ issueCode: 'play_authoring_csv_option_invalid',
1429
+ description: 'Canonical field-to-header aliases for a staged CSV.',
1430
+ errorMessage:
1431
+ 'ctx.csv options.columns values must be a non-empty header or alias list.',
1432
+ },
1433
+ 'ctx.csv.options.rename': {
1434
+ schema: Type.Record(
1435
+ Type.String(),
1436
+ Type.Union([
1437
+ Type.String({ minLength: 1 }),
1438
+ Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
1439
+ ]),
1440
+ ),
1441
+ fixtures: {
1442
+ valid: { domain: 'Company Domain' },
1443
+ invalid: { domain: '' },
1444
+ absent: undefined,
1445
+ unresolved: { expression: { dynamic: true } },
1446
+ edition1: { domain: 'domain' },
1447
+ },
1448
+ referenceType: 'CsvRenameMap',
1449
+ required: false,
1450
+ resolution: 'static-when-present',
1451
+ issueCode: 'play_authoring_csv_option_invalid',
1452
+ description: 'Legacy header rename aliases for a staged CSV.',
1453
+ errorMessage:
1454
+ 'ctx.csv options.rename values must be a non-empty header or alias list.',
1455
+ },
1456
+ 'ctx.csv.options.required': {
1457
+ schema: Type.Array(Type.String({ minLength: 1 })),
1458
+ fixtures: {
1459
+ valid: ['domain'],
1460
+ invalid: [''],
1461
+ absent: undefined,
1462
+ unresolved: { expression: 'requiredColumns' },
1463
+ edition1: [],
1464
+ },
1465
+ referenceType: 'readonly string[]',
1466
+ required: false,
1467
+ resolution: 'static-when-present',
1468
+ issueCode: 'play_authoring_csv_option_invalid',
1469
+ description: 'Canonical columns required after CSV normalization.',
1470
+ errorMessage:
1471
+ 'ctx.csv options.required entries must be non-empty column names.',
1472
+ },
1473
+ 'ctx.dataset.key': {
1474
+ schema: Type.String({ minLength: 1 }),
1475
+ fixtures: {
1476
+ valid: 'accounts',
1477
+ invalid: '',
1478
+ absent: undefined,
1479
+ unresolved: { expression: 'datasetKey' },
1480
+ edition1: 'rows',
1481
+ },
1482
+ referenceType: 'string',
1483
+ required: true,
1484
+ resolution: 'static-required',
1485
+ issueCode: 'play_authoring_dataset_option_invalid',
1486
+ description: 'Stable durable identity for one dataset.',
1487
+ errorMessage: 'ctx.dataset key must be a non-empty static string.',
1488
+ },
1489
+ 'ctx.dataset.run.description': {
1490
+ schema: Type.String({ minLength: 1 }),
1491
+ fixtures: {
1492
+ valid: 'Enrich account rows.',
1493
+ invalid: '',
1494
+ absent: undefined,
1495
+ unresolved: { expression: 'description' },
1496
+ edition1: 'Process rows.',
1497
+ },
1498
+ referenceType: 'string',
1499
+ required: false,
1500
+ resolution: 'static-when-present',
1501
+ issueCode: 'play_authoring_dataset_option_invalid',
1502
+ description: 'Non-empty description for one dataset execution.',
1503
+ errorMessage: 'ctx.dataset run description must be non-empty.',
1504
+ },
1505
+ 'ctx.dataset.run.key': {
1506
+ schema: Type.Union([
1507
+ Type.String({ minLength: 1 }),
1508
+ Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
1509
+ Type.Function(
1510
+ [Type.Record(Type.String(), Type.Unknown()), Type.Integer()],
1511
+ Type.Union([
1512
+ Type.String(),
1513
+ Type.Number(),
1514
+ Type.Readonly(Type.Array(Type.Unknown())),
1515
+ ]),
1516
+ ),
1517
+ ]),
1518
+ fixtures: {
1519
+ valid: (row: Record<string, unknown>) => String(row.domain),
1520
+ invalid: [],
1521
+ absent: undefined,
1522
+ unresolved: { expression: 'rowKey' },
1523
+ edition1: ['domain'],
1524
+ },
1525
+ referenceType: 'DatasetRowKey<InputRow>',
1526
+ required: false,
1527
+ resolution: 'runtime-dynamic',
1528
+ issueCode: 'play_authoring_dataset_option_invalid',
1529
+ description: 'Stable field or fields used for durable row identity.',
1530
+ errorMessage:
1531
+ 'ctx.dataset run key must be a non-empty field, field list, or key function.',
1532
+ },
1533
+ 'ctx.dataset.run.onRowError': {
1534
+ schema: Type.Union([Type.Literal('isolate'), Type.Literal('fail')]),
1535
+ fixtures: {
1536
+ valid: 'isolate',
1537
+ invalid: 'continue',
1538
+ absent: undefined,
1539
+ unresolved: { expression: 'rowErrorPolicy' },
1540
+ edition1: 'fail',
1541
+ },
1542
+ referenceType: "'isolate' | 'fail'",
1543
+ required: false,
1544
+ resolution: 'static-when-present',
1545
+ issueCode: 'play_authoring_dataset_option_invalid',
1546
+ description: 'Whether row failures isolate or fail the whole dataset.',
1547
+ errorMessage: 'ctx.dataset run onRowError must be "isolate" or "fail".',
1548
+ },
1549
+ 'ctx.dataset.run.mode': {
1550
+ schema: Type.Union([Type.Literal('upsert'), Type.Literal('net_new')]),
1551
+ fixtures: {
1552
+ valid: 'upsert',
1553
+ invalid: 'append',
1554
+ absent: undefined,
1555
+ unresolved: { expression: 'datasetMode' },
1556
+ edition1: 'upsert',
1557
+ },
1558
+ referenceType: "'upsert' | 'net_new'",
1559
+ required: false,
1560
+ resolution: 'static-when-present',
1561
+ issueCode: 'play_authoring_dataset_option_invalid',
1562
+ description:
1563
+ 'Whether the dataset returns all rows or only newly admitted rows.',
1564
+ errorMessage: 'ctx.dataset run mode must be "upsert" or "net_new".',
1565
+ },
1566
+ 'ctx.step.id': {
1567
+ schema: Type.String({ minLength: 1 }),
1568
+ fixtures: {
1569
+ valid: 'load-settings',
1570
+ invalid: '',
1571
+ absent: undefined,
1572
+ unresolved: { expression: 'stepId' },
1573
+ edition1: 'step',
1574
+ },
1575
+ referenceType: 'string',
1576
+ required: true,
1577
+ resolution: 'static-required',
1578
+ issueCode: 'play_authoring_step_option_invalid',
1579
+ description: 'Stable durable identity for one scalar checkpoint.',
1580
+ errorMessage: 'ctx.step id must be a non-empty static string.',
1581
+ },
1582
+ 'ctx.step.semanticKey': {
1583
+ schema: Type.String({ minLength: 1 }),
1584
+ fixtures: {
1585
+ valid: 'account:stripe.com',
1586
+ invalid: '',
1587
+ absent: undefined,
1588
+ unresolved: { expression: 'semanticKey' },
1589
+ edition1: 'account',
1590
+ },
1591
+ referenceType: 'string',
1592
+ required: false,
1593
+ resolution: 'runtime-dynamic',
1594
+ issueCode: 'play_authoring_step_option_invalid',
1595
+ description: 'Optional semantic receipt identity for a scalar checkpoint.',
1596
+ errorMessage: 'ctx.step semanticKey must be a non-empty string.',
1597
+ },
1598
+ 'ctx.step.staleAfterSeconds': {
1599
+ schema: Type.Union([Type.Null(), Type.Integer({ minimum: 0 })]),
1600
+ fixtures: {
1601
+ valid: 0,
1602
+ invalid: -1,
1603
+ absent: undefined,
1604
+ unresolved: { expression: 'ttl' },
1605
+ edition1: null,
1606
+ },
1607
+ referenceType: 'number | null',
1608
+ required: false,
1609
+ resolution: 'runtime-dynamic',
1610
+ issueCode: 'play_authoring_durable_policy_invalid',
1611
+ description:
1612
+ 'Checkpoint freshness: null/omitted never expires, 0 always executes.',
1613
+ errorMessage:
1614
+ 'staleAfterSeconds must be null, 0 (always execute), or a positive whole number of seconds.',
1615
+ },
1616
+ 'ctx.fetch.key': {
1617
+ schema: Type.String({ minLength: 1 }),
1618
+ fixtures: {
1619
+ valid: 'notify-crm',
1620
+ invalid: '',
1621
+ absent: undefined,
1622
+ unresolved: { expression: 'fetchKey' },
1623
+ edition1: 'fetch',
1624
+ },
1625
+ referenceType: 'string',
1626
+ required: true,
1627
+ resolution: 'static-required',
1628
+ issueCode: 'play_authoring_durable_policy_invalid',
1629
+ description: 'Stable durable identity for one external HTTP request.',
1630
+ errorMessage: 'ctx.fetch key must be a non-empty static string.',
1631
+ },
1632
+ 'ctx.fetch.staleAfterSeconds': {
1633
+ schema: Type.Union([Type.Null(), Type.Integer({ minimum: 0 })]),
1634
+ fixtures: {
1635
+ valid: null,
1636
+ invalid: 1.5,
1637
+ absent: undefined,
1638
+ unresolved: { expression: 'ttl' },
1639
+ edition1: 0,
1640
+ },
1641
+ referenceType: 'number | null',
1642
+ required: false,
1643
+ resolution: 'runtime-dynamic',
1644
+ issueCode: 'play_authoring_durable_policy_invalid',
1645
+ description:
1646
+ 'Fetch freshness: null/omitted never expires, 0 always executes.',
1647
+ errorMessage:
1648
+ 'staleAfterSeconds must be null, 0 (always execute), or a positive whole number of seconds.',
1649
+ },
1650
+ 'ctx.runPlay.key': {
1651
+ schema: Type.String({ minLength: 1 }),
1652
+ fixtures: {
1653
+ valid: 'enrich-company',
1654
+ invalid: '',
1655
+ absent: undefined,
1656
+ unresolved: { expression: 'callKey' },
1657
+ edition1: 'child',
1658
+ },
1659
+ referenceType: 'string',
1660
+ required: true,
1661
+ resolution: 'static-required',
1662
+ issueCode: 'play_authoring_run_play_option_invalid',
1663
+ description: 'Stable identity for one inline child Play call.',
1664
+ errorMessage: 'ctx.runPlay key must be a non-empty static string.',
1665
+ },
1666
+ 'ctx.runPlay.playRef': {
1667
+ schema: Type.Union([
1668
+ Type.String({ minLength: 1 }),
1669
+ Type.Union([
1670
+ Type.Object(
1671
+ { playName: Type.String({ minLength: 1 }) },
1672
+ { additionalProperties: true },
1673
+ ),
1674
+ Type.Object(
1675
+ { name: Type.String({ minLength: 1 }) },
1676
+ { additionalProperties: true },
1677
+ ),
1678
+ ]),
1679
+ ]),
1680
+ fixtures: {
1681
+ valid: 'prebuilt/company-lookup',
1682
+ invalid: {},
1683
+ absent: undefined,
1684
+ unresolved: { expression: 'playRef' },
1685
+ edition1: { name: 'company-lookup' },
1686
+ },
1687
+ referenceType: 'string | PlayReferenceLike',
1688
+ required: true,
1689
+ resolution: 'runtime-dynamic',
1690
+ issueCode: 'play_authoring_run_play_option_invalid',
1691
+ description: 'Child Play name or typed Play definition handle.',
1692
+ errorMessage:
1693
+ 'ctx.runPlay playRef must be a non-empty Play name or definition handle.',
1694
+ },
1695
+ 'ctx.runPlay.input': {
1696
+ schema: Type.Record(Type.String(), Type.Unknown()),
1697
+ fixtures: {
1698
+ valid: { domain: 'example.com' },
1699
+ invalid: 'example.com',
1700
+ absent: undefined,
1701
+ unresolved: 'childInput',
1702
+ edition1: {},
1703
+ },
1704
+ referenceType: 'Record<string, unknown>',
1705
+ required: true,
1706
+ resolution: 'runtime-dynamic',
1707
+ issueCode: 'play_authoring_run_play_option_invalid',
1708
+ description: 'Scalar input object submitted to the child Play.',
1709
+ errorMessage: 'ctx.runPlay input must be an object.',
1710
+ },
1711
+ 'ctx.runPlay.options.description': {
1712
+ schema: Type.String({ minLength: 1 }),
1713
+ fixtures: {
1714
+ valid: 'Enrich the company.',
1715
+ invalid: '',
1716
+ absent: undefined,
1717
+ unresolved: { expression: 'description' },
1718
+ edition1: 'Run child.',
1719
+ },
1720
+ referenceType: 'string',
1721
+ required: true,
1722
+ resolution: 'runtime-dynamic',
1723
+ issueCode: 'play_authoring_run_play_option_invalid',
1724
+ description: 'Non-empty purpose for one inline child Play call.',
1725
+ errorMessage: 'ctx.runPlay options.description must be non-empty.',
1726
+ },
1727
+ 'ctx.runPlay.options.execution': {
1728
+ schema: Type.Literal('inline'),
1729
+ fixtures: {
1730
+ valid: 'inline',
1731
+ invalid: 'child-workflow',
1732
+ absent: undefined,
1733
+ unresolved: { expression: 'execution' },
1734
+ edition1: 'inline',
1735
+ },
1736
+ referenceType: "'inline'",
1737
+ required: false,
1738
+ resolution: 'static-required',
1739
+ issueCode: 'play_authoring_run_play_option_invalid',
1740
+ description: 'Child composition strategy. Only inline is supported.',
1741
+ errorMessage: 'ctx.runPlay execution must be "inline".',
1742
+ },
1743
+ 'ctx.runPlay.options.timeoutMs': {
1744
+ schema: Type.Undefined(),
1745
+ fixtures: {
1746
+ valid: undefined,
1747
+ invalid: 1000,
1748
+ absent: undefined,
1749
+ unresolved: { expression: 'timeoutMs' },
1750
+ edition1: undefined,
1751
+ },
1752
+ referenceType: 'never',
1753
+ required: false,
1754
+ resolution: 'unsupported',
1755
+ issueCode: 'play_authoring_run_play_option_invalid',
1756
+ description: 'Unsupported legacy child-workflow timeout.',
1757
+ errorMessage:
1758
+ 'ctx.runPlay timeoutMs is unsupported because child Plays execute inline.',
1759
+ },
1760
+ 'runtime.timeout': {
1761
+ schema: Type.String({ pattern: '^\\d+\\s*[mh]$' }),
1762
+ fixtures: {
1763
+ valid: '90m',
1764
+ invalid: '90s',
1765
+ absent: undefined,
1766
+ unresolved: { expression: 'timeout' },
1767
+ edition1: '90m',
1768
+ },
1769
+ referenceType: 'string',
1770
+ required: false,
1771
+ resolution: 'static-required',
1772
+ issueCode: 'play_authoring_binding_invalid',
1773
+ description: 'Sandbox deadline such as 90m or 2h.',
1774
+ errorMessage:
1775
+ 'runtime.timeout must be a static duration such as "90m" or "2h".',
1776
+ },
1777
+ 'runtime.size': {
1778
+ schema: Type.Literal('standard'),
1779
+ fixtures: {
1780
+ valid: 'standard',
1781
+ invalid: 'large',
1782
+ absent: undefined,
1783
+ unresolved: { expression: 'size' },
1784
+ edition1: 'standard',
1785
+ },
1786
+ referenceType: "'standard'",
1787
+ required: false,
1788
+ resolution: 'static-required',
1789
+ issueCode: 'play_authoring_binding_invalid',
1790
+ description: 'Deepline-managed sandbox size. Only standard is supported.',
1791
+ errorMessage: 'runtime.size must be the static literal "standard".',
1792
+ },
1793
+ 'ctx.customerDb.query.statement': {
1794
+ schema: Type.Union([
1795
+ Type.String({ minLength: 1 }),
1796
+ Type.Object(
1797
+ {
1798
+ kind: Type.Optional(Type.Literal('sql.query')),
1799
+ text: Type.String({ minLength: 1 }),
1800
+ values: Type.Optional(Type.Array(Type.Unknown(), { maxItems: 0 })),
1801
+ },
1802
+ { additionalProperties: false },
1803
+ ),
1804
+ ]),
1805
+ fixtures: {
1806
+ valid: { kind: 'sql.query', text: 'select 1', values: [] },
1807
+ invalid: { kind: 'sql.query', text: 'select $1', values: [1] },
1808
+ absent: undefined,
1809
+ unresolved: { expression: 'statement' },
1810
+ edition1: 'select 1',
1811
+ },
1812
+ referenceType: 'SqlQuery',
1813
+ required: true,
1814
+ resolution: 'runtime-dynamic',
1815
+ issueCode: 'play_authoring_tool_request_invalid',
1816
+ description:
1817
+ 'One non-empty Customer DB SQL string; the deprecated SqlQuery object is accepted only without parameter values.',
1818
+ errorMessage:
1819
+ 'ctx.customerDb.query statement must be a non-empty SQL string. Deprecated SqlQuery objects cannot contain parameter values.',
1820
+ },
1821
+ 'ctx.customerDb.query.options.maxRows': {
1822
+ schema: Type.Integer({ minimum: 1 }),
1823
+ fixtures: {
1824
+ valid: 100,
1825
+ invalid: 0,
1826
+ absent: undefined,
1827
+ unresolved: { expression: 'maxRows' },
1828
+ edition1: 100,
1829
+ },
1830
+ referenceType: 'number',
1831
+ required: false,
1832
+ resolution: 'runtime-dynamic',
1833
+ issueCode: 'play_authoring_tool_request_invalid',
1834
+ description: 'Positive whole-number Customer DB response row limit.',
1835
+ errorMessage:
1836
+ 'ctx.customerDb.query options.maxRows must be a positive whole number.',
1837
+ },
1838
+ 'ctx.customerDb.query.options.timeoutMs': {
1839
+ schema: Type.Integer({ minimum: 1 }),
1840
+ fixtures: {
1841
+ valid: 1000,
1842
+ invalid: 0,
1843
+ absent: undefined,
1844
+ unresolved: { expression: 'timeoutMs' },
1845
+ edition1: 1000,
1846
+ },
1847
+ referenceType: 'number',
1848
+ required: false,
1849
+ resolution: 'runtime-dynamic',
1850
+ issueCode: 'play_authoring_durable_policy_invalid',
1851
+ description: 'Positive whole-number Customer DB timeout in milliseconds.',
1852
+ errorMessage:
1853
+ 'ctx.customerDb.query options.timeoutMs must be a positive whole number of milliseconds.',
1854
+ },
1855
+ 'ctx.tool.key': {
1856
+ schema: Type.String({ minLength: 1 }),
1857
+ fixtures: {
1858
+ valid: 'company',
1859
+ invalid: '',
1860
+ absent: undefined,
1861
+ unresolved: { expression: 'key' },
1862
+ edition1: 'tool',
1863
+ },
1864
+ referenceType: 'string',
1865
+ required: true,
1866
+ resolution: 'runtime-dynamic',
1867
+ issueCode: 'play_authoring_tool_request_invalid',
1868
+ description: 'Stable receipt identity for the tool shorthand.',
1869
+ errorMessage: 'ctx.tool key must be a non-empty string.',
1870
+ },
1871
+ 'ctx.tool.tool': {
1872
+ schema: Type.String({ minLength: 1 }),
1873
+ fixtures: {
1874
+ valid: 'openmart_enrich_company',
1875
+ invalid: '',
1876
+ absent: undefined,
1877
+ unresolved: { expression: 'tool' },
1878
+ edition1: 'openmart_enrich_company',
1879
+ },
1880
+ referenceType: 'string',
1881
+ required: true,
1882
+ resolution: 'runtime-dynamic',
1883
+ issueCode: 'play_authoring_tool_request_invalid',
1884
+ description: 'Integration tool id for the tool shorthand.',
1885
+ errorMessage: 'ctx.tool tool must be a non-empty tool id.',
1886
+ },
1887
+ 'ctx.tool.input': {
1888
+ schema: Type.Record(Type.String(), Type.Unknown()),
1889
+ fixtures: {
1890
+ valid: { domain: 'example.com' },
1891
+ invalid: 'example.com',
1892
+ absent: undefined,
1893
+ unresolved: 'toolInput',
1894
+ edition1: {},
1895
+ },
1896
+ referenceType: 'Record<string, unknown>',
1897
+ required: true,
1898
+ resolution: 'runtime-dynamic',
1899
+ issueCode: 'play_authoring_tool_request_invalid',
1900
+ description: 'Tool-specific input object for the shorthand.',
1901
+ errorMessage: 'ctx.tool input must be an object.',
1902
+ },
1903
+ 'ctx.tool.options.description': {
1904
+ schema: Type.String({ minLength: 1 }),
1905
+ fixtures: {
1906
+ valid: 'Enrich the company.',
1907
+ invalid: '',
1908
+ absent: undefined,
1909
+ unresolved: { expression: 'description' },
1910
+ edition1: 'Run tool.',
1911
+ },
1912
+ referenceType: 'string',
1913
+ required: false,
1914
+ resolution: 'runtime-dynamic',
1915
+ issueCode: 'play_authoring_tool_request_invalid',
1916
+ description: 'Non-empty purpose for the tool shorthand.',
1917
+ errorMessage: 'ctx.tool options.description must be non-empty.',
1918
+ },
1919
+ 'ctx.runSteps.options.description': {
1920
+ schema: Type.String({ minLength: 1 }),
1921
+ fixtures: {
1922
+ valid: 'Score the account.',
1923
+ invalid: '',
1924
+ absent: undefined,
1925
+ unresolved: { expression: 'description' },
1926
+ edition1: 'Run steps.',
1927
+ },
1928
+ referenceType: 'string',
1929
+ required: false,
1930
+ resolution: 'runtime-dynamic',
1931
+ issueCode: 'play_authoring_step_option_invalid',
1932
+ description: 'Non-empty purpose for a reusable step program.',
1933
+ errorMessage: 'ctx.runSteps options.description must be non-empty.',
1934
+ },
1935
+ 'ctx.sleep.ms': {
1936
+ schema: Type.Integer({ minimum: 0 }),
1937
+ fixtures: {
1938
+ valid: 0,
1939
+ invalid: -1,
1940
+ absent: undefined,
1941
+ unresolved: { expression: 'delayMs' },
1942
+ edition1: 1000,
1943
+ },
1944
+ referenceType: 'number',
1945
+ required: true,
1946
+ resolution: 'runtime-dynamic',
1947
+ issueCode: 'play_authoring_step_option_invalid',
1948
+ description: 'Non-negative whole-number sleep duration in milliseconds.',
1949
+ errorMessage: 'ctx.sleep ms must be a non-negative whole number.',
1950
+ },
1951
+ 'ctx.fetch.url': {
1952
+ schema: Type.String({ minLength: 1 }),
1953
+ fixtures: {
1954
+ valid: 'https://example.com',
1955
+ invalid: '',
1956
+ absent: undefined,
1957
+ unresolved: { expression: 'url' },
1958
+ edition1: 'https://example.com',
1959
+ },
1960
+ referenceType: 'string',
1961
+ required: true,
1962
+ resolution: 'runtime-allowed',
1963
+ issueCode: 'play_authoring_fetch_secret_requires_tls',
1964
+ description: 'HTTP request URL. Secret authentication requires HTTPS.',
1965
+ errorMessage: 'ctx.fetch URL must be a non-empty URL string.',
1966
+ },
1967
+ 'ctx.fetch.init.method': {
1968
+ schema: Type.String({ minLength: 1 }),
1969
+ fixtures: {
1970
+ valid: 'GET',
1971
+ invalid: '',
1972
+ absent: undefined,
1973
+ unresolved: { expression: 'method' },
1974
+ edition1: 'GET',
1975
+ },
1976
+ referenceType: 'string',
1977
+ required: false,
1978
+ resolution: 'runtime-allowed',
1979
+ issueCode: 'play_authoring_fetch_idempotency_required',
1980
+ description: 'HTTP method. Mutating methods require an Idempotency-Key.',
1981
+ errorMessage: 'ctx.fetch method must be a non-empty string.',
1982
+ },
1983
+ 'ctx.fetch.init.headers.Idempotency-Key': {
1984
+ schema: Type.String({ minLength: 1 }),
1985
+ fixtures: {
1986
+ valid: 'contact-123-update',
1987
+ invalid: '',
1988
+ absent: undefined,
1989
+ unresolved: { expression: 'idempotencyKey' },
1990
+ edition1: 'contact-123-update',
1991
+ },
1992
+ referenceType: 'string',
1993
+ required: false,
1994
+ resolution: 'runtime-allowed',
1995
+ issueCode: 'play_authoring_fetch_idempotency_required',
1996
+ description: 'Required for mutating HTTP methods to make replay safe.',
1997
+ errorMessage: 'Idempotency-Key must be a non-empty string when provided.',
1998
+ },
1999
+ } as const satisfies Record<
2000
+ string,
2001
+ {
2002
+ schema: TSchema;
2003
+ fixtures: {
2004
+ valid: unknown;
2005
+ invalid: unknown;
2006
+ absent: undefined;
2007
+ unresolved: unknown;
2008
+ edition1: unknown;
2009
+ };
2010
+ referenceType: string;
2011
+ required: boolean;
2012
+ resolution:
2013
+ | 'static-required'
2014
+ | 'static-when-present'
2015
+ | 'runtime-allowed'
2016
+ | 'runtime-dynamic'
2017
+ | 'unsupported';
2018
+ issueCode: PlayAuthoringContractIssueCode;
2019
+ description: string;
2020
+ errorMessage: string;
2021
+ }
2022
+ >;
2023
+
2024
+ export type PlayAuthoringFieldPath = keyof typeof PLAY_AUTHORING_FIELD_REGISTRY;
2025
+
2026
+ export type PlayAuthoringBindingsSnapshot = PlayAuthoringAstBindings;
2027
+
2028
+ export type AdmittedPlayAuthoringContract = {
2029
+ edition: PlayAuthoringContractEdition;
2030
+ staticPipeline: unknown;
2031
+ /** Input schema materialized at admission; launch must never reparse source. */
2032
+ inputSchema: Record<string, unknown> | null;
2033
+ bindings: PlayAuthoringBindingsSnapshot | null;
2034
+ billingLimit: { maxCreditsPerRun: number } | null;
2035
+ runtimeLimit: PlaySandboxRuntimeLimits;
2036
+ allowedSecrets: string[];
2037
+ };
2038
+
2039
+ export class UnsupportedPlayAuthoringContractEditionError extends Error {
2040
+ constructor(value: unknown) {
2041
+ super(
2042
+ `Unsupported Play authoring contract edition ${String(value)}. Supported editions: ${SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS.join(', ')}.`,
2043
+ );
2044
+ this.name = 'UnsupportedPlayAuthoringContractEditionError';
2045
+ }
2046
+ }
2047
+
2048
+ export class PlayAuthoringContractViolationError extends Error {
2049
+ constructor(
2050
+ readonly path: string,
2051
+ readonly code: PlayAuthoringContractIssueCode,
2052
+ readonly detail: string,
2053
+ readonly hint?: string,
2054
+ ) {
2055
+ super(`[${code} path=${path}] ${detail}`);
2056
+ this.name = 'PlayAuthoringContractViolationError';
2057
+ }
2058
+ }
2059
+
2060
+ /** A schema violation for one field declared by the Authoring Contract Module. */
2061
+ export class PlayAuthoringFieldValidationError extends PlayAuthoringContractViolationError {
2062
+ constructor(
2063
+ path: PlayAuthoringFieldPath,
2064
+ code: PlayAuthoringContractIssueCode,
2065
+ message: string,
2066
+ ) {
2067
+ super(path, code, message);
2068
+ this.name = 'PlayAuthoringFieldValidationError';
2069
+ }
2070
+ }
2071
+
2072
+ export function normalizePlayAuthoringContractEdition(
2073
+ value: unknown,
2074
+ ): PlayAuthoringContractEdition {
2075
+ const edition = value ?? LEGACY_PLAY_AUTHORING_CONTRACT_EDITION;
2076
+ if (
2077
+ !SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS.includes(
2078
+ edition as PlayAuthoringContractEdition,
2079
+ )
2080
+ ) {
2081
+ throw new UnsupportedPlayAuthoringContractEditionError(edition);
2082
+ }
2083
+ return edition as PlayAuthoringContractEdition;
2084
+ }
2085
+
2086
+ export function validatePlayAuthoringField(
2087
+ path: PlayAuthoringFieldPath,
2088
+ value: unknown,
2089
+ ): void {
2090
+ const definition = PLAY_AUTHORING_FIELD_REGISTRY[path];
2091
+ if (Value.Check(definition.schema, value)) return;
2092
+ throw new PlayAuthoringFieldValidationError(
2093
+ path,
2094
+ definition.issueCode,
2095
+ definition.errorMessage,
2096
+ );
2097
+ }
2098
+
2099
+ export function validateOptionalPlayAuthoringField(
2100
+ path: PlayAuthoringFieldPath,
2101
+ value: unknown,
2102
+ ): void {
2103
+ const definition = PLAY_AUTHORING_FIELD_REGISTRY[path];
2104
+ if (value === undefined && !definition.required) return;
2105
+ validatePlayAuthoringField(path, value);
2106
+ }
2107
+
2108
+ /** Normalize the deprecated SqlQuery compatibility shape at the contract seam. */
2109
+ export function normalizePlayAuthoringCustomerDbStatement(
2110
+ statement: PlaySqlQuery | string,
2111
+ ): string {
2112
+ validatePlayAuthoringField('ctx.customerDb.query.statement', statement);
2113
+ return typeof statement === 'string' ? statement : statement.text;
2114
+ }
2115
+
2116
+ export type PlayAuthoringBillingLimit = Static<
2117
+ (typeof PLAY_AUTHORING_FIELD_REGISTRY)['billing.maxCreditsPerRun']['schema']
2118
+ >;
2119
+
2120
+ export type DurableCallStaleAfterSeconds = Static<
2121
+ (typeof PLAY_AUTHORING_FIELD_REGISTRY)['ctx.tools.execute.staleAfterSeconds']['schema']
2122
+ >;
2123
+
2124
+ /** Runtime validation, not TypeScript, enforces positive whole milliseconds. */
2125
+ export type PlayRuntimeTimeoutMs = number;
2126
+ export type PlayReceiptWaitMs = number;
2127
+
2128
+ function cloudReferenceType(path: PlayAuthoringFieldPath): string {
2129
+ return PLAY_AUTHORING_FIELD_REGISTRY[path].referenceType;
2130
+ }
2131
+
2132
+ /** Ambient declarations generated into the cloud Play compiler from this model. */
2133
+ export const PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
2134
+ `export type DurableCallStaleAfterSeconds = ${cloudReferenceType('ctx.tools.execute.staleAfterSeconds')};`,
2135
+ `export type PlayRuntimeTimeoutMs = ${cloudReferenceType('ctx.tools.execute.timeoutMs')};`,
2136
+ `export type PlayReceiptWaitMs = ${cloudReferenceType('ctx.tools.execute.receiptWaitMs')};`,
2137
+ `export type SqlListenerOperation = ${cloudReferenceType('bindings.sqlListeners[].operations[]')};`,
2138
+ 'export type SqlListenerFilterScalar = string | number | boolean | null;',
2139
+ `export type SqlListenerFilterOperator = { eq?: ${cloudReferenceType('bindings.sqlListeners[].where.*.*.eq')}; neq?: ${cloudReferenceType('bindings.sqlListeners[].where.*.*.neq')}; in?: ${cloudReferenceType('bindings.sqlListeners[].where.*.*.in')}; notIn?: ${cloudReferenceType('bindings.sqlListeners[].where.*.*.notIn')}; isNull?: ${cloudReferenceType('bindings.sqlListeners[].where.*.*.isNull')}; isNotNull?: ${cloudReferenceType('bindings.sqlListeners[].where.*.*.isNotNull')}; ilike?: ${cloudReferenceType('bindings.sqlListeners[].where.*.*.ilike')} };`,
2140
+ `export type SqlListenerWhere = { before?: ${cloudReferenceType('bindings.sqlListeners[].where.before')}; after?: ${cloudReferenceType('bindings.sqlListeners[].where.after')} };`,
2141
+ `export type SqlListenerDeclaration = { id: ${cloudReferenceType('bindings.sqlListeners[].id')}; tool: ${cloudReferenceType('bindings.sqlListeners[].tool')}; stream: ${cloudReferenceType('bindings.sqlListeners[].stream')}; operations?: readonly SqlListenerOperation[]; where?: SqlListenerWhere };`,
2142
+ 'export type SqlListenerEvent<T extends object = Record<string, unknown>> = { tool: string; stream: string; operation: SqlListenerOperation; before: T | null; after: T | null; changedAt: string; metadata: { outboxId: string; listenerId: string; table: string } };',
2143
+ "export type SqlQuery = string | { kind?: 'sql.query'; text: string; values?: readonly unknown[] };",
2144
+ 'export type ToolExecutionRequest<K extends string> = {',
2145
+ ` readonly id: ${cloudReferenceType('ctx.tools.execute.id')};`,
2146
+ ` readonly tool: ${cloudReferenceType('ctx.tools.execute.tool')};`,
2147
+ ` readonly input: ${cloudReferenceType('ctx.tools.execute.input')};`,
2148
+ ` readonly description?: ${cloudReferenceType('ctx.tools.execute.description')};`,
2149
+ ` readonly force?: ${cloudReferenceType('ctx.tools.execute.force')};`,
2150
+ ' readonly staleAfterSeconds?: DurableCallStaleAfterSeconds;',
2151
+ ' readonly timeoutMs?: PlayRuntimeTimeoutMs;',
2152
+ ' readonly receiptWaitMs?: PlayReceiptWaitMs;',
2153
+ '};',
2154
+ 'export type PlayBindings = {',
2155
+ ` description?: ${cloudReferenceType('description')};`,
2156
+ ` compatibility?: { toolErrorSchemaVersion: ${cloudReferenceType('compatibility.toolErrorSchemaVersion')} };`,
2157
+ ` inline?: ${cloudReferenceType('inline')};`,
2158
+ ` billing?: { maxCreditsPerRun?: ${cloudReferenceType('billing.maxCreditsPerRun')} };`,
2159
+ ` runtime?: { timeout?: ${cloudReferenceType('runtime.timeout')}; size?: ${cloudReferenceType('runtime.size')} };`,
2160
+ ` webhook?: { hmac?: { algorithm?: ${cloudReferenceType('bindings.webhook.hmac.algorithm')}; header?: ${cloudReferenceType('bindings.webhook.hmac.header')}; secretEnv: ${cloudReferenceType('bindings.webhook.hmac.secretEnv')} } };`,
2161
+ ` cron?: { schedule: ${cloudReferenceType('bindings.cron.schedule')}; timezone?: ${cloudReferenceType('bindings.cron.timezone')} };`,
2162
+ ' sqlListeners?: readonly SqlListenerDeclaration[];',
2163
+ ` secrets?: readonly ${cloudReferenceType('bindings.secrets[]')}[];`,
2164
+ '};',
2165
+ 'declare const SECRET_HANDLE_BRAND: unique symbol;',
2166
+ 'export type SecretHandle = { readonly [SECRET_HANDLE_BRAND]: never; readonly name: string; toString(): string; toJSON(): never };',
2167
+ "export type SecretAuth = { readonly kind: 'bearer' | 'header'; readonly secret: SecretHandle; readonly header?: string };",
2168
+ 'export type PlayInputContract<TInput> = { readonly schema: Record<string, unknown>; readonly __inputType?: TInput };',
2169
+ 'export type PlayReturnObject = Record<string, unknown> & { readonly _metadata?: never };',
2170
+ 'export type CsvRenameMap = Record<string, string | readonly string[]>;',
2171
+ 'export type FileInput<TMetadata = unknown> = string & { readonly __deeplineFileInputMetadata?: TMetadata };',
2172
+ "export type CsvInput<TRow extends object = Record<string, unknown>> = FileInput<{ readonly kind: 'csv'; readonly row: TRow }>;",
2173
+ 'export type ColumnMap<TRow extends object> = { [K in keyof TRow & string]?: string | readonly string[] };',
2174
+ `export type CsvOptions = { description?: ${cloudReferenceType('ctx.csv.options.description')}; columns?: ${cloudReferenceType('ctx.csv.options.columns')}; rename?: ${cloudReferenceType('ctx.csv.options.rename')}; required?: ${cloudReferenceType('ctx.csv.options.required')} };`,
2175
+ "export type PlayCallExecution = 'inline';",
2176
+ `export type PlayCallOptions = { description: ${cloudReferenceType('ctx.runPlay.options.description')}; execution?: ${cloudReferenceType('ctx.runPlay.options.execution')}; timeoutMs?: ${cloudReferenceType('ctx.runPlay.options.timeoutMs')} };`,
2177
+ `export type RuntimeStepOptions = { semanticKey?: ${cloudReferenceType('ctx.step.semanticKey')}; staleAfterSeconds?: ${cloudReferenceType('ctx.step.staleAfterSeconds')} };`,
2178
+ `export type FetchOptions = { staleAfterSeconds?: ${cloudReferenceType('ctx.fetch.staleAfterSeconds')} };`,
2179
+ 'export type PlayFetchResponse = { ok: boolean; status: number; statusText: string; url: string; headers: Record<string, string>; bodyText: string; json: unknown | null };',
2180
+ 'export type StepResolver<Row, Value> = (row: Row, ctx: DeeplinePlayRuntimeContext, index: number, previousCell?: PreviousCell<Value>) => Value | Promise<Value>;',
2181
+ 'export type DatasetColumnRunInput<Row, Value> = { readonly row: Row; readonly ctx: DeeplinePlayRuntimeContext; readonly index: number; readonly previousCell?: PreviousCell<Value> };',
2182
+ 'export type DatasetColumnDefinition<Row, Value> = { readonly run: (input: DatasetColumnRunInput<Row, Value>) => Value | Promise<Value>; readonly runIf?: (row: Row, index: number) => boolean | Promise<boolean> };',
2183
+ "export type ConditionalStepResolver<Row, Value, Else = null> = { readonly kind: 'conditional'; readonly when: (row: Row, index: number) => boolean | Promise<boolean>; readonly run: StepResolver<Row, Value>; readonly elseValue: Else; else<ValueElse>(value: ValueElse): ConditionalStepResolver<Row, Value, ValueElse>; };",
2184
+ 'export type StepOptions<Row, Value = unknown> = { readonly runIf?: (row: Row, index: number) => boolean | Promise<boolean>; readonly recompute?: boolean; readonly recomputeOnError?: boolean; readonly staleAfterSeconds?: number };',
2185
+ "export type StepProgram<Input, Output, Return = Output> = { readonly kind: 'steps'; readonly steps: readonly PlayStepProgramStep[]; readonly returnResolver?: StepResolver<Output, Return>; readonly __inputType?: (input: Input) => void; step<Name extends string, Value>(name: Name, resolver: StepResolver<Output, Value> | ConditionalStepResolver<Output, Value> | StepProgramResolver<Output, Value>): StepProgram<Input, Output & Record<Name, Value>, Return>; step<Name extends string, Value>(name: Name, resolver: StepResolver<Output, Value> | StepProgramResolver<Output, Value>, options: StepOptions<Output, Value>): StepProgram<Input, Output & Record<Name, Value | null>, Return>; return<Value>(resolver: StepResolver<Output, Value>): StepProgram<Input, Output, Value>; };",
2186
+ "export type StepProgramResolver<Input, Return> = { readonly kind: 'steps'; readonly steps: readonly PlayStepProgramStep[]; readonly returnResolver?: StepResolver<never, Return>; readonly __inputType?: (input: Input) => void };",
2187
+ "export type RunnableStepProgram<Input, Return> = Pick<StepProgram<Input, never, Return>, 'kind' | 'steps' | 'returnResolver' | '__inputType'>;",
2188
+ "export type RunnableColumnStepProgram<Return> = Pick<StepProgramResolver<unknown, Return>, 'kind' | 'steps' | 'returnResolver'>;",
2189
+ 'export type PlayStepProgramStep = { readonly name: string; readonly recompute?: boolean; readonly recomputeOnError?: boolean; readonly staleAfterSeconds?: number; readonly resolver: StepResolver<Record<string, unknown>, unknown> | ConditionalStepResolver<Record<string, unknown>, unknown> | StepProgramResolver<Record<string, unknown>, unknown> };',
2190
+ 'export type ColumnResolver<Row, Value> = StepResolver<Row, Value> | ConditionalStepResolver<Row, Value> | RunnableColumnStepProgram<Value>;',
2191
+ 'export type StepProgramOutput<TProgram> = TProgram extends StepProgram<unknown, infer Output, unknown> ? Output : never;',
2192
+ 'export type DatasetRowKey<InputRow extends object> = (keyof InputRow & string) | readonly (keyof InputRow & string)[] | ((row: InputRow, index: number) => string | number | readonly unknown[]);',
2193
+ 'export type DatasetDefinitionOptions<InputRow extends object> = { key?: DatasetRowKey<InputRow> };',
2194
+ `export type DatasetRunOptions<InputRow extends object> = { description?: ${cloudReferenceType('ctx.dataset.run.description')}; key?: DatasetRowKey<InputRow>; onRowError?: ${cloudReferenceType('ctx.dataset.run.onRowError')}; mode?: ${cloudReferenceType('ctx.dataset.run.mode')} };`,
2195
+ 'export type DatasetBuilder<InputRow extends object, OutputRow extends object> = {',
2196
+ ' withColumn<Name extends string, Value>(name: Name, resolver: ColumnResolver<OutputRow, Value>): DatasetBuilder<InputRow, OutputRow & Record<Name, Value>>;',
2197
+ ' withColumn<Name extends string, Value>(name: Name, definition: DatasetColumnDefinition<OutputRow, Value> & { readonly runIf: (row: OutputRow, index: number) => boolean | Promise<boolean> }): DatasetBuilder<InputRow, OutputRow & Record<Name, Value | null>>;',
2198
+ ' withColumn<Name extends string, Value>(name: Name, definition: DatasetColumnDefinition<OutputRow, Value>): DatasetBuilder<InputRow, OutputRow & Record<Name, Value>>;',
2199
+ ' withColumn<Name extends string, Value>(name: Name, resolver: StepResolver<OutputRow, Value> | RunnableColumnStepProgram<Value>, options: StepOptions<OutputRow, Value>): DatasetBuilder<InputRow, OutputRow & Record<Name, Value | null>>;',
2200
+ ' withColumns<Program extends StepProgram<OutputRow, object, unknown>>(program: Program): DatasetBuilder<InputRow, StepProgramOutput<Program>>;',
2201
+ ' step<Name extends string, Value>(name: Name, resolver: ColumnResolver<OutputRow, Value>): never;',
2202
+ ' run(options?: DatasetRunOptions<InputRow>): Promise<PlayDataset<OutputRow>>;',
2203
+ '};',
2204
+ 'export type PlayReferenceLike = { readonly playName: string; readonly name?: string } | { readonly name: string; readonly playName?: string };',
2205
+ 'export interface DeeplinePlayRuntimeContext {',
2206
+ ' csv<T = Record<string, unknown>>(path: string | CsvInput<T & object>, options?: CsvOptions): Promise<PlayDataset<T>>;',
2207
+ ' dataset<TSource extends PlayDatasetInput<object>>(key: string, items: TSource): DatasetBuilder<PlayDatasetRow<TSource> & object, PlayDatasetRow<TSource> & object>;',
2208
+ ' map<TSource extends PlayDatasetInput<object>>(key: string, items: TSource, options?: DatasetDefinitionOptions<PlayDatasetRow<TSource> & object>): never;',
2209
+ ` runSteps<TInput extends Record<string, unknown>, TOutput>(program: RunnableStepProgram<TInput, TOutput>, input: TInput, options?: { description?: ${cloudReferenceType('ctx.runSteps.options.description')} }): Promise<TOutput>;`,
2210
+ ' tools: { execute<K extends string>(request: ToolExecutionRequest<K>): Promise<ToolExecutionOutput<K>> };',
2211
+ ` customerDb: { query<TRow extends Record<string, unknown> = Record<string, unknown>>(statement: SqlQuery, options?: { maxRows?: ${cloudReferenceType('ctx.customerDb.query.options.maxRows')}; timeoutMs?: ${cloudReferenceType('ctx.customerDb.query.options.timeoutMs')} }): Promise<TRow[]> };`,
2212
+ ` tool<K extends string>(key: ${cloudReferenceType('ctx.tool.key')}, toolId: K, input: ${cloudReferenceType('ctx.tool.input')}, options?: { description?: ${cloudReferenceType('ctx.tool.options.description')} }): Promise<ToolExecutionOutput<K>>;`,
2213
+ ' step<T>(id: string, run: () => T | Promise<T>, options?: RuntimeStepOptions): Promise<T>;',
2214
+ " fetch(key: string, url: string | URL, init?: RequestInit & { headers?: HeadersInit & { 'Idempotency-Key'?: string; 'X-Idempotency-Key'?: string }; auth?: SecretAuth }, options?: FetchOptions): Promise<PlayFetchResponse>;",
2215
+ ' secrets: { get(name: string): SecretHandle; bearer(secret: SecretHandle): SecretAuth; header(header: string, secret: SecretHandle): SecretAuth };',
2216
+ ` runPlay<TOutput = unknown>(key: string, playRef: ${cloudReferenceType('ctx.runPlay.playRef')}, input: ${cloudReferenceType('ctx.runPlay.input')}, options: PlayCallOptions): Promise<TOutput>;`,
2217
+ ' log(message: string): void;',
2218
+ ` sleep(ms: ${cloudReferenceType('ctx.sleep.ms')}): Promise<void>;`,
2219
+ '}',
2220
+ "export type DefinePlayConfig<TInput, TOutput extends PlayReturnObject> = { id: string; description?: string; input: PlayInputContract<TInput>; run: (ctx: DeeplinePlayRuntimeContext, input: TInput) => Promise<TOutput>; bindings?: PlayBindings; billing?: PlayBindings['billing']; runtime?: PlayBindings['runtime']; compatibility?: PlayBindings['compatibility'] };",
2221
+ "export type DefinedPlay<TInput, TOutput extends PlayReturnObject> = ((ctx: DeeplinePlayRuntimeContext, input: TInput) => Promise<TOutput>) & { readonly name: string; readonly __inputType?: TInput; readonly __outputType?: TOutput; readonly runtime?: PlayBindings['runtime']; readonly compatibility?: PlayBindings['compatibility'] };",
2222
+ ] as const;