deepline 0.3.49 → 0.3.51

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 (31) hide show
  1. package/dist/bundling-sources/sdk/src/index.ts +1 -0
  2. package/dist/bundling-sources/sdk/src/play.ts +1 -0
  3. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  4. package/dist/bundling-sources/sdk/src/types.ts +2 -0
  5. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +1 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +106 -89
  7. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +0 -2
  8. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +52 -21
  9. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +45 -5
  10. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +11 -3
  11. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +0 -2
  12. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +11 -0
  13. package/dist/bundling-sources/shared_libs/play-runtime/secret-capability.ts +5 -1
  14. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +1 -14
  15. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/contract.ts +17 -7
  16. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +0 -1
  17. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +112 -5
  18. package/dist/bundling-sources/shared_libs/security/safe-fetch.ts +6 -1
  19. package/dist/cli/index.js +837 -3147
  20. package/dist/cli/index.mjs +704 -3010
  21. package/dist/{compiler-manifest-CbzdZrJj.d.mts → compiler-manifest-B47AA7As.d.mts} +46 -4
  22. package/dist/{compiler-manifest-CbzdZrJj.d.ts → compiler-manifest-B47AA7As.d.ts} +46 -4
  23. package/dist/index.d.mts +151 -149
  24. package/dist/index.d.ts +151 -149
  25. package/dist/index.js +1515 -117
  26. package/dist/index.mjs +1514 -117
  27. package/dist/install-integrity.json +2 -2
  28. package/dist/plays/bundle-play-file.d.mts +2 -2
  29. package/dist/plays/bundle-play-file.d.ts +2 -2
  30. package/dist/plays/bundle-play-file.mjs +5 -2614
  31. package/package.json +2 -1
@@ -36,8 +36,6 @@ type ValidatedRuntimeTestFaultHeader =
36
36
  export type RuntimeTestPolicyOverrides = {
37
37
  /** Opt-in bounded runner map latency profile for local/preview diagnosis. */
38
38
  mapLatencyProfile?: boolean;
39
- /** Exercise provider pacing during fixture runs without dispatching provider traffic. */
40
- enforceFixtureProviderPacing?: boolean;
41
39
  receiptLeaseTtlMs?: number;
42
40
  sheetAttemptLeaseMs?: number;
43
41
  heartbeatIntervalMs?: number;
@@ -258,8 +256,7 @@ function parseRuntimeTestPolicyOverrides(
258
256
  (key) =>
259
257
  !RUNTIME_TEST_POLICY_MS_FIELDS.has(key) &&
260
258
  key !== 'workBudgetYieldLimits' &&
261
- key !== 'mapLatencyProfile' &&
262
- key !== 'enforceFixtureProviderPacing',
259
+ key !== 'mapLatencyProfile',
263
260
  );
264
261
  if (unknownKeys.length > 0) {
265
262
  return {
@@ -276,16 +273,6 @@ function parseRuntimeTestPolicyOverrides(
276
273
  }
277
274
  overrides.mapLatencyProfile = record.mapLatencyProfile;
278
275
  }
279
- if ('enforceFixtureProviderPacing' in record) {
280
- if (typeof record.enforceFixtureProviderPacing !== 'boolean') {
281
- return {
282
- error:
283
- 'testPolicyOverrides.enforceFixtureProviderPacing must be a boolean.',
284
- };
285
- }
286
- overrides.enforceFixtureProviderPacing =
287
- record.enforceFixtureProviderPacing;
288
- }
289
276
  for (const field of RUNTIME_TEST_POLICY_MS_FIELDS) {
290
277
  if (!(field in record)) continue;
291
278
  const parsed = readPositiveIntegerField({
@@ -105,15 +105,25 @@ export type ToolResultReceipts = {
105
105
  }): Promise<void>;
106
106
  };
107
107
 
108
+ export type AlwaysFreshToolCallDispatch = {
109
+ call: ToolCallInput;
110
+ /** An always-fresh call must not claim a provider idempotency identity. */
111
+ providerOperationKey: null;
112
+ /** Receiptless means structurally absent, not a nullable lease. */
113
+ receipt?: never;
114
+ };
115
+
116
+ export type ReceiptBackedToolCallDispatch = {
117
+ call: ToolCallInput;
118
+ providerOperationKey: string;
119
+ receipt: ToolCallReceiptLease;
120
+ };
121
+
108
122
  /** Direct and map execution are Adapter choices, never separate public jobs. */
109
123
  export type ToolCallDispatcher = {
110
- dispatch(input: {
111
- call: ToolCallInput;
112
- /** Null means the adapter must not emit a provider-idempotency identity. */
113
- providerOperationKey: string | null;
114
- /** Null means this is a receiptless, always-fresh physical call. */
115
- receipt: ToolCallReceiptLease | null;
116
- }): Promise<ToolExecuteResult>;
124
+ dispatch(
125
+ input: AlwaysFreshToolCallDispatch | ReceiptBackedToolCallDispatch,
126
+ ): Promise<ToolExecuteResult>;
117
127
  };
118
128
 
119
129
  export type ToolCallDependencies = {
@@ -160,7 +160,6 @@ export function createToolCallJob(
160
160
  return await dependencies.dispatcher.dispatch({
161
161
  call: input,
162
162
  providerOperationKey: null,
163
- receipt: null,
164
163
  });
165
164
  }
166
165
 
@@ -7,9 +7,11 @@ import type { ToolExecutionErrorSchemaVersion } from './tool-execution-error';
7
7
  import type { PlayDataset, PlayDatasetInput, PlayDatasetRow } from './dataset';
8
8
 
9
9
  export const LEGACY_PLAY_AUTHORING_CONTRACT_EDITION = 1 as const;
10
- export const PLAY_AUTHORING_CONTRACT_EDITION = 4 as const;
10
+ export const PLAY_AUTHORING_CONTRACT_EDITION = 5 as const;
11
11
  export const PLAY_AUTHORING_INPUT_SCHEMA_SNAPSHOT_EDITION = 3 as const;
12
- export const SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS = [1, 2, 3, 4] as const;
12
+ export const SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS = [
13
+ 1, 2, 3, 4, 5,
14
+ ] as const;
13
15
 
14
16
  export type PlayAuthoringContractEdition =
15
17
  (typeof SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS)[number];
@@ -49,6 +51,47 @@ export const PLAY_AUTHORING_CONTRACT_CHANGELOG = [
49
51
  newWritesEnd: null,
50
52
  readerRemoval: null,
51
53
  },
54
+ {
55
+ edition: 5,
56
+ changed:
57
+ 'ctx.fetch throws a typed, redacted CtxFetchHttpError for non-2xx responses. Editions 1–4 continue to return the response record for every HTTP status.',
58
+ compatibilityOwner: 'Plays Runtime',
59
+ newWritesEnd: null,
60
+ readerRemoval: null,
61
+ },
62
+ ] as const;
63
+
64
+ /**
65
+ * Customer-visible runtime capabilities that are not expressible as one
66
+ * `ctx.*` signature. The generated authoring reference renders this inventory
67
+ * directly; add a row here alongside any new supported runtime global or
68
+ * execution-boundary guarantee.
69
+ */
70
+ export const PLAY_AUTHORING_RUNTIME_CAPABILITIES = [
71
+ {
72
+ capability: 'Durable external I/O',
73
+ surface: '`ctx.fetch`, `ctx.tools.execute`, `ctx.step`, `ctx.runPlay`',
74
+ contract:
75
+ 'Use a `ctx.*` primitive for external work. Each primitive owns durable receipt identity and replay; raw I/O in an authored handler does not.',
76
+ },
77
+ {
78
+ capability: 'Web Crypto',
79
+ surface: '`crypto.subtle`',
80
+ contract:
81
+ 'WebCrypto is available for standards-based signing, verification, encryption, and key import. Keep private material in `ctx.secrets`; `docs-examples/sdk-v2/github-app-jwt.play.ts` signs an RS256 GitHub App JWT and uses `staleAfterSeconds: 0` for its time-varying auth exchange.',
82
+ },
83
+ {
84
+ capability: 'Workspace secrets',
85
+ surface: '`ctx.secrets.get`, `.bearer`, `.header`',
86
+ contract:
87
+ 'Declare the secret at the Play boundary, read it only at runtime, and never return or log it. Secret-bearing HTTP requests require HTTPS.',
88
+ },
89
+ {
90
+ capability: 'Freshness',
91
+ surface: '`staleAfterSeconds` on durable calls',
92
+ contract:
93
+ 'This is call-receipt freshness: omitted/null reuses forever, zero always executes, and a positive integer is a TTL in seconds. It never changes dataset or request identity.',
94
+ },
52
95
  ] as const;
53
96
 
54
97
  export const PLAY_AUTHORING_CONTRACT_ISSUE_CODES = [
@@ -78,6 +121,7 @@ export const PLAY_AUTHORING_CONTRACT_ISSUE_CODES = [
78
121
  'play_authoring_fetch_secret_requires_tls',
79
122
  'play_authoring_fetch_idempotency_required',
80
123
  'play_authoring_fetch_key_reused_in_loop',
124
+ 'play_authoring_fetch_http_error_branch',
81
125
  'play_authoring_binding_invalid',
82
126
  'play_authoring_input_schema_unresolved',
83
127
  'tool_response_raw_access',
@@ -842,12 +886,24 @@ export type PlayAuthoringRuntimeStepOptions = {
842
886
  staleAfterSeconds?: DurableCallStaleAfterSeconds;
843
887
  };
844
888
 
889
+ /**
890
+ * Durable freshness for one `ctx.fetch` call. The key identifies the request;
891
+ * `staleAfterSeconds` controls when that completed request may be reused across
892
+ * Play runs. Omit it (or pass `null`) to reuse indefinitely, pass `0` to
893
+ * execute on every new run, or pass a positive number of seconds for a TTL.
894
+ *
895
+ * Use this for polling or periodically refreshing one external resource. It
896
+ * does not change dataset row identity.
897
+ *
898
+ */
845
899
  export type PlayAuthoringFetchOptions = {
846
900
  staleAfterSeconds?: DurableCallStaleAfterSeconds;
901
+ /** Run through Deepline's guarded outbound path without retaining a response receipt or checkpoint. Use this for short-lived credential exchanges or other response data that should stay in the running Play only. */
902
+ transient?: boolean;
847
903
  };
848
904
 
849
905
  /**
850
- * The value `ctx.fetch(...)` resolves to: a plain durable record, not a WHATWG `Response`. The body is read once at request time so the call can be checkpointed and replayed, so `bodyText` and `json` are already-materialized properties. There is no `.json()`, `.text()`, or `.body` to await — `await res.json()` is a type error, not a typing problem.
906
+ * A durable response record, not a WHATWG `Response`: read the already-materialized `bodyText` and `json` properties; do not call `.json()`, `.text()`, or `.body`.
851
907
  *
852
908
  * @sdkReference runtime 175 PlayFetchResponse
853
909
  */
@@ -870,6 +926,55 @@ export type PlayAuthoringFetchResponse = {
870
926
  json: unknown | null;
871
927
  };
872
928
 
929
+ /**
930
+ * Edition 5+ `ctx.fetch` error for a non-2xx response. Its full readable body is secret-redacted; editions 1–4 retain `PlayFetchResponse { ok: false }`.
931
+ *
932
+ * @sdkReference runtime 178 CtxFetchHttpError
933
+ */
934
+ export class CtxFetchHttpError extends Error {
935
+ /**
936
+ * Play source and the runtime are separately bundled. Recognize the stable
937
+ * public error code so `instanceof` works across that boundary as well.
938
+ */
939
+ static [Symbol.hasInstance](value: unknown): boolean {
940
+ return (
941
+ value !== null &&
942
+ typeof value === 'object' &&
943
+ (value as { code?: unknown }).code === 'CTX_FETCH_HTTP_ERROR'
944
+ );
945
+ }
946
+
947
+ /** Stable machine-readable HTTP-failure code. */
948
+ readonly code = 'CTX_FETCH_HTTP_ERROR' as const;
949
+ /** Upstream HTTP status. */
950
+ readonly status: number;
951
+ /** Upstream HTTP status text. */
952
+ readonly statusText: string;
953
+ /** Final response URL after redirects. */
954
+ readonly url: string;
955
+ /** Secret-redacted response headers. */
956
+ readonly headers: Record<string, string>;
957
+ /** Complete secret-redacted response body. */
958
+ readonly bodyText: string;
959
+ /** Eagerly parsed secret-redacted JSON, or null. */
960
+ readonly json: unknown | null;
961
+
962
+ /** Build the error from the durable response record. */
963
+ constructor(readonly response: PlayAuthoringFetchResponse) {
964
+ const body = response.bodyText || 'empty response body';
965
+ super(
966
+ `ctx.fetch(${response.url}) returned HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ''}: ${body}`,
967
+ );
968
+ this.name = 'CtxFetchHttpError';
969
+ this.status = response.status;
970
+ this.statusText = response.statusText;
971
+ this.url = response.url;
972
+ this.headers = response.headers;
973
+ this.bodyText = response.bodyText;
974
+ this.json = response.json;
975
+ }
976
+ }
977
+
873
978
  export type PlayAuthoringCustomerDbQueryOptions = {
874
979
  maxRows?: number;
875
980
  timeoutMs?: number;
@@ -1008,7 +1113,8 @@ export interface PlayAuthoringRuntimeContext {
1008
1113
  ): Promise<T>;
1009
1114
 
1010
1115
  /**
1011
- * Execute a durable, replay-safe HTTP request.
1116
+ * Execute a guarded HTTP request. By default it is durable and replay-safe; `staleAfterSeconds` governs only that completed call receipt, never dataset/request identity. Pass `{ transient: true }` for short-lived credential exchanges or other response data that must not be retained in a receipt or checkpoint. Edition 5+ throws `CtxFetchHttpError` for non-2xx; catch it only when the Play intentionally recovers, otherwise let it fail the Play. Editions 1–4 retain their previous response projections.
1117
+ *
1012
1118
  * @sdkReference runtime 170 ctx.fetch(key, url, init)
1013
1119
  */
1014
1120
  fetch(
@@ -2541,8 +2647,9 @@ export const PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
2541
2647
  "export type PlayCallExecution = 'inline';",
2542
2648
  `export type PlayCallOptions = { description: ${cloudReferenceType('ctx.runPlay.options.description')}; execution?: ${cloudReferenceType('ctx.runPlay.options.execution')}; timeoutMs?: ${cloudReferenceType('ctx.runPlay.options.timeoutMs')} };`,
2543
2649
  `export type RuntimeStepOptions = { semanticKey?: ${cloudReferenceType('ctx.step.semanticKey')}; staleAfterSeconds?: ${cloudReferenceType('ctx.step.staleAfterSeconds')} };`,
2544
- `export type FetchOptions = { staleAfterSeconds?: ${cloudReferenceType('ctx.fetch.staleAfterSeconds')} };`,
2650
+ `export type FetchOptions = { staleAfterSeconds?: ${cloudReferenceType('ctx.fetch.staleAfterSeconds')}; transient?: boolean };`,
2545
2651
  'export type PlayFetchResponse = { ok: boolean; status: number; statusText: string; url: string; headers: Record<string, string>; bodyText: string; json: unknown | null };',
2652
+ "export declare class CtxFetchHttpError extends Error { readonly code: 'CTX_FETCH_HTTP_ERROR'; readonly response: PlayFetchResponse; readonly status: number; readonly statusText: string; readonly url: string; readonly headers: Record<string, string>; readonly bodyText: string; readonly json: unknown | null; }",
2546
2653
  'export type StepResolver<Row, Value> = (row: Row, ctx: DeeplinePlayRuntimeContext, index: number, previousCell?: PreviousCell<Value>) => Value | Promise<Value>;',
2547
2654
  'export type DatasetColumnRunInput<Row, Value> = { readonly row: Row; readonly ctx: DeeplinePlayRuntimeContext; readonly index: number; readonly previousCell?: PreviousCell<Value> };',
2548
2655
  'export type DatasetColumnDefinition<Row, Value> = { readonly run: (input: DatasetColumnRunInput<Row, Value>) => Value | Promise<Value>; readonly runIf?: (row: Row, index: number) => boolean | Promise<boolean> };',
@@ -15,6 +15,8 @@ export type SafeFetchOptions = {
15
15
  sensitiveHeaders?: Iterable<string>;
16
16
  /** Drop every caller-supplied header when a redirect changes origin. */
17
17
  stripHeadersOnCrossOriginRedirect?: boolean;
18
+ /** Headers the trusted runtime may add after caller headers are stripped. */
19
+ headersOnCrossOriginRedirect?: HeadersInit;
18
20
  };
19
21
 
20
22
  function removeHeader(headers: Headers, name: string) {
@@ -32,6 +34,7 @@ function requestInitForRedirect(
32
34
  status: number,
33
35
  sensitiveHeaders: Iterable<string>,
34
36
  stripHeadersOnCrossOriginRedirect: boolean,
37
+ headersOnCrossOriginRedirect: HeadersInit | undefined,
35
38
  ): RequestInit {
36
39
  let headers = new Headers(init.headers);
37
40
  let method = String(init.method ?? 'GET').toUpperCase();
@@ -57,7 +60,7 @@ function requestInitForRedirect(
57
60
  // Callers that can construct credentials from plaintext secrets cannot
58
61
  // reliably identify every transformed value. Do not forward any caller
59
62
  // header across an origin boundary in that trust model.
60
- headers = new Headers();
63
+ headers = new Headers(headersOnCrossOriginRedirect);
61
64
  } else {
62
65
  removeHeader(headers, 'authorization');
63
66
  removeHeader(headers, 'cookie');
@@ -88,6 +91,7 @@ export async function safePublicFetch(
88
91
  const sensitiveHeaders = options.sensitiveHeaders ?? [];
89
92
  const stripHeadersOnCrossOriginRedirect =
90
93
  options.stripHeadersOnCrossOriginRedirect === true;
94
+ const headersOnCrossOriginRedirect = options.headersOnCrossOriginRedirect;
91
95
  let currentUrl = assertPublicHttpUrl(input);
92
96
  let currentInit: RequestInit = {
93
97
  ...init,
@@ -135,6 +139,7 @@ export async function safePublicFetch(
135
139
  response.status,
136
140
  sensitiveHeaders,
137
141
  stripHeadersOnCrossOriginRedirect,
142
+ headersOnCrossOriginRedirect,
138
143
  );
139
144
  currentUrl = nextUrl;
140
145
  }