deepline 0.3.7 → 0.3.8

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.
@@ -1033,7 +1033,7 @@ var SDK_RELEASE = {
1033
1033
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
1034
1034
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1035
1035
  // getters keep their established compatibility behavior.
1036
- version: "0.3.7",
1036
+ version: "0.3.8",
1037
1037
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
1038
1038
  contracts: {
1039
1039
  api: {
@@ -2006,10 +2006,30 @@ function redactSecretLikeString(value) {
2006
2006
  function createSecretRedactionContext(initialValues = []) {
2007
2007
  const exactSecrets = /* @__PURE__ */ new Set();
2008
2008
  function register(value) {
2009
- if (value.length >= 4) exactSecrets.add(value);
2009
+ if (value.length > 0) exactSecrets.add(value);
2010
2010
  }
2011
2011
  for (const value of initialValues) register(value);
2012
- function redactString2(value) {
2012
+ function containsRegisteredSecret(value, {
2013
+ includeEncoded = false,
2014
+ minimumLength = 1
2015
+ } = {}) {
2016
+ for (const secret of exactSecrets) {
2017
+ if (secret.length < minimumLength) continue;
2018
+ if (value.includes(secret)) return true;
2019
+ if (includeEncoded) {
2020
+ try {
2021
+ const encoded = encodeURIComponent(secret);
2022
+ if (encoded !== secret && value.includes(encoded)) return true;
2023
+ } catch {
2024
+ }
2025
+ }
2026
+ }
2027
+ return false;
2028
+ }
2029
+ function matchesRegisteredSecret(value) {
2030
+ return exactSecrets.has(value);
2031
+ }
2032
+ function redactRegisteredSecrets(value) {
2013
2033
  let output2 = value;
2014
2034
  for (const secret of exactSecrets) {
2015
2035
  output2 = output2.replace(
@@ -2027,6 +2047,10 @@ function createSecretRedactionContext(initialValues = []) {
2027
2047
  } catch {
2028
2048
  }
2029
2049
  }
2050
+ return output2;
2051
+ }
2052
+ function redactString2(value) {
2053
+ const output2 = redactRegisteredSecrets(value);
2030
2054
  return redactSecretLikeString(output2);
2031
2055
  }
2032
2056
  function redact(value) {
@@ -2059,6 +2083,9 @@ function createSecretRedactionContext(initialValues = []) {
2059
2083
  }
2060
2084
  return {
2061
2085
  register,
2086
+ containsRegisteredSecret,
2087
+ matchesRegisteredSecret,
2088
+ redactRegisteredSecrets,
2062
2089
  redactString: redactString2,
2063
2090
  redactKnownSecrets,
2064
2091
  redact
@@ -16745,8 +16772,11 @@ var PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
16745
16772
  ` secrets?: readonly ${cloudReferenceType("bindings.secrets[]")}[];`,
16746
16773
  "};",
16747
16774
  "declare const SECRET_HANDLE_BRAND: unique symbol;",
16775
+ "declare const SECRET_PROMISE_BRAND: unique symbol;",
16748
16776
  "export type SecretHandle = { readonly [SECRET_HANDLE_BRAND]: never; readonly name: string; toString(): string; toJSON(): never };",
16749
- "export type SecretAuth = { readonly kind: 'bearer' | 'header'; readonly secret: SecretHandle; readonly header?: string };",
16777
+ "export type SecretPromise = Promise<string> & { readonly [SECRET_PROMISE_BRAND]: never };",
16778
+ "export type SecretValue = SecretHandle;",
16779
+ "export type SecretAuth = { readonly kind: 'bearer' | 'header'; readonly secret: string | SecretPromise | SecretHandle; readonly header?: string };",
16750
16780
  "export type SecretAuthInput = SecretAuth | readonly SecretAuth[];",
16751
16781
  "export type PlayInputContract<TInput> = { readonly schema: Record<string, unknown>; readonly __inputType?: TInput };",
16752
16782
  "export type PlayReturnObject = Record<string, unknown> & { readonly _metadata?: never };",
@@ -16797,7 +16827,7 @@ var PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
16797
16827
  ` 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>>;`,
16798
16828
  " step<T>(id: string, run: () => T | Promise<T>, options?: RuntimeStepOptions): Promise<T>;",
16799
16829
  " fetch(key: string, url: string | URL, init?: RequestInit & { headers?: HeadersInit & { 'Idempotency-Key'?: string; 'X-Idempotency-Key'?: string }; auth?: SecretAuthInput }, options?: FetchOptions): Promise<PlayFetchResponse>;",
16800
- " secrets: { get(name: string): SecretHandle; bearer(secret: SecretHandle): SecretAuth; header(header: string, secret: SecretHandle): SecretAuth };",
16830
+ " secrets: { get(name: string): SecretPromise; bearer(secret: string | SecretPromise | SecretHandle): SecretAuth; header(header: string, secret: string | SecretPromise | SecretHandle): SecretAuth };",
16801
16831
  ` runPlay<TOutput = unknown>(key: string, playRef: ${cloudReferenceType("ctx.runPlay.playRef")}, input: ${cloudReferenceType("ctx.runPlay.input")}, options: PlayCallOptions): Promise<TOutput>;`,
16802
16832
  " log(message: string): void;",
16803
16833
  ` sleep(ms: ${cloudReferenceType("ctx.sleep.ms")}): Promise<void>;`,
@@ -16938,15 +16968,118 @@ function listPlayFileExports(sourceCode) {
16938
16968
  return exports;
16939
16969
  }
16940
16970
 
16941
- // ../shared_libs/plays/docflow.ts
16942
- var MERMAID_NODE_ATTRIBUTES = ["label", "type", "in", "out", "arm"];
16943
- var LEGACY_DOCFLOW_ATTRIBUTES = ["id", ...MERMAID_NODE_ATTRIBUTES];
16944
-
16945
16971
  // ../shared_libs/plays/secret-guardrails.ts
16946
16972
  var SECRET_ENV_PATTERN = /\bprocess(?:\.env|\[['"]env['"]\])(?:\.|\[['"])([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY|ACCESS[_-]?KEY)[A-Z0-9_]*)(?:['"]\])?/g;
16947
16973
  var PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/;
16948
16974
  var BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
16949
16975
  var ASSIGNMENT_SECRET_LITERAL_PATTERN = /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
16976
+ var SECRET_AUTH_LITERAL_FINDING = "literal credential passed to ctx.secrets auth helper";
16977
+ function skipQuoted(source, start) {
16978
+ const quote = source[start];
16979
+ let index = start + 1;
16980
+ while (index < source.length) {
16981
+ if (source[index] === "\\") {
16982
+ index += 2;
16983
+ } else if (source[index] === quote) {
16984
+ return index + 1;
16985
+ } else {
16986
+ index += 1;
16987
+ }
16988
+ }
16989
+ return source.length;
16990
+ }
16991
+ function skipTrivia(source, start) {
16992
+ let index = start;
16993
+ while (index < source.length) {
16994
+ if (/\s/.test(source[index])) {
16995
+ index += 1;
16996
+ } else if (source.startsWith("//", index)) {
16997
+ index = source.indexOf("\n", index + 2);
16998
+ if (index === -1) return source.length;
16999
+ } else if (source.startsWith("/*", index)) {
17000
+ index = source.indexOf("*/", index + 2);
17001
+ if (index === -1) return source.length;
17002
+ index += 2;
17003
+ } else {
17004
+ return index;
17005
+ }
17006
+ }
17007
+ return index;
17008
+ }
17009
+ function consumeIdentifier(source, start, expected) {
17010
+ return source.startsWith(expected, start) && !/[A-Za-z0-9_$]/.test(source[start - 1] ?? "") && !/[A-Za-z0-9_$]/.test(source[start + expected.length] ?? "") ? start + expected.length : void 0;
17011
+ }
17012
+ function consumeMember(source, start, expected) {
17013
+ let index = skipTrivia(source, start);
17014
+ if (source[index] === ".") {
17015
+ return consumeIdentifier(source, skipTrivia(source, index + 1), expected);
17016
+ }
17017
+ if (source[index] !== "[") return void 0;
17018
+ index = skipTrivia(source, index + 1);
17019
+ if (source[index] !== "'" && source[index] !== '"') return void 0;
17020
+ const end = skipQuoted(source, index);
17021
+ if (source.slice(index + 1, end - 1) !== expected) return void 0;
17022
+ index = skipTrivia(source, end);
17023
+ return source[index] === "]" ? index + 1 : void 0;
17024
+ }
17025
+ function skipExpression(source, start) {
17026
+ let index = start;
17027
+ let depth = 0;
17028
+ while (index < source.length) {
17029
+ const char = source[index];
17030
+ if (char === "'" || char === '"' || char === "`") {
17031
+ index = skipQuoted(source, index);
17032
+ continue;
17033
+ }
17034
+ if (source.startsWith("//", index) || source.startsWith("/*", index)) {
17035
+ index = skipTrivia(source, index);
17036
+ continue;
17037
+ }
17038
+ if (char === "(" || char === "[" || char === "{") {
17039
+ depth += 1;
17040
+ } else if (char === ")" || char === "]" || char === "}") {
17041
+ if (depth === 0) return index;
17042
+ depth -= 1;
17043
+ } else if (char === "," && depth === 0) {
17044
+ return index;
17045
+ }
17046
+ index += 1;
17047
+ }
17048
+ return index;
17049
+ }
17050
+ function isDirectStringLiteral(source, start) {
17051
+ const quote = source[start];
17052
+ if (quote !== "'" && quote !== '"' && quote !== "`") return false;
17053
+ const end = skipQuoted(source, start);
17054
+ return quote !== "`" || !source.slice(start, end).includes("${");
17055
+ }
17056
+ function hasLiteralSecretAuthCredential(source) {
17057
+ for (let index = 0; index < source.length; index += 1) {
17058
+ const char = source[index];
17059
+ if (char === "'" || char === '"' || char === "`") {
17060
+ index = skipQuoted(source, index) - 1;
17061
+ continue;
17062
+ }
17063
+ if (source.startsWith("//", index) || source.startsWith("/*", index)) {
17064
+ index = skipTrivia(source, index) - 1;
17065
+ continue;
17066
+ }
17067
+ const afterCtx = consumeIdentifier(source, index, "ctx");
17068
+ if (!afterCtx) continue;
17069
+ const afterSecrets = consumeMember(source, afterCtx, "secrets");
17070
+ if (!afterSecrets) continue;
17071
+ const afterHeader = consumeMember(source, afterSecrets, "header");
17072
+ const helper = afterHeader ? "header" : "bearer";
17073
+ const afterHelper = afterHeader ?? consumeMember(source, afterSecrets, "bearer");
17074
+ if (!afterHelper) continue;
17075
+ const afterOpen = skipTrivia(source, afterHelper);
17076
+ if (source[afterOpen] !== "(") continue;
17077
+ const firstArgument = skipTrivia(source, afterOpen + 1);
17078
+ const credential = helper === "header" ? skipTrivia(source, skipExpression(source, firstArgument) + 1) : firstArgument;
17079
+ if (isDirectStringLiteral(source, credential)) return true;
17080
+ }
17081
+ return false;
17082
+ }
16950
17083
  function collectInlineSecretFindings(sourceCode) {
16951
17084
  const findings = [];
16952
17085
  for (const match of sourceCode.matchAll(SECRET_ENV_PATTERN)) {
@@ -16958,6 +17091,9 @@ function collectInlineSecretFindings(sourceCode) {
16958
17091
  if (ASSIGNMENT_SECRET_LITERAL_PATTERN.test(sourceCode)) {
16959
17092
  findings.push("secret-looking assignment literal");
16960
17093
  }
17094
+ if (hasLiteralSecretAuthCredential(sourceCode)) {
17095
+ findings.push(SECRET_AUTH_LITERAL_FINDING);
17096
+ }
16961
17097
  return [...new Set(findings)];
16962
17098
  }
16963
17099
 
@@ -25314,6 +25450,14 @@ Concepts:
25314
25450
  bundle local .play.ts files for development workflows.
25315
25451
  Running a local file does not make it live; use publish or set-live for that.
25316
25452
 
25453
+ Authoring:
25454
+ Use normal TypeScript interpolation for human-facing strings:
25455
+ const readyMessage = \`Put \${input.title} through to send-ready.\`;
25456
+ An authored diagram is optional. Docflow parses only an explicit
25457
+ /** @mermaid ... */ block and its // @mermaid-node annotations; ordinary
25458
+ prose comments are never Docflow syntax. When Docflow is enabled, plays check
25459
+ gives missing diagrams a non-blocking visualization warning.
25460
+
25317
25461
  Common commands:
25318
25462
  deepline plays search email --json
25319
25463
  deepline plays describe prebuilt/person-linkedin-to-email --json
@@ -101,13 +101,13 @@ type PlayDocflow = {
101
101
  nodes: PlayDocflowNode[];
102
102
  edges: PlayDocflowEdge[];
103
103
  bindings: PlayDocflowBinding[];
104
- /** Authoring syntax used by the source file. Absent on older persisted graphs. */
105
- syntax?: 'docflow' | 'mermaid';
104
+ /** Authoring syntax used by the source file. */
105
+ syntax?: 'mermaid';
106
106
  /** Normalized Mermaid text, ready to pass directly to a Mermaid renderer. */
107
107
  mermaidSource?: string;
108
108
  /**
109
- * Mermaid `subgraph` loop regions. Optional so older persisted graphs stay
110
- * valid. Only populated for the Mermaid syntax; legacy `docflow` has none.
109
+ * Mermaid `subgraph` loop regions. Optional for persisted graphs that have
110
+ * no authored regions.
111
111
  */
112
112
  subgraphs?: PlayDocflowSubgraph[];
113
113
  /** Mermaid directives accepted by the parser but not applied by React Flow. */
@@ -1017,7 +1017,7 @@ declare function isProviderUnavailable(error: unknown): error is ProviderUnavail
1017
1017
  /** @deprecated Use isProviderUnavailable. */
1018
1018
  declare const isProviderWaterfallUnavailableError: typeof isProviderUnavailable;
1019
1019
 
1020
- declare const SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS: readonly [1, 2, 3];
1020
+ declare const SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS: readonly [1, 2, 3, 4];
1021
1021
  type PlayAuthoringContractEdition = (typeof SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS)[number];
1022
1022
  type PlaySqlListenerOperation = 'INSERT' | 'UPDATE' | 'DELETE';
1023
1023
  type PlayStandardWebhookHeaderFamily = 'standard' | 'svix';
@@ -1146,8 +1146,10 @@ type PlaySqlQuery = {
1146
1146
  readonly values: readonly unknown[];
1147
1147
  };
1148
1148
  declare const PLAY_SECRET_HANDLE_BRAND: unique symbol;
1149
+ declare const PLAY_SECRET_PROMISE_BRAND: unique symbol;
1149
1150
  /**
1150
- * An opaque reference to a workspace secret, returned by `ctx.secrets.get`. The handle never carries the value into play code: it stringifies to `[secret:NAME]` and throws on `JSON.stringify`, so a secret cannot reach a play variable, a log line, a dataset cell, or a replay artifact even by accident. Only the runtime resolves it, at the moment it attaches the request header.
1151
+ * An opaque reference to a workspace secret used by legacy authoring-contract
1152
+ * editions. New Plays receive plaintext strings from `ctx.secrets.get`.
1151
1153
  *
1152
1154
  * @sdkReference runtime 176 SecretHandle
1153
1155
  */
@@ -1160,6 +1162,12 @@ type PlaySecretHandle = {
1160
1162
  /** Always throws. A secret handle is deliberately not serializable. */
1161
1163
  toJSON(): never;
1162
1164
  };
1165
+ /** A secret-reading promise returned only by `ctx.secrets.get`. */
1166
+ type PlaySecretPromise = Promise<string> & {
1167
+ readonly [PLAY_SECRET_PROMISE_BRAND]: never;
1168
+ };
1169
+ /** An opaque legacy secret handle retained for earlier Play artifacts. */
1170
+ type PlaySecretValue = PlaySecretHandle;
1163
1171
  /**
1164
1172
  * One resolved authentication scheme, built by `ctx.secrets.bearer` or `ctx.secrets.header` and attached to a request through `init.auth`.
1165
1173
  *
@@ -1168,8 +1176,8 @@ type PlaySecretHandle = {
1168
1176
  type PlaySecretAuth = {
1169
1177
  /** `bearer` sends `Authorization: Bearer <value>`; `header` sends a named header. */
1170
1178
  readonly kind: 'bearer' | 'header';
1171
- /** The handle whose value the runtime attaches. */
1172
- readonly secret: PlaySecretHandle;
1179
+ /** The value whose bytes the runtime attaches. */
1180
+ readonly secret: string | PlaySecretPromise | PlaySecretValue;
1173
1181
  /** Header name, set only when `kind` is `header`. */
1174
1182
  readonly header?: string;
1175
1183
  };
@@ -1181,10 +1189,10 @@ type PlaySecretAuthInput = PlaySecretAuth | readonly PlaySecretAuth[];
1181
1189
  * @sdkReference runtime 174 SecretAwareRequestInit
1182
1190
  */
1183
1191
  type PlaySecretAwareRequestInit = Omit<RequestInit, 'headers'> & {
1184
- /** Ordinary request headers, recorded in the durable receipt. Never interpolate a secret value here use `auth`. */
1192
+ /** Ordinary request headers, recorded in the durable receipt with any resolved Play secret value redacted. Prefer `auth` for credentials: it enforces HTTPS and keeps the auth header out of the receipt. */
1185
1193
  headers?: HeadersInit;
1186
1194
  /**
1187
- * One or more secret-backed authentication headers for this request. Pass a single `ctx.secrets` auth for the common case, or an array when an API requires multiple credentialed headers — for example, Supabase with both `apikey` and `Authorization`. Every secret is resolved only while the request is attached, never stored in the durable receipt. Each auth entry must target a distinct header.
1195
+ * One or more credentialed headers for this request. Pass a single `ctx.secrets` auth for the common case, or an array when an API requires multiple credentialed headers — for example, Supabase with both `apikey` and `Authorization`. Auth-helper requests require HTTPS and omit the credential from the durable receipt. Each auth entry must target a distinct header.
1188
1196
  */
1189
1197
  auth?: PlaySecretAuthInput;
1190
1198
  };
@@ -1453,23 +1461,26 @@ interface PlayAuthoringRuntimeContext {
1453
1461
  fetch(key: string, url: string | URL, init?: PlaySecretAwareRequestInit, options?: PlayAuthoringFetchOptions): Promise<PlayAuthoringFetchResponse>;
1454
1462
  secrets: {
1455
1463
  /**
1456
- * Reference a workspace secret by name without reading its value. This is the only supported way to authenticate an outbound request from a Play: `process.env.X` is rejected at check time because an env read puts the raw value in a play variable, where it can reach a log line or a replay artifact. A handle cannot — pass it to `bearer` or `header` and the runtime resolves it only while attaching the header. Names are uppercased; manage stored values with `deepline secrets set` / `deepline secrets list`.
1464
+ * Read an allowed workspace secret inside the running Play; do not log or return it. Declare uppercase names in top-level `secrets`.
1457
1465
  *
1458
1466
  * @sdkReference runtime 171 ctx.secrets.get(name)
1459
1467
  */
1460
- get(name: string): PlaySecretHandle;
1468
+ get(name: string): PlaySecretPromise;
1461
1469
  /**
1462
- * Send the secret as `Authorization: Bearer <value>`.
1470
+ * Send a credential as `Authorization: Bearer <value>`. Await `get` first;
1471
+ * its direct promise remains accepted for source compatibility, while other
1472
+ * promises are rejected.
1463
1473
  *
1464
1474
  * @sdkReference runtime 172 ctx.secrets.bearer(secret)
1465
1475
  */
1466
- bearer(secret: PlaySecretHandle): PlaySecretAuth;
1476
+ bearer(secret: string | PlaySecretPromise | PlaySecretHandle): PlaySecretAuth;
1467
1477
  /**
1468
- * Send the secret as a named header, for APIs that do not use bearer tokens — `x-api-key`, `apikey`, `private-token`, and similar.
1478
+ * Send a credential as a named header, for APIs that do not use bearer
1479
+ * tokens — `x-api-key`, `apikey`, `private-token`, and similar.
1469
1480
  *
1470
1481
  * @sdkReference runtime 173 ctx.secrets.header(header, secret)
1471
1482
  */
1472
- header(header: string, secret: PlaySecretHandle): PlaySecretAuth;
1483
+ header(header: string, secret: string | PlaySecretPromise | PlaySecretHandle): PlaySecretAuth;
1473
1484
  };
1474
1485
  /**
1475
1486
  * Compose another Play inline under a stable call key.
@@ -101,13 +101,13 @@ type PlayDocflow = {
101
101
  nodes: PlayDocflowNode[];
102
102
  edges: PlayDocflowEdge[];
103
103
  bindings: PlayDocflowBinding[];
104
- /** Authoring syntax used by the source file. Absent on older persisted graphs. */
105
- syntax?: 'docflow' | 'mermaid';
104
+ /** Authoring syntax used by the source file. */
105
+ syntax?: 'mermaid';
106
106
  /** Normalized Mermaid text, ready to pass directly to a Mermaid renderer. */
107
107
  mermaidSource?: string;
108
108
  /**
109
- * Mermaid `subgraph` loop regions. Optional so older persisted graphs stay
110
- * valid. Only populated for the Mermaid syntax; legacy `docflow` has none.
109
+ * Mermaid `subgraph` loop regions. Optional for persisted graphs that have
110
+ * no authored regions.
111
111
  */
112
112
  subgraphs?: PlayDocflowSubgraph[];
113
113
  /** Mermaid directives accepted by the parser but not applied by React Flow. */
@@ -1017,7 +1017,7 @@ declare function isProviderUnavailable(error: unknown): error is ProviderUnavail
1017
1017
  /** @deprecated Use isProviderUnavailable. */
1018
1018
  declare const isProviderWaterfallUnavailableError: typeof isProviderUnavailable;
1019
1019
 
1020
- declare const SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS: readonly [1, 2, 3];
1020
+ declare const SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS: readonly [1, 2, 3, 4];
1021
1021
  type PlayAuthoringContractEdition = (typeof SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS)[number];
1022
1022
  type PlaySqlListenerOperation = 'INSERT' | 'UPDATE' | 'DELETE';
1023
1023
  type PlayStandardWebhookHeaderFamily = 'standard' | 'svix';
@@ -1146,8 +1146,10 @@ type PlaySqlQuery = {
1146
1146
  readonly values: readonly unknown[];
1147
1147
  };
1148
1148
  declare const PLAY_SECRET_HANDLE_BRAND: unique symbol;
1149
+ declare const PLAY_SECRET_PROMISE_BRAND: unique symbol;
1149
1150
  /**
1150
- * An opaque reference to a workspace secret, returned by `ctx.secrets.get`. The handle never carries the value into play code: it stringifies to `[secret:NAME]` and throws on `JSON.stringify`, so a secret cannot reach a play variable, a log line, a dataset cell, or a replay artifact even by accident. Only the runtime resolves it, at the moment it attaches the request header.
1151
+ * An opaque reference to a workspace secret used by legacy authoring-contract
1152
+ * editions. New Plays receive plaintext strings from `ctx.secrets.get`.
1151
1153
  *
1152
1154
  * @sdkReference runtime 176 SecretHandle
1153
1155
  */
@@ -1160,6 +1162,12 @@ type PlaySecretHandle = {
1160
1162
  /** Always throws. A secret handle is deliberately not serializable. */
1161
1163
  toJSON(): never;
1162
1164
  };
1165
+ /** A secret-reading promise returned only by `ctx.secrets.get`. */
1166
+ type PlaySecretPromise = Promise<string> & {
1167
+ readonly [PLAY_SECRET_PROMISE_BRAND]: never;
1168
+ };
1169
+ /** An opaque legacy secret handle retained for earlier Play artifacts. */
1170
+ type PlaySecretValue = PlaySecretHandle;
1163
1171
  /**
1164
1172
  * One resolved authentication scheme, built by `ctx.secrets.bearer` or `ctx.secrets.header` and attached to a request through `init.auth`.
1165
1173
  *
@@ -1168,8 +1176,8 @@ type PlaySecretHandle = {
1168
1176
  type PlaySecretAuth = {
1169
1177
  /** `bearer` sends `Authorization: Bearer <value>`; `header` sends a named header. */
1170
1178
  readonly kind: 'bearer' | 'header';
1171
- /** The handle whose value the runtime attaches. */
1172
- readonly secret: PlaySecretHandle;
1179
+ /** The value whose bytes the runtime attaches. */
1180
+ readonly secret: string | PlaySecretPromise | PlaySecretValue;
1173
1181
  /** Header name, set only when `kind` is `header`. */
1174
1182
  readonly header?: string;
1175
1183
  };
@@ -1181,10 +1189,10 @@ type PlaySecretAuthInput = PlaySecretAuth | readonly PlaySecretAuth[];
1181
1189
  * @sdkReference runtime 174 SecretAwareRequestInit
1182
1190
  */
1183
1191
  type PlaySecretAwareRequestInit = Omit<RequestInit, 'headers'> & {
1184
- /** Ordinary request headers, recorded in the durable receipt. Never interpolate a secret value here use `auth`. */
1192
+ /** Ordinary request headers, recorded in the durable receipt with any resolved Play secret value redacted. Prefer `auth` for credentials: it enforces HTTPS and keeps the auth header out of the receipt. */
1185
1193
  headers?: HeadersInit;
1186
1194
  /**
1187
- * One or more secret-backed authentication headers for this request. Pass a single `ctx.secrets` auth for the common case, or an array when an API requires multiple credentialed headers — for example, Supabase with both `apikey` and `Authorization`. Every secret is resolved only while the request is attached, never stored in the durable receipt. Each auth entry must target a distinct header.
1195
+ * One or more credentialed headers for this request. Pass a single `ctx.secrets` auth for the common case, or an array when an API requires multiple credentialed headers — for example, Supabase with both `apikey` and `Authorization`. Auth-helper requests require HTTPS and omit the credential from the durable receipt. Each auth entry must target a distinct header.
1188
1196
  */
1189
1197
  auth?: PlaySecretAuthInput;
1190
1198
  };
@@ -1453,23 +1461,26 @@ interface PlayAuthoringRuntimeContext {
1453
1461
  fetch(key: string, url: string | URL, init?: PlaySecretAwareRequestInit, options?: PlayAuthoringFetchOptions): Promise<PlayAuthoringFetchResponse>;
1454
1462
  secrets: {
1455
1463
  /**
1456
- * Reference a workspace secret by name without reading its value. This is the only supported way to authenticate an outbound request from a Play: `process.env.X` is rejected at check time because an env read puts the raw value in a play variable, where it can reach a log line or a replay artifact. A handle cannot — pass it to `bearer` or `header` and the runtime resolves it only while attaching the header. Names are uppercased; manage stored values with `deepline secrets set` / `deepline secrets list`.
1464
+ * Read an allowed workspace secret inside the running Play; do not log or return it. Declare uppercase names in top-level `secrets`.
1457
1465
  *
1458
1466
  * @sdkReference runtime 171 ctx.secrets.get(name)
1459
1467
  */
1460
- get(name: string): PlaySecretHandle;
1468
+ get(name: string): PlaySecretPromise;
1461
1469
  /**
1462
- * Send the secret as `Authorization: Bearer <value>`.
1470
+ * Send a credential as `Authorization: Bearer <value>`. Await `get` first;
1471
+ * its direct promise remains accepted for source compatibility, while other
1472
+ * promises are rejected.
1463
1473
  *
1464
1474
  * @sdkReference runtime 172 ctx.secrets.bearer(secret)
1465
1475
  */
1466
- bearer(secret: PlaySecretHandle): PlaySecretAuth;
1476
+ bearer(secret: string | PlaySecretPromise | PlaySecretHandle): PlaySecretAuth;
1467
1477
  /**
1468
- * Send the secret as a named header, for APIs that do not use bearer tokens — `x-api-key`, `apikey`, `private-token`, and similar.
1478
+ * Send a credential as a named header, for APIs that do not use bearer
1479
+ * tokens — `x-api-key`, `apikey`, `private-token`, and similar.
1469
1480
  *
1470
1481
  * @sdkReference runtime 173 ctx.secrets.header(header, secret)
1471
1482
  */
1472
- header(header: string, secret: PlaySecretHandle): PlaySecretAuth;
1483
+ header(header: string, secret: string | PlaySecretPromise | PlaySecretHandle): PlaySecretAuth;
1473
1484
  };
1474
1485
  /**
1475
1486
  * Compose another Play inline under a stable call key.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { e as PlayRuntimeBackendId, c as PlayCompilerManifest, D as DeeplineError, f as ToolExecutionError, g as ToolExecutionErrorOptions, h as PlayAuthoringColumnMap, i as PlayAuthoringColumnResolver, j as PlayAuthoringRuntimeContext, k as PlayAuthoringConditionalStepResolver, l as PlayAuthoringCsvInput, m as PlayAuthoringCsvOptions, n as PlayAuthoringDatasetBuilder, o as PlayAuthoringDatasetColumnDefinition, p as PlayAuthoringDatasetColumnRunInput, q as ToolExecuteResult, r as PlayAuthoringReferenceLike, s as PlayReturnObject$1, t as PlayAuthoringDefineConfig, u as PlayAuthoringDefinedPlay, v as PlayAuthoringFetchOptions, w as PlayAuthoringFileInput, x as PlayAuthoringBindings, y as PlayAuthoringCallExecution, z as PlayAuthoringCallOptions, A as PlayAuthoringFetchResponse, B as PlayAuthoringInputContract, C as PlayAuthoringStepProgramStep, E as PlayAuthoringRuntimeStepOptions, F as PlaySqlListenerDeclaration, G as PlaySqlListenerEvent, H as PlaySqlListenerOperation, I as PlaySqlQuery, J as PlayAuthoringStepOptions, K as PlayAuthoringStepProgram, L as PlayAuthoringStepProgramResolver, M as PlayAuthoringStepResolver, N as PlayToolExecutionRequest, O as PlayAuthoringStepProgramOptions } from './compiler-manifest-CdgJeOr2.mjs';
2
- export { Q as DEEPLINE_EXTRACTOR_TARGETS, R as DEEPLINE_EXTRACTOR_TARGET_DEFINITIONS, S as DeeplineEmailStatusGetterValue, U as DeeplineExtractorTarget, V as DeeplineGetterValue, W as DeeplineGetterValueMap, X as JOB_CHANGE_STATUS_VALUES, Y as JobChangeStatus, Z as PHONE_STATUS_VALUES, _ as PhoneStatus, $ as PlayDataset, a0 as PlayDatasetInput, a1 as PreviousCell, a2 as ProviderTransientError, a3 as ProviderTransientErrorCategory, a4 as ProviderUnavailableError, a5 as ProviderUnavailableReason, a6 as ToolExecutionErrorCategory, a7 as ToolExecutionErrorOrigin, a8 as ToolExecutionFailureV1, a9 as ToolExecutionNetworkKind, aa as ToolExecutionNetworkScope, ab as getProviderUnavailableReason, ac as isDeeplineExtractorTarget, ad as isProviderUnavailable, ae as isProviderWaterfallUnavailableError } from './compiler-manifest-CdgJeOr2.mjs';
1
+ import { e as PlayRuntimeBackendId, c as PlayCompilerManifest, D as DeeplineError, f as ToolExecutionError, g as ToolExecutionErrorOptions, h as PlayAuthoringColumnMap, i as PlayAuthoringColumnResolver, j as PlayAuthoringRuntimeContext, k as PlayAuthoringConditionalStepResolver, l as PlayAuthoringCsvInput, m as PlayAuthoringCsvOptions, n as PlayAuthoringDatasetBuilder, o as PlayAuthoringDatasetColumnDefinition, p as PlayAuthoringDatasetColumnRunInput, q as ToolExecuteResult, r as PlayAuthoringReferenceLike, s as PlayReturnObject$1, t as PlayAuthoringDefineConfig, u as PlayAuthoringDefinedPlay, v as PlayAuthoringFetchOptions, w as PlayAuthoringFileInput, x as PlayAuthoringBindings, y as PlayAuthoringCallExecution, z as PlayAuthoringCallOptions, A as PlayAuthoringFetchResponse, B as PlayAuthoringInputContract, C as PlayAuthoringStepProgramStep, E as PlayAuthoringRuntimeStepOptions, F as PlaySqlListenerDeclaration, G as PlaySqlListenerEvent, H as PlaySqlListenerOperation, I as PlaySqlQuery, J as PlayAuthoringStepOptions, K as PlayAuthoringStepProgram, L as PlayAuthoringStepProgramResolver, M as PlayAuthoringStepResolver, N as PlayToolExecutionRequest, O as PlayAuthoringStepProgramOptions } from './compiler-manifest-YIjoJo8y.mjs';
2
+ export { Q as DEEPLINE_EXTRACTOR_TARGETS, R as DEEPLINE_EXTRACTOR_TARGET_DEFINITIONS, S as DeeplineEmailStatusGetterValue, U as DeeplineExtractorTarget, V as DeeplineGetterValue, W as DeeplineGetterValueMap, X as JOB_CHANGE_STATUS_VALUES, Y as JobChangeStatus, Z as PHONE_STATUS_VALUES, _ as PhoneStatus, $ as PlayDataset, a0 as PlayDatasetInput, a1 as PreviousCell, a2 as ProviderTransientError, a3 as ProviderTransientErrorCategory, a4 as ProviderUnavailableError, a5 as ProviderUnavailableReason, a6 as ToolExecutionErrorCategory, a7 as ToolExecutionErrorOrigin, a8 as ToolExecutionFailureV1, a9 as ToolExecutionNetworkKind, aa as ToolExecutionNetworkScope, ab as getProviderUnavailableReason, ac as isDeeplineExtractorTarget, ad as isProviderUnavailable, ae as isProviderWaterfallUnavailableError } from './compiler-manifest-YIjoJo8y.mjs';
3
3
  import '@sinclair/typebox';
4
4
 
5
5
  declare const FIXTURE_BEHAVIOR_VERSION: 1;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { e as PlayRuntimeBackendId, c as PlayCompilerManifest, D as DeeplineError, f as ToolExecutionError, g as ToolExecutionErrorOptions, h as PlayAuthoringColumnMap, i as PlayAuthoringColumnResolver, j as PlayAuthoringRuntimeContext, k as PlayAuthoringConditionalStepResolver, l as PlayAuthoringCsvInput, m as PlayAuthoringCsvOptions, n as PlayAuthoringDatasetBuilder, o as PlayAuthoringDatasetColumnDefinition, p as PlayAuthoringDatasetColumnRunInput, q as ToolExecuteResult, r as PlayAuthoringReferenceLike, s as PlayReturnObject$1, t as PlayAuthoringDefineConfig, u as PlayAuthoringDefinedPlay, v as PlayAuthoringFetchOptions, w as PlayAuthoringFileInput, x as PlayAuthoringBindings, y as PlayAuthoringCallExecution, z as PlayAuthoringCallOptions, A as PlayAuthoringFetchResponse, B as PlayAuthoringInputContract, C as PlayAuthoringStepProgramStep, E as PlayAuthoringRuntimeStepOptions, F as PlaySqlListenerDeclaration, G as PlaySqlListenerEvent, H as PlaySqlListenerOperation, I as PlaySqlQuery, J as PlayAuthoringStepOptions, K as PlayAuthoringStepProgram, L as PlayAuthoringStepProgramResolver, M as PlayAuthoringStepResolver, N as PlayToolExecutionRequest, O as PlayAuthoringStepProgramOptions } from './compiler-manifest-CdgJeOr2.js';
2
- export { Q as DEEPLINE_EXTRACTOR_TARGETS, R as DEEPLINE_EXTRACTOR_TARGET_DEFINITIONS, S as DeeplineEmailStatusGetterValue, U as DeeplineExtractorTarget, V as DeeplineGetterValue, W as DeeplineGetterValueMap, X as JOB_CHANGE_STATUS_VALUES, Y as JobChangeStatus, Z as PHONE_STATUS_VALUES, _ as PhoneStatus, $ as PlayDataset, a0 as PlayDatasetInput, a1 as PreviousCell, a2 as ProviderTransientError, a3 as ProviderTransientErrorCategory, a4 as ProviderUnavailableError, a5 as ProviderUnavailableReason, a6 as ToolExecutionErrorCategory, a7 as ToolExecutionErrorOrigin, a8 as ToolExecutionFailureV1, a9 as ToolExecutionNetworkKind, aa as ToolExecutionNetworkScope, ab as getProviderUnavailableReason, ac as isDeeplineExtractorTarget, ad as isProviderUnavailable, ae as isProviderWaterfallUnavailableError } from './compiler-manifest-CdgJeOr2.js';
1
+ import { e as PlayRuntimeBackendId, c as PlayCompilerManifest, D as DeeplineError, f as ToolExecutionError, g as ToolExecutionErrorOptions, h as PlayAuthoringColumnMap, i as PlayAuthoringColumnResolver, j as PlayAuthoringRuntimeContext, k as PlayAuthoringConditionalStepResolver, l as PlayAuthoringCsvInput, m as PlayAuthoringCsvOptions, n as PlayAuthoringDatasetBuilder, o as PlayAuthoringDatasetColumnDefinition, p as PlayAuthoringDatasetColumnRunInput, q as ToolExecuteResult, r as PlayAuthoringReferenceLike, s as PlayReturnObject$1, t as PlayAuthoringDefineConfig, u as PlayAuthoringDefinedPlay, v as PlayAuthoringFetchOptions, w as PlayAuthoringFileInput, x as PlayAuthoringBindings, y as PlayAuthoringCallExecution, z as PlayAuthoringCallOptions, A as PlayAuthoringFetchResponse, B as PlayAuthoringInputContract, C as PlayAuthoringStepProgramStep, E as PlayAuthoringRuntimeStepOptions, F as PlaySqlListenerDeclaration, G as PlaySqlListenerEvent, H as PlaySqlListenerOperation, I as PlaySqlQuery, J as PlayAuthoringStepOptions, K as PlayAuthoringStepProgram, L as PlayAuthoringStepProgramResolver, M as PlayAuthoringStepResolver, N as PlayToolExecutionRequest, O as PlayAuthoringStepProgramOptions } from './compiler-manifest-YIjoJo8y.js';
2
+ export { Q as DEEPLINE_EXTRACTOR_TARGETS, R as DEEPLINE_EXTRACTOR_TARGET_DEFINITIONS, S as DeeplineEmailStatusGetterValue, U as DeeplineExtractorTarget, V as DeeplineGetterValue, W as DeeplineGetterValueMap, X as JOB_CHANGE_STATUS_VALUES, Y as JobChangeStatus, Z as PHONE_STATUS_VALUES, _ as PhoneStatus, $ as PlayDataset, a0 as PlayDatasetInput, a1 as PreviousCell, a2 as ProviderTransientError, a3 as ProviderTransientErrorCategory, a4 as ProviderUnavailableError, a5 as ProviderUnavailableReason, a6 as ToolExecutionErrorCategory, a7 as ToolExecutionErrorOrigin, a8 as ToolExecutionFailureV1, a9 as ToolExecutionNetworkKind, aa as ToolExecutionNetworkScope, ab as getProviderUnavailableReason, ac as isDeeplineExtractorTarget, ad as isProviderUnavailable, ae as isProviderWaterfallUnavailableError } from './compiler-manifest-YIjoJo8y.js';
3
3
  import '@sinclair/typebox';
4
4
 
5
5
  declare const FIXTURE_BEHAVIOR_VERSION: 1;
package/dist/index.js CHANGED
@@ -783,7 +783,7 @@ var SDK_RELEASE = {
783
783
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
784
784
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
785
785
  // getters keep their established compatibility behavior.
786
- version: "0.3.7",
786
+ version: "0.3.8",
787
787
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
788
788
  contracts: {
789
789
  api: {
@@ -1756,10 +1756,30 @@ function redactSecretLikeString(value) {
1756
1756
  function createSecretRedactionContext(initialValues = []) {
1757
1757
  const exactSecrets = /* @__PURE__ */ new Set();
1758
1758
  function register(value) {
1759
- if (value.length >= 4) exactSecrets.add(value);
1759
+ if (value.length > 0) exactSecrets.add(value);
1760
1760
  }
1761
1761
  for (const value of initialValues) register(value);
1762
- function redactString2(value) {
1762
+ function containsRegisteredSecret(value, {
1763
+ includeEncoded = false,
1764
+ minimumLength = 1
1765
+ } = {}) {
1766
+ for (const secret of exactSecrets) {
1767
+ if (secret.length < minimumLength) continue;
1768
+ if (value.includes(secret)) return true;
1769
+ if (includeEncoded) {
1770
+ try {
1771
+ const encoded = encodeURIComponent(secret);
1772
+ if (encoded !== secret && value.includes(encoded)) return true;
1773
+ } catch {
1774
+ }
1775
+ }
1776
+ }
1777
+ return false;
1778
+ }
1779
+ function matchesRegisteredSecret(value) {
1780
+ return exactSecrets.has(value);
1781
+ }
1782
+ function redactRegisteredSecrets(value) {
1763
1783
  let output = value;
1764
1784
  for (const secret of exactSecrets) {
1765
1785
  output = output.replace(
@@ -1777,6 +1797,10 @@ function createSecretRedactionContext(initialValues = []) {
1777
1797
  } catch {
1778
1798
  }
1779
1799
  }
1800
+ return output;
1801
+ }
1802
+ function redactString2(value) {
1803
+ const output = redactRegisteredSecrets(value);
1780
1804
  return redactSecretLikeString(output);
1781
1805
  }
1782
1806
  function redact(value) {
@@ -1809,6 +1833,9 @@ function createSecretRedactionContext(initialValues = []) {
1809
1833
  }
1810
1834
  return {
1811
1835
  register,
1836
+ containsRegisteredSecret,
1837
+ matchesRegisteredSecret,
1838
+ redactRegisteredSecrets,
1812
1839
  redactString: redactString2,
1813
1840
  redactKnownSecrets,
1814
1841
  redact
package/dist/index.mjs CHANGED
@@ -706,7 +706,7 @@ var SDK_RELEASE = {
706
706
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
707
707
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
708
708
  // getters keep their established compatibility behavior.
709
- version: "0.3.7",
709
+ version: "0.3.8",
710
710
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
711
711
  contracts: {
712
712
  api: {
@@ -1679,10 +1679,30 @@ function redactSecretLikeString(value) {
1679
1679
  function createSecretRedactionContext(initialValues = []) {
1680
1680
  const exactSecrets = /* @__PURE__ */ new Set();
1681
1681
  function register(value) {
1682
- if (value.length >= 4) exactSecrets.add(value);
1682
+ if (value.length > 0) exactSecrets.add(value);
1683
1683
  }
1684
1684
  for (const value of initialValues) register(value);
1685
- function redactString2(value) {
1685
+ function containsRegisteredSecret(value, {
1686
+ includeEncoded = false,
1687
+ minimumLength = 1
1688
+ } = {}) {
1689
+ for (const secret of exactSecrets) {
1690
+ if (secret.length < minimumLength) continue;
1691
+ if (value.includes(secret)) return true;
1692
+ if (includeEncoded) {
1693
+ try {
1694
+ const encoded = encodeURIComponent(secret);
1695
+ if (encoded !== secret && value.includes(encoded)) return true;
1696
+ } catch {
1697
+ }
1698
+ }
1699
+ }
1700
+ return false;
1701
+ }
1702
+ function matchesRegisteredSecret(value) {
1703
+ return exactSecrets.has(value);
1704
+ }
1705
+ function redactRegisteredSecrets(value) {
1686
1706
  let output = value;
1687
1707
  for (const secret of exactSecrets) {
1688
1708
  output = output.replace(
@@ -1700,6 +1720,10 @@ function createSecretRedactionContext(initialValues = []) {
1700
1720
  } catch {
1701
1721
  }
1702
1722
  }
1723
+ return output;
1724
+ }
1725
+ function redactString2(value) {
1726
+ const output = redactRegisteredSecrets(value);
1703
1727
  return redactSecretLikeString(output);
1704
1728
  }
1705
1729
  function redact(value) {
@@ -1732,6 +1756,9 @@ function createSecretRedactionContext(initialValues = []) {
1732
1756
  }
1733
1757
  return {
1734
1758
  register,
1759
+ containsRegisteredSecret,
1760
+ matchesRegisteredSecret,
1761
+ redactRegisteredSecrets,
1735
1762
  redactString: redactString2,
1736
1763
  redactKnownSecrets,
1737
1764
  redact
@@ -226,8 +226,8 @@
226
226
  "dist/cli/index.d.ts",
227
227
  "dist/cli/index.js",
228
228
  "dist/cli/index.mjs",
229
- "dist/compiler-manifest-CdgJeOr2.d.mts",
230
- "dist/compiler-manifest-CdgJeOr2.d.ts",
229
+ "dist/compiler-manifest-YIjoJo8y.d.mts",
230
+ "dist/compiler-manifest-YIjoJo8y.d.ts",
231
231
  "dist/helpers.d.mts",
232
232
  "dist/helpers.d.ts",
233
233
  "dist/helpers.js",
@@ -1,5 +1,5 @@
1
- import { T as ToolExecutionErrorSchemaVersion, P as PlayAuthoringContractEdition, a as PlayArtifactKind$1, b as PlaySandboxRuntimeDeclaration, c as PlayCompilerManifest } from '../compiler-manifest-CdgJeOr2.mjs';
2
- export { d as PLAY_ARTIFACT_KINDS } from '../compiler-manifest-CdgJeOr2.mjs';
1
+ import { T as ToolExecutionErrorSchemaVersion, P as PlayAuthoringContractEdition, a as PlayArtifactKind$1, b as PlaySandboxRuntimeDeclaration, c as PlayCompilerManifest } from '../compiler-manifest-YIjoJo8y.mjs';
2
+ export { d as PLAY_ARTIFACT_KINDS } from '../compiler-manifest-YIjoJo8y.mjs';
3
3
  import '@sinclair/typebox';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { T as ToolExecutionErrorSchemaVersion, P as PlayAuthoringContractEdition, a as PlayArtifactKind$1, b as PlaySandboxRuntimeDeclaration, c as PlayCompilerManifest } from '../compiler-manifest-CdgJeOr2.js';
2
- export { d as PLAY_ARTIFACT_KINDS } from '../compiler-manifest-CdgJeOr2.js';
1
+ import { T as ToolExecutionErrorSchemaVersion, P as PlayAuthoringContractEdition, a as PlayArtifactKind$1, b as PlaySandboxRuntimeDeclaration, c as PlayCompilerManifest } from '../compiler-manifest-YIjoJo8y.js';
2
+ export { d as PLAY_ARTIFACT_KINDS } from '../compiler-manifest-YIjoJo8y.js';
3
3
  import '@sinclair/typebox';
4
4
 
5
5
  /**