@adcp/sdk 14.0.0-beta.10 → 14.0.0-beta.12

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 (208) hide show
  1. package/bin/adcp-storyboard-sandbox.js +16 -0
  2. package/bin/adcp.js +28 -30
  3. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  4. package/dist/lib/core/SingleAgentClient.d.mts +2 -1
  5. package/dist/lib/core/SingleAgentClient.d.ts +2 -1
  6. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  7. package/dist/lib/core/SingleAgentClient.js +113 -64
  8. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  9. package/dist/lib/core/SingleAgentClient.mjs +113 -64
  10. package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
  11. package/dist/lib/index.d.mts +1 -1
  12. package/dist/lib/index.d.ts +1 -1
  13. package/dist/lib/index.d.ts.map +1 -1
  14. package/dist/lib/index.js.map +1 -1
  15. package/dist/lib/index.mjs.map +1 -1
  16. package/dist/lib/protocols/a2a.d.mts +10 -3
  17. package/dist/lib/protocols/a2a.d.ts +10 -3
  18. package/dist/lib/protocols/a2a.d.ts.map +1 -1
  19. package/dist/lib/protocols/a2a.js +162 -34
  20. package/dist/lib/protocols/a2a.js.map +1 -1
  21. package/dist/lib/protocols/a2a.mjs +166 -34
  22. package/dist/lib/protocols/a2a.mjs.map +1 -1
  23. package/dist/lib/schemas/index.d.mts +385 -1
  24. package/dist/lib/schemas/index.d.ts +385 -1
  25. package/dist/lib/schemas/index.d.ts.map +1 -1
  26. package/dist/lib/schemas/index.js +13 -0
  27. package/dist/lib/schemas/index.js.map +1 -1
  28. package/dist/lib/schemas/index.mjs +11 -0
  29. package/dist/lib/schemas/index.mjs.map +1 -1
  30. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  31. package/dist/lib/server/a2a-adapter.d.mts +59 -33
  32. package/dist/lib/server/a2a-adapter.d.ts +59 -33
  33. package/dist/lib/server/a2a-adapter.d.ts.map +1 -1
  34. package/dist/lib/server/a2a-adapter.js +278 -67
  35. package/dist/lib/server/a2a-adapter.js.map +1 -1
  36. package/dist/lib/server/a2a-adapter.mjs +280 -68
  37. package/dist/lib/server/a2a-adapter.mjs.map +1 -1
  38. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  39. package/dist/lib/server/create-adcp-server.js +35 -108
  40. package/dist/lib/server/create-adcp-server.js.map +1 -1
  41. package/dist/lib/server/create-adcp-server.mjs +37 -109
  42. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  43. package/dist/lib/server/decisioning/index.d.mts +2 -0
  44. package/dist/lib/server/decisioning/index.d.ts +2 -0
  45. package/dist/lib/server/decisioning/index.d.ts.map +1 -1
  46. package/dist/lib/server/decisioning/index.js +5 -2
  47. package/dist/lib/server/decisioning/index.js.map +1 -1
  48. package/dist/lib/server/decisioning/index.mjs +3 -1
  49. package/dist/lib/server/decisioning/index.mjs.map +1 -1
  50. package/dist/lib/server/decisioning/response-summary.d.mts +33 -0
  51. package/dist/lib/server/decisioning/response-summary.d.ts +34 -0
  52. package/dist/lib/server/decisioning/response-summary.d.ts.map +1 -0
  53. package/dist/lib/server/decisioning/response-summary.js +62 -0
  54. package/dist/lib/server/decisioning/response-summary.js.map +1 -0
  55. package/dist/lib/server/decisioning/response-summary.mjs +37 -0
  56. package/dist/lib/server/decisioning/response-summary.mjs.map +1 -0
  57. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  58. package/dist/lib/server/decisioning/runtime/from-platform.js +27 -5
  59. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  60. package/dist/lib/server/decisioning/runtime/from-platform.mjs +27 -5
  61. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  62. package/dist/lib/server/decisioning/specialisms/sales.d.mts +7 -1
  63. package/dist/lib/server/decisioning/specialisms/sales.d.ts +7 -1
  64. package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
  65. package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
  66. package/dist/lib/server/index.d.mts +1 -1
  67. package/dist/lib/server/index.d.ts +1 -1
  68. package/dist/lib/server/index.d.ts.map +1 -1
  69. package/dist/lib/server/index.js.map +1 -1
  70. package/dist/lib/server/index.mjs.map +1 -1
  71. package/dist/lib/server/responses.d.ts.map +1 -1
  72. package/dist/lib/server/responses.js +9 -1
  73. package/dist/lib/server/responses.js.map +1 -1
  74. package/dist/lib/server/responses.mjs +8 -1
  75. package/dist/lib/server/responses.mjs.map +1 -1
  76. package/dist/lib/signing/agent-context.d.mts +1 -0
  77. package/dist/lib/signing/agent-context.d.ts +1 -0
  78. package/dist/lib/signing/agent-context.d.ts.map +1 -1
  79. package/dist/lib/signing/agent-context.js +37 -2
  80. package/dist/lib/signing/agent-context.js.map +1 -1
  81. package/dist/lib/signing/agent-context.mjs +38 -3
  82. package/dist/lib/signing/agent-context.mjs.map +1 -1
  83. package/dist/lib/signing/agent-fetch.d.mts +1 -2
  84. package/dist/lib/signing/agent-fetch.d.ts +1 -2
  85. package/dist/lib/signing/agent-fetch.d.ts.map +1 -1
  86. package/dist/lib/signing/agent-fetch.js +2 -0
  87. package/dist/lib/signing/agent-fetch.js.map +1 -1
  88. package/dist/lib/signing/agent-fetch.mjs +2 -0
  89. package/dist/lib/signing/agent-fetch.mjs.map +1 -1
  90. package/dist/lib/signing/agent-resolver/etld.js.map +1 -1
  91. package/dist/lib/signing/agent-resolver/etld.mjs.map +1 -1
  92. package/dist/lib/testing/client.d.mts +6 -0
  93. package/dist/lib/testing/client.d.ts +6 -0
  94. package/dist/lib/testing/client.d.ts.map +1 -1
  95. package/dist/lib/testing/client.js +76 -4
  96. package/dist/lib/testing/client.js.map +1 -1
  97. package/dist/lib/testing/client.mjs +75 -4
  98. package/dist/lib/testing/client.mjs.map +1 -1
  99. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  100. package/dist/lib/testing/compliance/comply.js +6 -0
  101. package/dist/lib/testing/compliance/comply.js.map +1 -1
  102. package/dist/lib/testing/compliance/comply.mjs +7 -1
  103. package/dist/lib/testing/compliance/comply.mjs.map +1 -1
  104. package/dist/lib/testing/storyboard/context.d.ts.map +1 -1
  105. package/dist/lib/testing/storyboard/context.js +9 -4
  106. package/dist/lib/testing/storyboard/context.js.map +1 -1
  107. package/dist/lib/testing/storyboard/context.mjs +9 -4
  108. package/dist/lib/testing/storyboard/context.mjs.map +1 -1
  109. package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -1
  110. package/dist/lib/testing/storyboard/request-builder.js +28 -4
  111. package/dist/lib/testing/storyboard/request-builder.js.map +1 -1
  112. package/dist/lib/testing/storyboard/request-builder.mjs +28 -4
  113. package/dist/lib/testing/storyboard/request-builder.mjs.map +1 -1
  114. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.d.mts +15 -0
  115. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.d.ts +16 -0
  116. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.d.ts.map +1 -0
  117. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.js +106 -0
  118. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.js.map +1 -0
  119. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.mjs +82 -0
  120. package/dist/lib/testing/storyboard/request-signing/functional-dispatch.mjs.map +1 -0
  121. package/dist/lib/testing/storyboard/request-signing/test-kit.d.mts +15 -0
  122. package/dist/lib/testing/storyboard/request-signing/test-kit.d.ts +15 -0
  123. package/dist/lib/testing/storyboard/request-signing/test-kit.d.ts.map +1 -1
  124. package/dist/lib/testing/storyboard/request-signing/test-kit.js +58 -0
  125. package/dist/lib/testing/storyboard/request-signing/test-kit.js.map +1 -1
  126. package/dist/lib/testing/storyboard/request-signing/test-kit.mjs +58 -0
  127. package/dist/lib/testing/storyboard/request-signing/test-kit.mjs.map +1 -1
  128. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +2 -0
  129. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +2 -0
  130. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts.map +1 -1
  131. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +7 -1
  132. package/dist/lib/testing/storyboard/request-signing/vector-loader.js.map +1 -1
  133. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +6 -1
  134. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs.map +1 -1
  135. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  136. package/dist/lib/testing/storyboard/runner.js +31 -7
  137. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  138. package/dist/lib/testing/storyboard/runner.mjs +31 -7
  139. package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
  140. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  141. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  142. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
  143. package/dist/lib/testing/storyboard/validations.js +18 -7
  144. package/dist/lib/testing/storyboard/validations.js.map +1 -1
  145. package/dist/lib/testing/storyboard/validations.mjs +18 -7
  146. package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
  147. package/dist/lib/testing/storyboard/webhook-receiver.d.ts.map +1 -1
  148. package/dist/lib/testing/storyboard/webhook-receiver.js +32 -20
  149. package/dist/lib/testing/storyboard/webhook-receiver.js.map +1 -1
  150. package/dist/lib/testing/storyboard/webhook-receiver.mjs +32 -20
  151. package/dist/lib/testing/storyboard/webhook-receiver.mjs.map +1 -1
  152. package/dist/lib/testing/types.d.mts +10 -0
  153. package/dist/lib/testing/types.d.ts +10 -0
  154. package/dist/lib/testing/types.d.ts.map +1 -1
  155. package/dist/lib/testing/types.js.map +1 -1
  156. package/dist/lib/types/comply-test-controller.d.ts +1 -14
  157. package/dist/lib/types/core.generated.d.mts +1 -1
  158. package/dist/lib/types/core.generated.d.ts +1 -1
  159. package/dist/lib/types/core.generated.d.ts.map +1 -1
  160. package/dist/lib/types/core.generated.js.map +1 -1
  161. package/dist/lib/types/get-products.d.ts +1 -14
  162. package/dist/lib/types/schemas.generated.d.ts +519 -571
  163. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  164. package/dist/lib/types/schemas.generated.js +2 -2
  165. package/dist/lib/types/schemas.generated.js.map +1 -1
  166. package/dist/lib/types/schemas.generated.mjs +2 -2
  167. package/dist/lib/types/schemas.generated.mjs.map +1 -1
  168. package/dist/lib/types/tools.generated.d.mts +1 -1
  169. package/dist/lib/types/tools.generated.d.ts +1 -1
  170. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  171. package/dist/lib/types/tools.generated.js.map +1 -1
  172. package/dist/lib/utils/a2a-artifacts.d.ts.map +1 -1
  173. package/dist/lib/utils/a2a-artifacts.js +2 -2
  174. package/dist/lib/utils/a2a-artifacts.js.map +1 -1
  175. package/dist/lib/utils/a2a-artifacts.mjs +2 -2
  176. package/dist/lib/utils/a2a-artifacts.mjs.map +1 -1
  177. package/dist/lib/utils/a2a-discovery.d.mts +3 -3
  178. package/dist/lib/utils/a2a-discovery.d.ts +3 -3
  179. package/dist/lib/utils/a2a-discovery.js +1 -1
  180. package/dist/lib/utils/a2a-discovery.js.map +1 -1
  181. package/dist/lib/utils/a2a-discovery.mjs +1 -1
  182. package/dist/lib/utils/a2a-discovery.mjs.map +1 -1
  183. package/dist/lib/utils/tool-request-schemas.d.mts +31 -31
  184. package/dist/lib/utils/tool-request-schemas.d.ts +31 -31
  185. package/dist/lib/v2/projection/index.d.mts +2 -0
  186. package/dist/lib/v2/projection/index.d.ts +2 -0
  187. package/dist/lib/v2/projection/index.d.ts.map +1 -1
  188. package/dist/lib/v2/projection/index.js +3 -0
  189. package/dist/lib/v2/projection/index.js.map +1 -1
  190. package/dist/lib/v2/projection/index.mjs +2 -0
  191. package/dist/lib/v2/projection/index.mjs.map +1 -1
  192. package/dist/lib/v2/projection/legacy-normalization.d.mts +24 -0
  193. package/dist/lib/v2/projection/legacy-normalization.d.ts +25 -0
  194. package/dist/lib/v2/projection/legacy-normalization.d.ts.map +1 -0
  195. package/dist/lib/v2/projection/legacy-normalization.js +32 -0
  196. package/dist/lib/v2/projection/legacy-normalization.js.map +1 -0
  197. package/dist/lib/v2/projection/legacy-normalization.mjs +8 -0
  198. package/dist/lib/v2/projection/legacy-normalization.mjs.map +1 -0
  199. package/dist/lib/version.d.mts +3 -3
  200. package/dist/lib/version.d.ts +3 -3
  201. package/dist/lib/version.js +3 -3
  202. package/dist/lib/version.js.map +1 -1
  203. package/dist/lib/version.mjs +3 -3
  204. package/dist/lib/version.mjs.map +1 -1
  205. package/docs/guides/BUILD-AN-AGENT.md +42 -6
  206. package/docs/llms.txt +2 -2
  207. package/docs/migration-13-to-14.md +17 -0
  208. package/package.json +44 -41
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/context.ts"],"names":[],"mappings":"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"}
@@ -119,13 +119,18 @@ const CONTEXT_EXTRACTORS = {
119
119
  return { account_id: accounts[0].account_id };
120
120
  },
121
121
  get_products(data) {
122
- const d = data;
122
+ const d = asRecord(data);
123
123
  const products = d?.products;
124
- if (!products?.[0]) return {};
125
- const extracted = { products };
126
- if (products[0].product_id) extracted.product_id = products[0].product_id;
124
+ const extracted = {};
125
+ if (products?.[0]) {
126
+ extracted.products = products;
127
+ if (products[0].product_id) extracted.product_id = products[0].product_id;
128
+ }
127
129
  const proposals = d?.proposals;
128
130
  if (proposals?.[0]?.proposal_id) extracted.proposal_id = proposals[0].proposal_id;
131
+ if (d?.wholesale_feed_version !== void 0) extracted.wholesale_feed_version = d.wholesale_feed_version;
132
+ if (d?.pricing_version !== void 0) extracted.pricing_version = d.pricing_version;
133
+ if (d?.cache_scope !== void 0) extracted.cache_scope = d.cache_scope;
129
134
  return extracted;
130
135
  },
131
136
  list_products(data) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/testing/storyboard/context.ts"],"sourcesContent":["/**\n * Context propagation for storyboard steps.\n *\n * After each successful step, known IDs and references are extracted\n * from the response and accumulated in a StoryboardContext. Before\n * executing a step, context values are injected into the request via\n * \"$context.<key>\" placeholders.\n *\n * This convention-based approach avoids requiring YAML enrichment\n * (context_outputs/context_inputs) while still enabling stateful flows.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { StoryboardContext, ContextOutput, ContextInput, ContextProvenanceEntry } from './types';\nimport { resolvePath, setPath } from './path';\nimport { getAuthoritativeMediaBuyStatus } from '../../utils/media-buy-status';\n\n// ────────────────────────────────────────────────────────────\n// Context extraction: pull known IDs from task responses\n// ────────────────────────────────────────────────────────────\n\ntype ContextExtractor = (data: unknown) => Record<string, unknown>;\n\nconst PRODUCT_CONTEXT_KEYS = [\n 'product',\n 'products',\n 'product_id',\n 'pricing_option',\n 'pricing_option_id',\n 'feed_version',\n 'pricing_version',\n];\nconst PROPOSAL_CONTEXT_KEYS = [\n 'proposal',\n 'proposals',\n 'proposal_id',\n 'proposal_status',\n 'proposal_kind',\n 'terms_digest',\n 'proposal_terms_digest',\n];\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction readMediaBuyStatus(record: Record<string, unknown> | undefined): unknown {\n return getAuthoritativeMediaBuyStatus(record);\n}\n\nfunction readMediaBuyFields(data: unknown): { mediaBuyId?: unknown; status?: unknown } {\n const outer = asRecord(data);\n const nested = asRecord(outer?.media_buy);\n return {\n mediaBuyId: nested?.media_buy_id ?? outer?.media_buy_id,\n status: readMediaBuyStatus(nested) ?? readMediaBuyStatus(outer),\n };\n}\n\nfunction readProposalFields(proposal: Record<string, unknown> | undefined): Record<string, unknown> {\n if (!proposal) return {};\n const extracted: Record<string, unknown> = {};\n if (proposal.proposal_id) extracted.proposal_id = proposal.proposal_id;\n if (proposal.proposal_status) extracted.proposal_status = proposal.proposal_status;\n if (proposal.proposal_kind) extracted.proposal_kind = proposal.proposal_kind;\n if (proposal.terms_digest) {\n extracted.terms_digest = proposal.terms_digest;\n extracted.proposal_terms_digest = proposal.terms_digest;\n }\n return extracted;\n}\n\nfunction readCompactMediaBuyFields(data: unknown): Record<string, unknown> {\n const outer = asRecord(data);\n if (!outer || outer.status !== 'completed') return {};\n const mediaBuyId = outer.media_buy_id;\n // Compact responses use `status` for task completion and\n // `media_buy_status` for lifecycle state. Never reinterpret a bare\n // `status: completed` as the MediaBuy's status when the optional lifecycle\n // field is absent.\n const status = readMediaBuyStatus({ media_buy_status: outer.media_buy_status });\n const acceptedProposal = asRecord(outer.accepted_proposal);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n if (outer.revision) {\n extracted.revision = outer.revision;\n extracted.media_buy_revision = outer.revision;\n }\n if (acceptedProposal) {\n Object.assign(extracted, readProposalFields(acceptedProposal));\n }\n if (Array.isArray(outer.available_actions)) extracted.available_actions = outer.available_actions;\n return extracted;\n}\n\nexport const CONTEXT_EXTRACTORS: Record<string, ContextExtractor> = {\n sync_accounts(data) {\n const d = data as Record<string, unknown> | undefined;\n const accounts = d?.accounts as Array<Record<string, unknown>> | undefined;\n if (!accounts?.[0]) return {};\n const first = accounts[0];\n const extracted: Record<string, unknown> = {};\n if (first.account_id) extracted.account_id = first.account_id;\n if (first.status) extracted.account_status = first.status;\n // Build an account reference for downstream steps. Only include fields\n // the response actually carries — propagating `operator: undefined`\n // would serialize away on the wire (JSON.stringify drops undefined),\n // leaving the natural-key arm short of its required `operator` field\n // (#1419). The brand/operator pair stays paired or both absent.\n const accountRef: Record<string, unknown> = {};\n if (first.brand) accountRef.brand = first.brand;\n if (first.operator) accountRef.operator = first.operator;\n extracted.account = accountRef;\n return extracted;\n },\n\n list_accounts(data) {\n const d = data as Record<string, unknown> | undefined;\n const accounts = d?.accounts as Array<Record<string, unknown>> | undefined;\n if (!accounts?.[0]) return {};\n return { account_id: accounts[0].account_id };\n },\n\n get_products(data) {\n const d = data as Record<string, unknown> | undefined;\n const products = d?.products as Array<Record<string, unknown>> | undefined;\n if (!products?.[0]) return {};\n const extracted: Record<string, unknown> = { products };\n if (products[0].product_id) extracted.product_id = products[0].product_id;\n // Extract proposal_id if proposals are returned\n const proposals = d?.proposals as Array<Record<string, unknown>> | undefined;\n if (proposals?.[0]?.proposal_id) extracted.proposal_id = proposals[0].proposal_id;\n return extracted;\n },\n\n list_products(data) {\n const d = asRecord(data);\n const products = d?.products as Array<Record<string, unknown>> | undefined;\n if (!products?.[0]) return {};\n const first = products[0];\n const pricingOptions = first.pricing_options as Array<Record<string, unknown>> | undefined;\n const extracted: Record<string, unknown> = {};\n if (first.product_id) extracted.product_id = first.product_id;\n if (pricingOptions?.[0]) {\n if (pricingOptions[0].pricing_option_id) extracted.pricing_option_id = pricingOptions[0].pricing_option_id;\n }\n if (d?.feed_version) extracted.feed_version = d.feed_version;\n if (d?.pricing_version) extracted.pricing_version = d.pricing_version;\n return extracted;\n },\n\n request_proposals(data) {\n const d = asRecord(data);\n const proposals = d?.proposals as Array<Record<string, unknown>> | undefined;\n if (!proposals?.[0]) return {};\n return readProposalFields(proposals[0]);\n },\n\n refine_proposals(data) {\n const d = asRecord(data);\n const results = d?.results as Array<Record<string, unknown>> | undefined;\n if (!results?.length) return {};\n const proposalResult = results.find(result => asRecord(result.proposal) || Array.isArray(result.proposals));\n const proposal =\n asRecord(proposalResult?.proposal) ??\n (proposalResult?.proposals as Array<Record<string, unknown>> | undefined)?.[0] ??\n undefined;\n return proposal ? readProposalFields(proposal) : {};\n },\n\n decline_proposals() {\n return {};\n },\n\n buy_products(data) {\n return readCompactMediaBuyFields(data);\n },\n\n accept_proposal(data) {\n return readCompactMediaBuyFields(data);\n },\n\n control_media_buy(data) {\n return readCompactMediaBuyFields(data);\n },\n\n create_media_buy(data) {\n const { mediaBuyId, status } = readMediaBuyFields(data);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n return extracted;\n },\n\n update_media_buy(data) {\n const { mediaBuyId, status } = readMediaBuyFields(data);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n return extracted;\n },\n\n get_media_buys(data) {\n const d = data as Record<string, unknown> | undefined;\n const buys = d?.media_buys as Array<Record<string, unknown>> | undefined;\n if (!buys?.[0]) return {};\n // Don't extract a single-resource ID from a broad-list page. When\n // has_more: true the caller is mid-pagination walk and buys[0] is not\n // the canonical buy — extracting it here causes the enricher to inject\n // media_buy_ids: [that_id] on the next step, turning a continuation into\n // an ID-lookup. Conservative: === true matches the codebase convention\n // (absent has_more is treated as terminal, not as a list-in-progress).\n const pagination = d?.pagination as Record<string, unknown> | undefined;\n if (pagination?.has_more === true) return {};\n const extracted: Record<string, unknown> = {\n media_buy_id: buys[0].media_buy_id,\n media_buy_status: readMediaBuyStatus(buys[0]),\n };\n if (buys[0].revision) {\n extracted.revision = buys[0].revision;\n extracted.media_buy_revision = buys[0].revision;\n }\n if (Array.isArray(buys[0].available_actions)) extracted.available_actions = buys[0].available_actions;\n return extracted;\n },\n\n list_creative_formats(data) {\n const d = data as Record<string, unknown> | undefined;\n const formats = d?.formats as Array<Record<string, unknown>> | undefined;\n if (!formats?.[0]) return {};\n return {\n formats,\n format_id: formats[0].format_id,\n };\n },\n\n build_creative(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n // Single response: creative_manifest\n const manifest = d?.creative_manifest as Record<string, unknown> | undefined;\n if (manifest) {\n extracted.creative_manifest = manifest;\n if (manifest.format_id) extracted.format_id = manifest.format_id;\n }\n // Multi response: creative_manifests\n const manifests = d?.creative_manifests as Array<Record<string, unknown>> | undefined;\n if (manifests?.[0]) {\n extracted.creative_manifests = manifests;\n if (manifests[0].format_id) extracted.format_id = manifests[0].format_id;\n }\n // Variant response: creatives[].variants[] (BuildCreativeVariantSuccess).\n const creatives = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (creatives?.[0]) {\n extracted.creatives = creatives;\n\n const variants = creatives.flatMap(creative => {\n const creativeVariants = creative.variants as Array<Record<string, unknown>> | undefined;\n return Array.isArray(creativeVariants) ? creativeVariants : [];\n });\n if (variants[0]) {\n extracted.variants = variants;\n if (variants[0].build_variant_id) extracted.build_variant_id = variants[0].build_variant_id;\n\n const variantManifest = variants[0].creative_manifest as Record<string, unknown> | undefined;\n if (variantManifest) {\n extracted.creative_manifest ??= variantManifest;\n if (!extracted.format_id && variantManifest.format_id) extracted.format_id = variantManifest.format_id;\n }\n }\n }\n return extracted;\n },\n\n sync_creatives(data) {\n const d = data as Record<string, unknown> | undefined;\n const results = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (!results?.length) return {};\n return { creative_results: results };\n },\n\n list_creatives(data) {\n const d = data as Record<string, unknown> | undefined;\n const creatives = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (!creatives?.[0]) return {};\n const extracted: Record<string, unknown> = { creatives };\n if (creatives[0].creative_id) extracted.creative_id = creatives[0].creative_id;\n return extracted;\n },\n\n preview_creative(data) {\n const d = data as Record<string, unknown> | undefined;\n const previews = d?.previews as Array<Record<string, unknown>> | undefined;\n if (!previews?.length) return {};\n return { previews };\n },\n\n get_signals(data) {\n const d = data as Record<string, unknown> | undefined;\n const signals = d?.signals as Array<Record<string, unknown>> | undefined;\n if (!signals?.[0]) return {};\n return {\n signals,\n signal_id: signals[0].signal_id,\n };\n },\n\n activate_signal(data) {\n const d = data as Record<string, unknown> | undefined;\n const deployments = d?.deployments as Array<Record<string, unknown>> | undefined;\n if (!deployments?.[0]) return {};\n const first = deployments[0];\n const extracted: Record<string, unknown> = { deployments };\n if (first.activation_key) extracted.activation_key = first.activation_key;\n if (first.type) extracted.deployment_type = first.type;\n return extracted;\n },\n\n sync_catalogs(data) {\n const d = data as Record<string, unknown> | undefined;\n const catalogs = d?.catalogs as Array<Record<string, unknown>> | undefined;\n if (!catalogs?.[0]) return {};\n const extracted: Record<string, unknown> = { catalogs };\n if (catalogs[0].catalog_id) extracted.catalog_id = catalogs[0].catalog_id;\n return extracted;\n },\n\n sync_audiences(data) {\n const d = data as Record<string, unknown> | undefined;\n const audiences = d?.audiences as Array<Record<string, unknown>> | undefined;\n if (!audiences?.[0]) return {};\n const extracted: Record<string, unknown> = { audiences };\n if (audiences[0].audience_id) extracted.audience_id = audiences[0].audience_id;\n return extracted;\n },\n\n sync_event_sources(data) {\n const d = data as Record<string, unknown> | undefined;\n const sources = d?.event_sources as Array<Record<string, unknown>> | undefined;\n if (!sources?.[0]) return {};\n const extracted: Record<string, unknown> = { event_sources: sources };\n if (sources[0].event_source_id) extracted.event_source_id = sources[0].event_source_id;\n return extracted;\n },\n\n si_initiate_session(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.session_id) extracted.session_id = d.session_id;\n return extracted;\n },\n\n si_get_offering(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.offering_id) extracted.offering_id = d.offering_id;\n const offerings = d?.offerings as Array<Record<string, unknown>> | undefined;\n if (offerings?.[0]?.offering_id) extracted.offering_id = offerings[0].offering_id;\n return extracted;\n },\n\n sync_plans(data) {\n const d = data as Record<string, unknown> | undefined;\n const plans = d?.plans as Array<Record<string, unknown>> | undefined;\n if (!plans?.[0]) return {};\n return { plan_id: plans[0].plan_id };\n },\n\n create_property_list(data) {\n const d = data as Record<string, unknown> | undefined;\n const list = d?.list as Record<string, unknown> | undefined;\n if (!list) return {};\n const extracted: Record<string, unknown> = {};\n if (list.list_id) extracted.property_list_id = list.list_id;\n if (list.name) extracted.property_list_name = list.name;\n // auth_token intentionally not extracted — avoid leaking credentials into\n // storyboard context which may appear in logs or compliance reports.\n return extracted;\n },\n\n create_content_standards(data) {\n const d = data as Record<string, unknown> | undefined;\n if (!d?.standards_id) return {};\n return { content_standards_id: d.standards_id };\n },\n\n get_rights(data) {\n const d = data as Record<string, unknown> | undefined;\n const rights = d?.rights as Array<Record<string, unknown>> | undefined;\n if (!rights?.[0]?.rights_id) return {};\n return { rights_id: rights[0].rights_id };\n },\n\n acquire_rights(data) {\n const d = data as Record<string, unknown> | undefined;\n if (!d?.rights_grant_id) return {};\n return { rights_grant_id: d.rights_grant_id, rights_id: d.rights_id };\n },\n\n sync_governance(data) {\n // Governance registration — no IDs to extract, just confirmation\n return { governance_synced: true, governance_response: data };\n },\n\n check_governance(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.governance_context) extracted.governance_context = d.governance_context;\n if (d?.check_id) extracted.check_id = d.check_id;\n if (d?.plan_id) extracted.plan_id = d.plan_id;\n if (d?.verdict) extracted.governance_status = d.verdict;\n return extracted;\n },\n\n report_plan_outcome(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.outcome_id) extracted.outcome_id = d.outcome_id;\n if (d?.outcome_state) extracted.outcome_status = d.outcome_state;\n return extracted;\n },\n};\n\n/**\n * Extract context values from a task response.\n */\nexport function extractContext(taskName: string, data: unknown): Record<string, unknown> {\n const extractor = CONTEXT_EXTRACTORS[taskName];\n if (!extractor) return {};\n try {\n return extractor(data);\n } catch {\n return {};\n }\n}\n\n// ────────────────────────────────────────────────────────────\n// Context injection: substitute $context.<key> in requests\n// ────────────────────────────────────────────────────────────\n\n/**\n * Per-context alias cache for `$generate:uuid_v4#<alias>` placeholders.\n *\n * A WeakMap keyed off the StoryboardContext identity avoids landing\n * implementation-detail keys on the serialized context object and avoids\n * fragility when context is shallow-cloned between steps — the cache\n * follows the context reference rather than riding as an owned key.\n *\n * Propagation across steps is handled by `forwardAliasCache` (called by\n * the runner when it rolls context forward to the next step), keeping\n * this a deliberate design choice rather than an invisible by-reference\n * leak through `{ ...context }`.\n */\nconst aliasCaches = new WeakMap<StoryboardContext, Record<string, string>>();\n\n/**\n * Ensure an alias cache exists for the given context and return it.\n */\nfunction getAliasCache(context: StoryboardContext): Record<string, string> {\n let cache = aliasCaches.get(context);\n if (!cache) {\n cache = {};\n aliasCaches.set(context, cache);\n }\n return cache;\n}\n\n/**\n * Propagate the alias cache from one context to another — call after\n * shallow-cloning context between storyboard steps so replay tests\n * (initial + replay sharing `$generate:uuid_v4#<alias>`) resolve to the\n * same UUID. No-op when `from` has no cache.\n */\nexport function forwardAliasCache(from: StoryboardContext, to: StoryboardContext): void {\n const cache = aliasCaches.get(from);\n if (cache) aliasCaches.set(to, cache);\n}\n\n/**\n * Runner-owned substitution variables.\n *\n * Parallels `$context.*` but lives outside the serialized context object so\n * implementation details (the receiver's bound URL, per-step operation ids)\n * stay off the compliance report. Expanded within strings (embedded\n * substitution), unlike `$context.*` which matches whole strings only.\n *\n * Supported patterns:\n * - `{{runner.webhook_base}}` — base URL of the receiver.\n * - `{{runner.webhook_url:<step_id>}}` — per-step webhook URL\n * (`<base>/step/<step_id>/<operation_id>`). The operation_id is minted\n * lazily on first expansion and cached for the rest of the run so the\n * matching `{{prior_step.<step_id>.operation_id}}` reference downstream\n * resolves to the same value.\n * - `{{prior_step.<step_id>.operation_id}}` — operation_id the runner\n * allocated when expanding `{{runner.webhook_url:<step_id>}}`.\n */\nexport interface RunnerVariables {\n /** Millisecond timestamp captured once at run start for deterministic enrichment. */\n runStartMs?: number;\n /** Base URL of the runner's webhook receiver, when enabled. */\n webhookBase?: string;\n /** step_id → operation_id, filled lazily on expansion. */\n stepOperationIds: Map<string, string>;\n /**\n * Free-form slot for cross-step run state that isn't user-facing. Used\n * today to share a single `InMemoryReplayStore` / `InMemoryRevocationStore`\n * across every `expect_webhook_signature_valid` call in a run so a\n * replayed (keyid, nonce) across two deliveries of the same event is\n * actually detected. Untyped here to keep the context module free of\n * signing-module imports.\n */\n runState: Map<string, unknown>;\n}\n\nexport function createRunnerVariables(opts: { webhookBase?: string } = {}): RunnerVariables {\n return {\n runStartMs: Date.now(),\n ...(opts.webhookBase !== undefined && { webhookBase: opts.webhookBase }),\n stepOperationIds: new Map(),\n runState: new Map(),\n };\n}\n\n/**\n * Deep-walk an object and replace recognized placeholder strings:\n *\n * - `$context.<key>` → value from `context[key]` (anchored whole-string match)\n * - `$generate:uuid_v4` → fresh UUID v4 per occurrence (anchored)\n * - `$generate:uuid_v4#<alias>` → fresh UUID v4 on first occurrence, then the\n * same UUID for every subsequent occurrence of the same alias within this\n * run (anchored)\n * - `{{runner.*}}` / `{{prior_step.<id>.operation_id}}` → embedded runner-\n * variable substitution (only when `runnerVars` is supplied)\n *\n * Returns a new object (does not mutate the input).\n */\nexport function injectContext(\n obj: Record<string, unknown>,\n context: StoryboardContext,\n runnerVars?: RunnerVariables\n): Record<string, unknown> {\n return deepReplace(obj, context, runnerVars) as Record<string, unknown>;\n}\n\nfunction deepReplace(value: unknown, context: StoryboardContext, runnerVars?: RunnerVariables): unknown {\n if (typeof value === 'string') {\n // Mustache first — expands in-place within the string, so anchored\n // patterns below still apply to the post-expansion result.\n const expanded = runnerVars ? expandMustache(value, runnerVars) : value;\n\n const ctxMatch = expanded.match(/^\\$context\\.(\\w+)$/);\n if (ctxMatch?.[1]) {\n const key = ctxMatch[1];\n return key in context ? context[key] : expanded;\n }\n const genMatch = expanded.match(/^\\$generate:(uuid_v4|opaque_id)(?:#([A-Za-z0-9_.-]+))?$/);\n if (genMatch) {\n const alias = genMatch[2];\n if (alias) {\n const cache = getAliasCache(context);\n if (!(alias in cache)) cache[alias] = randomUUID();\n return cache[alias];\n }\n return randomUUID();\n }\n return expanded;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => deepReplace(item, context, runnerVars));\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n result[k] = deepReplace(v, context, runnerVars);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * Expand every `{{runner.*}}` and `{{prior_step.*}}` token in a string.\n * Unknown tokens are left in place so the runner can surface a pointed\n * \"unresolved substitution\" error rather than silently shipping the\n * literal mustache tokens to an agent.\n */\n/**\n * Token shape for the outer expander. Single `[^{}]+` (excludes braces on\n * both sides) so nested or partial `{{…` can't straddle a token boundary\n * and force the engine to backtrack character-by-character. Unified prefix\n * alternation (`runner|prior_step`) keeps the two recognized names in one\n * place — the inner expander still narrows each. Closes CodeQL alert #49\n * (js/polynomial-redos).\n */\nconst MUSTACHE_TOKEN_RE = /\\{\\{((?:runner|prior_step)\\.[^{}]+)\\}\\}/g;\n\nfunction expandMustache(input: string, runnerVars: RunnerVariables): string {\n return input.replace(MUSTACHE_TOKEN_RE, (match, inner) => {\n if (inner === 'runner.webhook_base') {\n return runnerVars.webhookBase ?? match;\n }\n const webhookUrlMatch = /^runner\\.webhook_url:([A-Za-z0-9_]+)$/.exec(inner);\n if (webhookUrlMatch?.[1]) {\n if (!runnerVars.webhookBase) return match;\n const stepId = webhookUrlMatch[1];\n let opId = runnerVars.stepOperationIds.get(stepId);\n if (!opId) {\n opId = randomUUID();\n runnerVars.stepOperationIds.set(stepId, opId);\n }\n return `${runnerVars.webhookBase}/step/${stepId}/${opId}`;\n }\n const priorMatch = /^prior_step\\.([A-Za-z0-9_]+)\\.operation_id$/.exec(inner);\n if (priorMatch?.[1]) {\n return runnerVars.stepOperationIds.get(priorMatch[1]) ?? match;\n }\n return match;\n });\n}\n\n// ────────────────────────────────────────────────────────────\n// Explicit context_outputs: extract values by path\n// ────────────────────────────────────────────────────────────\n\n/**\n * Apply explicit context_outputs rules to extract values from response data.\n * Entries with `generate` set are skipped — use `applyContextOutputsWithProvenance`\n * (which accepts a context for alias-cache access) to handle those.\n *\n * Per runner-output-contract.yaml v2.0.0, paths that resolve to `undefined`,\n * `null`, or `\"\"` are equally non-resolvable — capturing null or \"\" produces\n * fabricated downstream state. The provenance-aware variant additionally\n * surfaces the failures on `ContextWriteResult.failures` so the runner can\n * synthesize a `capture_path_not_resolvable` validation result; this lower-\n * level form drops them silently and is kept for callers that don't need\n * the structured failure surface.\n */\nexport function applyContextOutputs(data: unknown, outputs: ContextOutput[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const output of outputs) {\n if (!output.path) continue;\n const value = resolvePath(data, output.path);\n if (value !== undefined && value !== null && value !== '') {\n result[output.key] = value;\n }\n }\n return result;\n}\n\n/**\n * Result of a context write with per-key provenance. The runner consumes\n * `provenance` to emit `context_value_rejected` hints when a later step's\n * seller response rejects a value that traces back to one of these keys.\n * `values` carries the same Record as the non-provenance call so the\n * runner's downstream `Object.assign(updatedContext, values)` path is\n * unchanged.\n */\nexport interface ContextWriteResult {\n values: Record<string, unknown>;\n provenance: Record<string, ContextProvenanceEntry>;\n /**\n * Convention-owned alias groups that must be removed before applying\n * `values`. Conditional groups only clear when the current context key\n * matches one of the response-derived values.\n */\n clearGroups?: Array<{\n keys: string[];\n when?: { key: string; values: unknown[] };\n }>;\n /**\n * `path:` entries whose declared response path did not resolve to a usable\n * value (absent, `null`, or `\"\"`). Per runner-output-contract.yaml v2.0.0,\n * the runner synthesizes a `capture_path_not_resolvable` validation result\n * for each entry — capturing null or \"\" produces fabricated downstream\n * state and is as incorrect as a missing path. Generator entries do not\n * appear here; they cannot fail to resolve. Absent or empty when every\n * `path:` entry produced a value.\n */\n failures?: Array<{ key: string; path: string; resolved: unknown }>;\n}\n\n/**\n * Like `extractContext`, but also returns provenance for each written key\n * tagging it as a convention-based extraction. `response_path` is absent\n * for convention extractors — they're hardcoded functions, not YAML paths.\n */\nexport function extractContextWithProvenance(taskName: string, data: unknown, stepId: string): ContextWriteResult {\n const values = extractContext(taskName, data);\n const clearGroups = (() => {\n const response = asRecord(data);\n switch (taskName) {\n case 'list_products':\n return response?.outcome === 'listed' && Array.isArray(response.products)\n ? [{ keys: PRODUCT_CONTEXT_KEYS }]\n : undefined;\n case 'request_proposals':\n return values.proposal_id ? [{ keys: PROPOSAL_CONTEXT_KEYS }] : undefined;\n case 'refine_proposals':\n return values.proposal_id ? [{ keys: PROPOSAL_CONTEXT_KEYS }] : undefined;\n case 'decline_proposals':\n const declinedIds = Array.isArray(response?.results)\n ? response.results\n .map(asRecord)\n .filter(result => result?.outcome === 'declined')\n .map(result => result?.proposal_id)\n .filter(proposalId => proposalId !== undefined)\n : [];\n return declinedIds.length\n ? [{ keys: PROPOSAL_CONTEXT_KEYS, when: { key: 'proposal_id', values: declinedIds } }]\n : undefined;\n default:\n return undefined;\n }\n })();\n const provenance: Record<string, ContextProvenanceEntry> = {};\n for (const key of Object.keys(values)) {\n provenance[key] = {\n source_step_id: stepId,\n source_kind: 'convention',\n source_task: taskName,\n };\n }\n return { values, provenance, ...(clearGroups && { clearGroups }) };\n}\n\n/**\n * Like `applyContextOutputs`, but also returns provenance for each written\n * key carrying the YAML `response_path` so diagnostics can cite it verbatim.\n *\n * Pass `context` to enable `generate:` entries with alias-cache coherence.\n * When an output declares `generate`, the runner mints a UUID v4 (or reuses\n * the value already cached under `output.key` if an inline `$generate:…#<alias>`\n * substitution ran in the same step). The generated value is written back into\n * the alias cache so that any later step referencing `$generate:opaque_id#<key>`\n * resolves to the same UUID.\n *\n * Omitting `context` disables alias-cache coherence: each generator entry mints\n * an independent UUID that cannot be matched by an inline `$generate:…` form.\n *\n * Generator entries fire regardless of whether `data` is present; path\n * entries are silently skipped when the resolved value is null/undefined.\n */\nexport function applyContextOutputsWithProvenance(\n data: unknown,\n outputs: ContextOutput[],\n stepId: string,\n taskName: string,\n context?: StoryboardContext\n): ContextWriteResult {\n const values: Record<string, unknown> = {};\n const provenance: Record<string, ContextProvenanceEntry> = {};\n const failures: Array<{ key: string; path: string; resolved: unknown }> = [];\n for (const output of outputs) {\n if (output.generate !== undefined) {\n // Generator entries require a context — without one the alias cache\n // can't be populated, so a later step's `$generate:opaque_id#<key>` would\n // mint an independent UUID that doesn't match the value stored here.\n // Loud error beats silent divergence.\n if (!context) {\n throw new Error(\n `applyContextOutputsWithProvenance: context_outputs entry '${output.key}' ` +\n `declares generate='${output.generate}' but no context was provided. ` +\n `Generator entries require a context for alias-cache coherence.`\n );\n }\n const cache = getAliasCache(context);\n let value: string;\n if (output.key in cache) {\n value = cache[output.key]!;\n } else {\n value = randomUUID();\n cache[output.key] = value;\n }\n values[output.key] = value;\n provenance[output.key] = {\n source_step_id: stepId,\n source_kind: 'generator',\n source_task: taskName,\n };\n } else if (output.path) {\n const value = resolvePath(data, output.path);\n // Per runner-output-contract.yaml v2.0.0 / storyboard-schema.yaml,\n // null, \"\", and structurally-absent paths are equally non-resolvable\n // for capture purposes — capturing null or \"\" produces fabricated\n // downstream state and is as incorrect as a missing path.\n const resolved = value === undefined || value === null || value === '';\n if (!resolved) {\n values[output.key] = value;\n provenance[output.key] = {\n source_step_id: stepId,\n source_kind: 'context_outputs',\n response_path: output.path,\n source_task: taskName,\n };\n } else {\n failures.push({\n key: output.key,\n path: output.path,\n resolved: value === undefined ? null : value,\n });\n }\n }\n }\n return { values, provenance, ...(failures.length > 0 ? { failures } : {}) };\n}\n\n// ────────────────────────────────────────────────────────────\n// Explicit context_inputs: inject values into request by path\n// ────────────────────────────────────────────────────────────\n\n/**\n * Apply explicit context_inputs rules to inject context values into a request.\n * Returns a new object (does not mutate the input).\n */\nexport function applyContextInputs(\n request: Record<string, unknown>,\n inputs: ContextInput[],\n context: StoryboardContext\n): Record<string, unknown> {\n const result = structuredClone(request);\n for (const input of inputs) {\n if (input.key in context) {\n setPath(result, input.inject_at, context[input.key]);\n }\n }\n return result;\n}\n\n// setPath is re-exported from ./path for backwards compat\nexport { setPath } from './path';\n"],"mappings":"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","names":["import_path"]}
1
+ {"version":3,"sources":["../../../../src/lib/testing/storyboard/context.ts"],"sourcesContent":["/**\n * Context propagation for storyboard steps.\n *\n * After each successful step, known IDs and references are extracted\n * from the response and accumulated in a StoryboardContext. Before\n * executing a step, context values are injected into the request via\n * \"$context.<key>\" placeholders.\n *\n * This convention-based approach avoids requiring YAML enrichment\n * (context_outputs/context_inputs) while still enabling stateful flows.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { StoryboardContext, ContextOutput, ContextInput, ContextProvenanceEntry } from './types';\nimport { resolvePath, setPath } from './path';\nimport { getAuthoritativeMediaBuyStatus } from '../../utils/media-buy-status';\n\n// ────────────────────────────────────────────────────────────\n// Context extraction: pull known IDs from task responses\n// ────────────────────────────────────────────────────────────\n\ntype ContextExtractor = (data: unknown) => Record<string, unknown>;\n\nconst PRODUCT_CONTEXT_KEYS = [\n 'product',\n 'products',\n 'product_id',\n 'pricing_option',\n 'pricing_option_id',\n 'feed_version',\n 'pricing_version',\n];\nconst PROPOSAL_CONTEXT_KEYS = [\n 'proposal',\n 'proposals',\n 'proposal_id',\n 'proposal_status',\n 'proposal_kind',\n 'terms_digest',\n 'proposal_terms_digest',\n];\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction readMediaBuyStatus(record: Record<string, unknown> | undefined): unknown {\n return getAuthoritativeMediaBuyStatus(record);\n}\n\nfunction readMediaBuyFields(data: unknown): { mediaBuyId?: unknown; status?: unknown } {\n const outer = asRecord(data);\n const nested = asRecord(outer?.media_buy);\n return {\n mediaBuyId: nested?.media_buy_id ?? outer?.media_buy_id,\n status: readMediaBuyStatus(nested) ?? readMediaBuyStatus(outer),\n };\n}\n\nfunction readProposalFields(proposal: Record<string, unknown> | undefined): Record<string, unknown> {\n if (!proposal) return {};\n const extracted: Record<string, unknown> = {};\n if (proposal.proposal_id) extracted.proposal_id = proposal.proposal_id;\n if (proposal.proposal_status) extracted.proposal_status = proposal.proposal_status;\n if (proposal.proposal_kind) extracted.proposal_kind = proposal.proposal_kind;\n if (proposal.terms_digest) {\n extracted.terms_digest = proposal.terms_digest;\n extracted.proposal_terms_digest = proposal.terms_digest;\n }\n return extracted;\n}\n\nfunction readCompactMediaBuyFields(data: unknown): Record<string, unknown> {\n const outer = asRecord(data);\n if (!outer || outer.status !== 'completed') return {};\n const mediaBuyId = outer.media_buy_id;\n // Compact responses use `status` for task completion and\n // `media_buy_status` for lifecycle state. Never reinterpret a bare\n // `status: completed` as the MediaBuy's status when the optional lifecycle\n // field is absent.\n const status = readMediaBuyStatus({ media_buy_status: outer.media_buy_status });\n const acceptedProposal = asRecord(outer.accepted_proposal);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n if (outer.revision) {\n extracted.revision = outer.revision;\n extracted.media_buy_revision = outer.revision;\n }\n if (acceptedProposal) {\n Object.assign(extracted, readProposalFields(acceptedProposal));\n }\n if (Array.isArray(outer.available_actions)) extracted.available_actions = outer.available_actions;\n return extracted;\n}\n\nexport const CONTEXT_EXTRACTORS: Record<string, ContextExtractor> = {\n sync_accounts(data) {\n const d = data as Record<string, unknown> | undefined;\n const accounts = d?.accounts as Array<Record<string, unknown>> | undefined;\n if (!accounts?.[0]) return {};\n const first = accounts[0];\n const extracted: Record<string, unknown> = {};\n if (first.account_id) extracted.account_id = first.account_id;\n if (first.status) extracted.account_status = first.status;\n // Build an account reference for downstream steps. Only include fields\n // the response actually carries — propagating `operator: undefined`\n // would serialize away on the wire (JSON.stringify drops undefined),\n // leaving the natural-key arm short of its required `operator` field\n // (#1419). The brand/operator pair stays paired or both absent.\n const accountRef: Record<string, unknown> = {};\n if (first.brand) accountRef.brand = first.brand;\n if (first.operator) accountRef.operator = first.operator;\n extracted.account = accountRef;\n return extracted;\n },\n\n list_accounts(data) {\n const d = data as Record<string, unknown> | undefined;\n const accounts = d?.accounts as Array<Record<string, unknown>> | undefined;\n if (!accounts?.[0]) return {};\n return { account_id: accounts[0].account_id };\n },\n\n get_products(data) {\n const d = asRecord(data);\n const products = d?.products as Array<Record<string, unknown>> | undefined;\n const extracted: Record<string, unknown> = {};\n if (products?.[0]) {\n extracted.products = products;\n if (products[0].product_id) extracted.product_id = products[0].product_id;\n }\n // Extract proposal_id if proposals are returned\n const proposals = d?.proposals as Array<Record<string, unknown>> | undefined;\n if (proposals?.[0]?.proposal_id) extracted.proposal_id = proposals[0].proposal_id;\n // Wholesale conditional-fetch steps need the response's scope and version\n // metadata even when `unchanged: true` legitimately omits product rows.\n if (d?.wholesale_feed_version !== undefined) extracted.wholesale_feed_version = d.wholesale_feed_version;\n if (d?.pricing_version !== undefined) extracted.pricing_version = d.pricing_version;\n if (d?.cache_scope !== undefined) extracted.cache_scope = d.cache_scope;\n return extracted;\n },\n\n list_products(data) {\n const d = asRecord(data);\n const products = d?.products as Array<Record<string, unknown>> | undefined;\n if (!products?.[0]) return {};\n const first = products[0];\n const pricingOptions = first.pricing_options as Array<Record<string, unknown>> | undefined;\n const extracted: Record<string, unknown> = {};\n if (first.product_id) extracted.product_id = first.product_id;\n if (pricingOptions?.[0]) {\n if (pricingOptions[0].pricing_option_id) extracted.pricing_option_id = pricingOptions[0].pricing_option_id;\n }\n if (d?.feed_version) extracted.feed_version = d.feed_version;\n if (d?.pricing_version) extracted.pricing_version = d.pricing_version;\n return extracted;\n },\n\n request_proposals(data) {\n const d = asRecord(data);\n const proposals = d?.proposals as Array<Record<string, unknown>> | undefined;\n if (!proposals?.[0]) return {};\n return readProposalFields(proposals[0]);\n },\n\n refine_proposals(data) {\n const d = asRecord(data);\n const results = d?.results as Array<Record<string, unknown>> | undefined;\n if (!results?.length) return {};\n const proposalResult = results.find(result => asRecord(result.proposal) || Array.isArray(result.proposals));\n const proposal =\n asRecord(proposalResult?.proposal) ??\n (proposalResult?.proposals as Array<Record<string, unknown>> | undefined)?.[0] ??\n undefined;\n return proposal ? readProposalFields(proposal) : {};\n },\n\n decline_proposals() {\n return {};\n },\n\n buy_products(data) {\n return readCompactMediaBuyFields(data);\n },\n\n accept_proposal(data) {\n return readCompactMediaBuyFields(data);\n },\n\n control_media_buy(data) {\n return readCompactMediaBuyFields(data);\n },\n\n create_media_buy(data) {\n const { mediaBuyId, status } = readMediaBuyFields(data);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n return extracted;\n },\n\n update_media_buy(data) {\n const { mediaBuyId, status } = readMediaBuyFields(data);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n return extracted;\n },\n\n get_media_buys(data) {\n const d = data as Record<string, unknown> | undefined;\n const buys = d?.media_buys as Array<Record<string, unknown>> | undefined;\n if (!buys?.[0]) return {};\n // Don't extract a single-resource ID from a broad-list page. When\n // has_more: true the caller is mid-pagination walk and buys[0] is not\n // the canonical buy — extracting it here causes the enricher to inject\n // media_buy_ids: [that_id] on the next step, turning a continuation into\n // an ID-lookup. Conservative: === true matches the codebase convention\n // (absent has_more is treated as terminal, not as a list-in-progress).\n const pagination = d?.pagination as Record<string, unknown> | undefined;\n if (pagination?.has_more === true) return {};\n const extracted: Record<string, unknown> = {\n media_buy_id: buys[0].media_buy_id,\n media_buy_status: readMediaBuyStatus(buys[0]),\n };\n if (buys[0].revision) {\n extracted.revision = buys[0].revision;\n extracted.media_buy_revision = buys[0].revision;\n }\n if (Array.isArray(buys[0].available_actions)) extracted.available_actions = buys[0].available_actions;\n return extracted;\n },\n\n list_creative_formats(data) {\n const d = data as Record<string, unknown> | undefined;\n const formats = d?.formats as Array<Record<string, unknown>> | undefined;\n if (!formats?.[0]) return {};\n return {\n formats,\n format_id: formats[0].format_id,\n };\n },\n\n build_creative(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n // Single response: creative_manifest\n const manifest = d?.creative_manifest as Record<string, unknown> | undefined;\n if (manifest) {\n extracted.creative_manifest = manifest;\n if (manifest.format_id) extracted.format_id = manifest.format_id;\n }\n // Multi response: creative_manifests\n const manifests = d?.creative_manifests as Array<Record<string, unknown>> | undefined;\n if (manifests?.[0]) {\n extracted.creative_manifests = manifests;\n if (manifests[0].format_id) extracted.format_id = manifests[0].format_id;\n }\n // Variant response: creatives[].variants[] (BuildCreativeVariantSuccess).\n const creatives = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (creatives?.[0]) {\n extracted.creatives = creatives;\n\n const variants = creatives.flatMap(creative => {\n const creativeVariants = creative.variants as Array<Record<string, unknown>> | undefined;\n return Array.isArray(creativeVariants) ? creativeVariants : [];\n });\n if (variants[0]) {\n extracted.variants = variants;\n if (variants[0].build_variant_id) extracted.build_variant_id = variants[0].build_variant_id;\n\n const variantManifest = variants[0].creative_manifest as Record<string, unknown> | undefined;\n if (variantManifest) {\n extracted.creative_manifest ??= variantManifest;\n if (!extracted.format_id && variantManifest.format_id) extracted.format_id = variantManifest.format_id;\n }\n }\n }\n return extracted;\n },\n\n sync_creatives(data) {\n const d = data as Record<string, unknown> | undefined;\n const results = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (!results?.length) return {};\n return { creative_results: results };\n },\n\n list_creatives(data) {\n const d = data as Record<string, unknown> | undefined;\n const creatives = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (!creatives?.[0]) return {};\n const extracted: Record<string, unknown> = { creatives };\n if (creatives[0].creative_id) extracted.creative_id = creatives[0].creative_id;\n return extracted;\n },\n\n preview_creative(data) {\n const d = data as Record<string, unknown> | undefined;\n const previews = d?.previews as Array<Record<string, unknown>> | undefined;\n if (!previews?.length) return {};\n return { previews };\n },\n\n get_signals(data) {\n const d = data as Record<string, unknown> | undefined;\n const signals = d?.signals as Array<Record<string, unknown>> | undefined;\n if (!signals?.[0]) return {};\n return {\n signals,\n signal_id: signals[0].signal_id,\n };\n },\n\n activate_signal(data) {\n const d = data as Record<string, unknown> | undefined;\n const deployments = d?.deployments as Array<Record<string, unknown>> | undefined;\n if (!deployments?.[0]) return {};\n const first = deployments[0];\n const extracted: Record<string, unknown> = { deployments };\n if (first.activation_key) extracted.activation_key = first.activation_key;\n if (first.type) extracted.deployment_type = first.type;\n return extracted;\n },\n\n sync_catalogs(data) {\n const d = data as Record<string, unknown> | undefined;\n const catalogs = d?.catalogs as Array<Record<string, unknown>> | undefined;\n if (!catalogs?.[0]) return {};\n const extracted: Record<string, unknown> = { catalogs };\n if (catalogs[0].catalog_id) extracted.catalog_id = catalogs[0].catalog_id;\n return extracted;\n },\n\n sync_audiences(data) {\n const d = data as Record<string, unknown> | undefined;\n const audiences = d?.audiences as Array<Record<string, unknown>> | undefined;\n if (!audiences?.[0]) return {};\n const extracted: Record<string, unknown> = { audiences };\n if (audiences[0].audience_id) extracted.audience_id = audiences[0].audience_id;\n return extracted;\n },\n\n sync_event_sources(data) {\n const d = data as Record<string, unknown> | undefined;\n const sources = d?.event_sources as Array<Record<string, unknown>> | undefined;\n if (!sources?.[0]) return {};\n const extracted: Record<string, unknown> = { event_sources: sources };\n if (sources[0].event_source_id) extracted.event_source_id = sources[0].event_source_id;\n return extracted;\n },\n\n si_initiate_session(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.session_id) extracted.session_id = d.session_id;\n return extracted;\n },\n\n si_get_offering(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.offering_id) extracted.offering_id = d.offering_id;\n const offerings = d?.offerings as Array<Record<string, unknown>> | undefined;\n if (offerings?.[0]?.offering_id) extracted.offering_id = offerings[0].offering_id;\n return extracted;\n },\n\n sync_plans(data) {\n const d = data as Record<string, unknown> | undefined;\n const plans = d?.plans as Array<Record<string, unknown>> | undefined;\n if (!plans?.[0]) return {};\n return { plan_id: plans[0].plan_id };\n },\n\n create_property_list(data) {\n const d = data as Record<string, unknown> | undefined;\n const list = d?.list as Record<string, unknown> | undefined;\n if (!list) return {};\n const extracted: Record<string, unknown> = {};\n if (list.list_id) extracted.property_list_id = list.list_id;\n if (list.name) extracted.property_list_name = list.name;\n // auth_token intentionally not extracted — avoid leaking credentials into\n // storyboard context which may appear in logs or compliance reports.\n return extracted;\n },\n\n create_content_standards(data) {\n const d = data as Record<string, unknown> | undefined;\n if (!d?.standards_id) return {};\n return { content_standards_id: d.standards_id };\n },\n\n get_rights(data) {\n const d = data as Record<string, unknown> | undefined;\n const rights = d?.rights as Array<Record<string, unknown>> | undefined;\n if (!rights?.[0]?.rights_id) return {};\n return { rights_id: rights[0].rights_id };\n },\n\n acquire_rights(data) {\n const d = data as Record<string, unknown> | undefined;\n if (!d?.rights_grant_id) return {};\n return { rights_grant_id: d.rights_grant_id, rights_id: d.rights_id };\n },\n\n sync_governance(data) {\n // Governance registration — no IDs to extract, just confirmation\n return { governance_synced: true, governance_response: data };\n },\n\n check_governance(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.governance_context) extracted.governance_context = d.governance_context;\n if (d?.check_id) extracted.check_id = d.check_id;\n if (d?.plan_id) extracted.plan_id = d.plan_id;\n if (d?.verdict) extracted.governance_status = d.verdict;\n return extracted;\n },\n\n report_plan_outcome(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.outcome_id) extracted.outcome_id = d.outcome_id;\n if (d?.outcome_state) extracted.outcome_status = d.outcome_state;\n return extracted;\n },\n};\n\n/**\n * Extract context values from a task response.\n */\nexport function extractContext(taskName: string, data: unknown): Record<string, unknown> {\n const extractor = CONTEXT_EXTRACTORS[taskName];\n if (!extractor) return {};\n try {\n return extractor(data);\n } catch {\n return {};\n }\n}\n\n// ────────────────────────────────────────────────────────────\n// Context injection: substitute $context.<key> in requests\n// ────────────────────────────────────────────────────────────\n\n/**\n * Per-context alias cache for `$generate:uuid_v4#<alias>` placeholders.\n *\n * A WeakMap keyed off the StoryboardContext identity avoids landing\n * implementation-detail keys on the serialized context object and avoids\n * fragility when context is shallow-cloned between steps — the cache\n * follows the context reference rather than riding as an owned key.\n *\n * Propagation across steps is handled by `forwardAliasCache` (called by\n * the runner when it rolls context forward to the next step), keeping\n * this a deliberate design choice rather than an invisible by-reference\n * leak through `{ ...context }`.\n */\nconst aliasCaches = new WeakMap<StoryboardContext, Record<string, string>>();\n\n/**\n * Ensure an alias cache exists for the given context and return it.\n */\nfunction getAliasCache(context: StoryboardContext): Record<string, string> {\n let cache = aliasCaches.get(context);\n if (!cache) {\n cache = {};\n aliasCaches.set(context, cache);\n }\n return cache;\n}\n\n/**\n * Propagate the alias cache from one context to another — call after\n * shallow-cloning context between storyboard steps so replay tests\n * (initial + replay sharing `$generate:uuid_v4#<alias>`) resolve to the\n * same UUID. No-op when `from` has no cache.\n */\nexport function forwardAliasCache(from: StoryboardContext, to: StoryboardContext): void {\n const cache = aliasCaches.get(from);\n if (cache) aliasCaches.set(to, cache);\n}\n\n/**\n * Runner-owned substitution variables.\n *\n * Parallels `$context.*` but lives outside the serialized context object so\n * implementation details (the receiver's bound URL, per-step operation ids)\n * stay off the compliance report. Expanded within strings (embedded\n * substitution), unlike `$context.*` which matches whole strings only.\n *\n * Supported patterns:\n * - `{{runner.webhook_base}}` — base URL of the receiver.\n * - `{{runner.webhook_url:<step_id>}}` — per-step webhook URL\n * (`<base>/step/<step_id>/<operation_id>`). The operation_id is minted\n * lazily on first expansion and cached for the rest of the run so the\n * matching `{{prior_step.<step_id>.operation_id}}` reference downstream\n * resolves to the same value.\n * - `{{prior_step.<step_id>.operation_id}}` — operation_id the runner\n * allocated when expanding `{{runner.webhook_url:<step_id>}}`.\n */\nexport interface RunnerVariables {\n /** Millisecond timestamp captured once at run start for deterministic enrichment. */\n runStartMs?: number;\n /** Base URL of the runner's webhook receiver, when enabled. */\n webhookBase?: string;\n /** step_id → operation_id, filled lazily on expansion. */\n stepOperationIds: Map<string, string>;\n /**\n * Free-form slot for cross-step run state that isn't user-facing. Used\n * today to share a single `InMemoryReplayStore` / `InMemoryRevocationStore`\n * across every `expect_webhook_signature_valid` call in a run so a\n * replayed (keyid, nonce) across two deliveries of the same event is\n * actually detected. Untyped here to keep the context module free of\n * signing-module imports.\n */\n runState: Map<string, unknown>;\n}\n\nexport function createRunnerVariables(opts: { webhookBase?: string } = {}): RunnerVariables {\n return {\n runStartMs: Date.now(),\n ...(opts.webhookBase !== undefined && { webhookBase: opts.webhookBase }),\n stepOperationIds: new Map(),\n runState: new Map(),\n };\n}\n\n/**\n * Deep-walk an object and replace recognized placeholder strings:\n *\n * - `$context.<key>` → value from `context[key]` (anchored whole-string match)\n * - `$generate:uuid_v4` → fresh UUID v4 per occurrence (anchored)\n * - `$generate:uuid_v4#<alias>` → fresh UUID v4 on first occurrence, then the\n * same UUID for every subsequent occurrence of the same alias within this\n * run (anchored)\n * - `{{runner.*}}` / `{{prior_step.<id>.operation_id}}` → embedded runner-\n * variable substitution (only when `runnerVars` is supplied)\n *\n * Returns a new object (does not mutate the input).\n */\nexport function injectContext(\n obj: Record<string, unknown>,\n context: StoryboardContext,\n runnerVars?: RunnerVariables\n): Record<string, unknown> {\n return deepReplace(obj, context, runnerVars) as Record<string, unknown>;\n}\n\nfunction deepReplace(value: unknown, context: StoryboardContext, runnerVars?: RunnerVariables): unknown {\n if (typeof value === 'string') {\n // Mustache first — expands in-place within the string, so anchored\n // patterns below still apply to the post-expansion result.\n const expanded = runnerVars ? expandMustache(value, runnerVars) : value;\n\n const ctxMatch = expanded.match(/^\\$context\\.(\\w+)$/);\n if (ctxMatch?.[1]) {\n const key = ctxMatch[1];\n return key in context ? context[key] : expanded;\n }\n const genMatch = expanded.match(/^\\$generate:(uuid_v4|opaque_id)(?:#([A-Za-z0-9_.-]+))?$/);\n if (genMatch) {\n const alias = genMatch[2];\n if (alias) {\n const cache = getAliasCache(context);\n if (!(alias in cache)) cache[alias] = randomUUID();\n return cache[alias];\n }\n return randomUUID();\n }\n return expanded;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => deepReplace(item, context, runnerVars));\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n result[k] = deepReplace(v, context, runnerVars);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * Expand every `{{runner.*}}` and `{{prior_step.*}}` token in a string.\n * Unknown tokens are left in place so the runner can surface a pointed\n * \"unresolved substitution\" error rather than silently shipping the\n * literal mustache tokens to an agent.\n */\n/**\n * Token shape for the outer expander. Single `[^{}]+` (excludes braces on\n * both sides) so nested or partial `{{…` can't straddle a token boundary\n * and force the engine to backtrack character-by-character. Unified prefix\n * alternation (`runner|prior_step`) keeps the two recognized names in one\n * place — the inner expander still narrows each. Closes CodeQL alert #49\n * (js/polynomial-redos).\n */\nconst MUSTACHE_TOKEN_RE = /\\{\\{((?:runner|prior_step)\\.[^{}]+)\\}\\}/g;\n\nfunction expandMustache(input: string, runnerVars: RunnerVariables): string {\n return input.replace(MUSTACHE_TOKEN_RE, (match, inner) => {\n if (inner === 'runner.webhook_base') {\n return runnerVars.webhookBase ?? match;\n }\n const webhookUrlMatch = /^runner\\.webhook_url:([A-Za-z0-9_]+)$/.exec(inner);\n if (webhookUrlMatch?.[1]) {\n if (!runnerVars.webhookBase) return match;\n const stepId = webhookUrlMatch[1];\n let opId = runnerVars.stepOperationIds.get(stepId);\n if (!opId) {\n opId = randomUUID();\n runnerVars.stepOperationIds.set(stepId, opId);\n }\n return `${runnerVars.webhookBase}/step/${stepId}/${opId}`;\n }\n const priorMatch = /^prior_step\\.([A-Za-z0-9_]+)\\.operation_id$/.exec(inner);\n if (priorMatch?.[1]) {\n return runnerVars.stepOperationIds.get(priorMatch[1]) ?? match;\n }\n return match;\n });\n}\n\n// ────────────────────────────────────────────────────────────\n// Explicit context_outputs: extract values by path\n// ────────────────────────────────────────────────────────────\n\n/**\n * Apply explicit context_outputs rules to extract values from response data.\n * Entries with `generate` set are skipped — use `applyContextOutputsWithProvenance`\n * (which accepts a context for alias-cache access) to handle those.\n *\n * Per runner-output-contract.yaml v2.0.0, paths that resolve to `undefined`,\n * `null`, or `\"\"` are equally non-resolvable — capturing null or \"\" produces\n * fabricated downstream state. The provenance-aware variant additionally\n * surfaces the failures on `ContextWriteResult.failures` so the runner can\n * synthesize a `capture_path_not_resolvable` validation result; this lower-\n * level form drops them silently and is kept for callers that don't need\n * the structured failure surface.\n */\nexport function applyContextOutputs(data: unknown, outputs: ContextOutput[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const output of outputs) {\n if (!output.path) continue;\n const value = resolvePath(data, output.path);\n if (value !== undefined && value !== null && value !== '') {\n result[output.key] = value;\n }\n }\n return result;\n}\n\n/**\n * Result of a context write with per-key provenance. The runner consumes\n * `provenance` to emit `context_value_rejected` hints when a later step's\n * seller response rejects a value that traces back to one of these keys.\n * `values` carries the same Record as the non-provenance call so the\n * runner's downstream `Object.assign(updatedContext, values)` path is\n * unchanged.\n */\nexport interface ContextWriteResult {\n values: Record<string, unknown>;\n provenance: Record<string, ContextProvenanceEntry>;\n /**\n * Convention-owned alias groups that must be removed before applying\n * `values`. Conditional groups only clear when the current context key\n * matches one of the response-derived values.\n */\n clearGroups?: Array<{\n keys: string[];\n when?: { key: string; values: unknown[] };\n }>;\n /**\n * `path:` entries whose declared response path did not resolve to a usable\n * value (absent, `null`, or `\"\"`). Per runner-output-contract.yaml v2.0.0,\n * the runner synthesizes a `capture_path_not_resolvable` validation result\n * for each entry — capturing null or \"\" produces fabricated downstream\n * state and is as incorrect as a missing path. Generator entries do not\n * appear here; they cannot fail to resolve. Absent or empty when every\n * `path:` entry produced a value.\n */\n failures?: Array<{ key: string; path: string; resolved: unknown }>;\n}\n\n/**\n * Like `extractContext`, but also returns provenance for each written key\n * tagging it as a convention-based extraction. `response_path` is absent\n * for convention extractors — they're hardcoded functions, not YAML paths.\n */\nexport function extractContextWithProvenance(taskName: string, data: unknown, stepId: string): ContextWriteResult {\n const values = extractContext(taskName, data);\n const clearGroups = (() => {\n const response = asRecord(data);\n switch (taskName) {\n case 'list_products':\n return response?.outcome === 'listed' && Array.isArray(response.products)\n ? [{ keys: PRODUCT_CONTEXT_KEYS }]\n : undefined;\n case 'request_proposals':\n return values.proposal_id ? [{ keys: PROPOSAL_CONTEXT_KEYS }] : undefined;\n case 'refine_proposals':\n return values.proposal_id ? [{ keys: PROPOSAL_CONTEXT_KEYS }] : undefined;\n case 'decline_proposals':\n const declinedIds = Array.isArray(response?.results)\n ? response.results\n .map(asRecord)\n .filter(result => result?.outcome === 'declined')\n .map(result => result?.proposal_id)\n .filter(proposalId => proposalId !== undefined)\n : [];\n return declinedIds.length\n ? [{ keys: PROPOSAL_CONTEXT_KEYS, when: { key: 'proposal_id', values: declinedIds } }]\n : undefined;\n default:\n return undefined;\n }\n })();\n const provenance: Record<string, ContextProvenanceEntry> = {};\n for (const key of Object.keys(values)) {\n provenance[key] = {\n source_step_id: stepId,\n source_kind: 'convention',\n source_task: taskName,\n };\n }\n return { values, provenance, ...(clearGroups && { clearGroups }) };\n}\n\n/**\n * Like `applyContextOutputs`, but also returns provenance for each written\n * key carrying the YAML `response_path` so diagnostics can cite it verbatim.\n *\n * Pass `context` to enable `generate:` entries with alias-cache coherence.\n * When an output declares `generate`, the runner mints a UUID v4 (or reuses\n * the value already cached under `output.key` if an inline `$generate:…#<alias>`\n * substitution ran in the same step). The generated value is written back into\n * the alias cache so that any later step referencing `$generate:opaque_id#<key>`\n * resolves to the same UUID.\n *\n * Omitting `context` disables alias-cache coherence: each generator entry mints\n * an independent UUID that cannot be matched by an inline `$generate:…` form.\n *\n * Generator entries fire regardless of whether `data` is present; path\n * entries are silently skipped when the resolved value is null/undefined.\n */\nexport function applyContextOutputsWithProvenance(\n data: unknown,\n outputs: ContextOutput[],\n stepId: string,\n taskName: string,\n context?: StoryboardContext\n): ContextWriteResult {\n const values: Record<string, unknown> = {};\n const provenance: Record<string, ContextProvenanceEntry> = {};\n const failures: Array<{ key: string; path: string; resolved: unknown }> = [];\n for (const output of outputs) {\n if (output.generate !== undefined) {\n // Generator entries require a context — without one the alias cache\n // can't be populated, so a later step's `$generate:opaque_id#<key>` would\n // mint an independent UUID that doesn't match the value stored here.\n // Loud error beats silent divergence.\n if (!context) {\n throw new Error(\n `applyContextOutputsWithProvenance: context_outputs entry '${output.key}' ` +\n `declares generate='${output.generate}' but no context was provided. ` +\n `Generator entries require a context for alias-cache coherence.`\n );\n }\n const cache = getAliasCache(context);\n let value: string;\n if (output.key in cache) {\n value = cache[output.key]!;\n } else {\n value = randomUUID();\n cache[output.key] = value;\n }\n values[output.key] = value;\n provenance[output.key] = {\n source_step_id: stepId,\n source_kind: 'generator',\n source_task: taskName,\n };\n } else if (output.path) {\n const value = resolvePath(data, output.path);\n // Per runner-output-contract.yaml v2.0.0 / storyboard-schema.yaml,\n // null, \"\", and structurally-absent paths are equally non-resolvable\n // for capture purposes — capturing null or \"\" produces fabricated\n // downstream state and is as incorrect as a missing path.\n const resolved = value === undefined || value === null || value === '';\n if (!resolved) {\n values[output.key] = value;\n provenance[output.key] = {\n source_step_id: stepId,\n source_kind: 'context_outputs',\n response_path: output.path,\n source_task: taskName,\n };\n } else {\n failures.push({\n key: output.key,\n path: output.path,\n resolved: value === undefined ? null : value,\n });\n }\n }\n }\n return { values, provenance, ...(failures.length > 0 ? { failures } : {}) };\n}\n\n// ────────────────────────────────────────────────────────────\n// Explicit context_inputs: inject values into request by path\n// ────────────────────────────────────────────────────────────\n\n/**\n * Apply explicit context_inputs rules to inject context values into a request.\n * Returns a new object (does not mutate the input).\n */\nexport function applyContextInputs(\n request: Record<string, unknown>,\n inputs: ContextInput[],\n context: StoryboardContext\n): Record<string, unknown> {\n const result = structuredClone(request);\n for (const input of inputs) {\n if (input.key in context) {\n setPath(result, input.inject_at, context[input.key]);\n }\n }\n return result;\n}\n\n// setPath is re-exported from ./path for backwards compat\nexport { setPath } from './path';\n"],"mappings":"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","names":["import_path"]}
@@ -86,13 +86,18 @@ const CONTEXT_EXTRACTORS = {
86
86
  return { account_id: accounts[0].account_id };
87
87
  },
88
88
  get_products(data) {
89
- const d = data;
89
+ const d = asRecord(data);
90
90
  const products = d?.products;
91
- if (!products?.[0]) return {};
92
- const extracted = { products };
93
- if (products[0].product_id) extracted.product_id = products[0].product_id;
91
+ const extracted = {};
92
+ if (products?.[0]) {
93
+ extracted.products = products;
94
+ if (products[0].product_id) extracted.product_id = products[0].product_id;
95
+ }
94
96
  const proposals = d?.proposals;
95
97
  if (proposals?.[0]?.proposal_id) extracted.proposal_id = proposals[0].proposal_id;
98
+ if (d?.wholesale_feed_version !== void 0) extracted.wholesale_feed_version = d.wholesale_feed_version;
99
+ if (d?.pricing_version !== void 0) extracted.pricing_version = d.pricing_version;
100
+ if (d?.cache_scope !== void 0) extracted.cache_scope = d.cache_scope;
96
101
  return extracted;
97
102
  },
98
103
  list_products(data) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/testing/storyboard/context.ts"],"sourcesContent":["/**\n * Context propagation for storyboard steps.\n *\n * After each successful step, known IDs and references are extracted\n * from the response and accumulated in a StoryboardContext. Before\n * executing a step, context values are injected into the request via\n * \"$context.<key>\" placeholders.\n *\n * This convention-based approach avoids requiring YAML enrichment\n * (context_outputs/context_inputs) while still enabling stateful flows.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { StoryboardContext, ContextOutput, ContextInput, ContextProvenanceEntry } from './types';\nimport { resolvePath, setPath } from './path';\nimport { getAuthoritativeMediaBuyStatus } from '../../utils/media-buy-status';\n\n// ────────────────────────────────────────────────────────────\n// Context extraction: pull known IDs from task responses\n// ────────────────────────────────────────────────────────────\n\ntype ContextExtractor = (data: unknown) => Record<string, unknown>;\n\nconst PRODUCT_CONTEXT_KEYS = [\n 'product',\n 'products',\n 'product_id',\n 'pricing_option',\n 'pricing_option_id',\n 'feed_version',\n 'pricing_version',\n];\nconst PROPOSAL_CONTEXT_KEYS = [\n 'proposal',\n 'proposals',\n 'proposal_id',\n 'proposal_status',\n 'proposal_kind',\n 'terms_digest',\n 'proposal_terms_digest',\n];\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction readMediaBuyStatus(record: Record<string, unknown> | undefined): unknown {\n return getAuthoritativeMediaBuyStatus(record);\n}\n\nfunction readMediaBuyFields(data: unknown): { mediaBuyId?: unknown; status?: unknown } {\n const outer = asRecord(data);\n const nested = asRecord(outer?.media_buy);\n return {\n mediaBuyId: nested?.media_buy_id ?? outer?.media_buy_id,\n status: readMediaBuyStatus(nested) ?? readMediaBuyStatus(outer),\n };\n}\n\nfunction readProposalFields(proposal: Record<string, unknown> | undefined): Record<string, unknown> {\n if (!proposal) return {};\n const extracted: Record<string, unknown> = {};\n if (proposal.proposal_id) extracted.proposal_id = proposal.proposal_id;\n if (proposal.proposal_status) extracted.proposal_status = proposal.proposal_status;\n if (proposal.proposal_kind) extracted.proposal_kind = proposal.proposal_kind;\n if (proposal.terms_digest) {\n extracted.terms_digest = proposal.terms_digest;\n extracted.proposal_terms_digest = proposal.terms_digest;\n }\n return extracted;\n}\n\nfunction readCompactMediaBuyFields(data: unknown): Record<string, unknown> {\n const outer = asRecord(data);\n if (!outer || outer.status !== 'completed') return {};\n const mediaBuyId = outer.media_buy_id;\n // Compact responses use `status` for task completion and\n // `media_buy_status` for lifecycle state. Never reinterpret a bare\n // `status: completed` as the MediaBuy's status when the optional lifecycle\n // field is absent.\n const status = readMediaBuyStatus({ media_buy_status: outer.media_buy_status });\n const acceptedProposal = asRecord(outer.accepted_proposal);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n if (outer.revision) {\n extracted.revision = outer.revision;\n extracted.media_buy_revision = outer.revision;\n }\n if (acceptedProposal) {\n Object.assign(extracted, readProposalFields(acceptedProposal));\n }\n if (Array.isArray(outer.available_actions)) extracted.available_actions = outer.available_actions;\n return extracted;\n}\n\nexport const CONTEXT_EXTRACTORS: Record<string, ContextExtractor> = {\n sync_accounts(data) {\n const d = data as Record<string, unknown> | undefined;\n const accounts = d?.accounts as Array<Record<string, unknown>> | undefined;\n if (!accounts?.[0]) return {};\n const first = accounts[0];\n const extracted: Record<string, unknown> = {};\n if (first.account_id) extracted.account_id = first.account_id;\n if (first.status) extracted.account_status = first.status;\n // Build an account reference for downstream steps. Only include fields\n // the response actually carries — propagating `operator: undefined`\n // would serialize away on the wire (JSON.stringify drops undefined),\n // leaving the natural-key arm short of its required `operator` field\n // (#1419). The brand/operator pair stays paired or both absent.\n const accountRef: Record<string, unknown> = {};\n if (first.brand) accountRef.brand = first.brand;\n if (first.operator) accountRef.operator = first.operator;\n extracted.account = accountRef;\n return extracted;\n },\n\n list_accounts(data) {\n const d = data as Record<string, unknown> | undefined;\n const accounts = d?.accounts as Array<Record<string, unknown>> | undefined;\n if (!accounts?.[0]) return {};\n return { account_id: accounts[0].account_id };\n },\n\n get_products(data) {\n const d = data as Record<string, unknown> | undefined;\n const products = d?.products as Array<Record<string, unknown>> | undefined;\n if (!products?.[0]) return {};\n const extracted: Record<string, unknown> = { products };\n if (products[0].product_id) extracted.product_id = products[0].product_id;\n // Extract proposal_id if proposals are returned\n const proposals = d?.proposals as Array<Record<string, unknown>> | undefined;\n if (proposals?.[0]?.proposal_id) extracted.proposal_id = proposals[0].proposal_id;\n return extracted;\n },\n\n list_products(data) {\n const d = asRecord(data);\n const products = d?.products as Array<Record<string, unknown>> | undefined;\n if (!products?.[0]) return {};\n const first = products[0];\n const pricingOptions = first.pricing_options as Array<Record<string, unknown>> | undefined;\n const extracted: Record<string, unknown> = {};\n if (first.product_id) extracted.product_id = first.product_id;\n if (pricingOptions?.[0]) {\n if (pricingOptions[0].pricing_option_id) extracted.pricing_option_id = pricingOptions[0].pricing_option_id;\n }\n if (d?.feed_version) extracted.feed_version = d.feed_version;\n if (d?.pricing_version) extracted.pricing_version = d.pricing_version;\n return extracted;\n },\n\n request_proposals(data) {\n const d = asRecord(data);\n const proposals = d?.proposals as Array<Record<string, unknown>> | undefined;\n if (!proposals?.[0]) return {};\n return readProposalFields(proposals[0]);\n },\n\n refine_proposals(data) {\n const d = asRecord(data);\n const results = d?.results as Array<Record<string, unknown>> | undefined;\n if (!results?.length) return {};\n const proposalResult = results.find(result => asRecord(result.proposal) || Array.isArray(result.proposals));\n const proposal =\n asRecord(proposalResult?.proposal) ??\n (proposalResult?.proposals as Array<Record<string, unknown>> | undefined)?.[0] ??\n undefined;\n return proposal ? readProposalFields(proposal) : {};\n },\n\n decline_proposals() {\n return {};\n },\n\n buy_products(data) {\n return readCompactMediaBuyFields(data);\n },\n\n accept_proposal(data) {\n return readCompactMediaBuyFields(data);\n },\n\n control_media_buy(data) {\n return readCompactMediaBuyFields(data);\n },\n\n create_media_buy(data) {\n const { mediaBuyId, status } = readMediaBuyFields(data);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n return extracted;\n },\n\n update_media_buy(data) {\n const { mediaBuyId, status } = readMediaBuyFields(data);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n return extracted;\n },\n\n get_media_buys(data) {\n const d = data as Record<string, unknown> | undefined;\n const buys = d?.media_buys as Array<Record<string, unknown>> | undefined;\n if (!buys?.[0]) return {};\n // Don't extract a single-resource ID from a broad-list page. When\n // has_more: true the caller is mid-pagination walk and buys[0] is not\n // the canonical buy — extracting it here causes the enricher to inject\n // media_buy_ids: [that_id] on the next step, turning a continuation into\n // an ID-lookup. Conservative: === true matches the codebase convention\n // (absent has_more is treated as terminal, not as a list-in-progress).\n const pagination = d?.pagination as Record<string, unknown> | undefined;\n if (pagination?.has_more === true) return {};\n const extracted: Record<string, unknown> = {\n media_buy_id: buys[0].media_buy_id,\n media_buy_status: readMediaBuyStatus(buys[0]),\n };\n if (buys[0].revision) {\n extracted.revision = buys[0].revision;\n extracted.media_buy_revision = buys[0].revision;\n }\n if (Array.isArray(buys[0].available_actions)) extracted.available_actions = buys[0].available_actions;\n return extracted;\n },\n\n list_creative_formats(data) {\n const d = data as Record<string, unknown> | undefined;\n const formats = d?.formats as Array<Record<string, unknown>> | undefined;\n if (!formats?.[0]) return {};\n return {\n formats,\n format_id: formats[0].format_id,\n };\n },\n\n build_creative(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n // Single response: creative_manifest\n const manifest = d?.creative_manifest as Record<string, unknown> | undefined;\n if (manifest) {\n extracted.creative_manifest = manifest;\n if (manifest.format_id) extracted.format_id = manifest.format_id;\n }\n // Multi response: creative_manifests\n const manifests = d?.creative_manifests as Array<Record<string, unknown>> | undefined;\n if (manifests?.[0]) {\n extracted.creative_manifests = manifests;\n if (manifests[0].format_id) extracted.format_id = manifests[0].format_id;\n }\n // Variant response: creatives[].variants[] (BuildCreativeVariantSuccess).\n const creatives = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (creatives?.[0]) {\n extracted.creatives = creatives;\n\n const variants = creatives.flatMap(creative => {\n const creativeVariants = creative.variants as Array<Record<string, unknown>> | undefined;\n return Array.isArray(creativeVariants) ? creativeVariants : [];\n });\n if (variants[0]) {\n extracted.variants = variants;\n if (variants[0].build_variant_id) extracted.build_variant_id = variants[0].build_variant_id;\n\n const variantManifest = variants[0].creative_manifest as Record<string, unknown> | undefined;\n if (variantManifest) {\n extracted.creative_manifest ??= variantManifest;\n if (!extracted.format_id && variantManifest.format_id) extracted.format_id = variantManifest.format_id;\n }\n }\n }\n return extracted;\n },\n\n sync_creatives(data) {\n const d = data as Record<string, unknown> | undefined;\n const results = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (!results?.length) return {};\n return { creative_results: results };\n },\n\n list_creatives(data) {\n const d = data as Record<string, unknown> | undefined;\n const creatives = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (!creatives?.[0]) return {};\n const extracted: Record<string, unknown> = { creatives };\n if (creatives[0].creative_id) extracted.creative_id = creatives[0].creative_id;\n return extracted;\n },\n\n preview_creative(data) {\n const d = data as Record<string, unknown> | undefined;\n const previews = d?.previews as Array<Record<string, unknown>> | undefined;\n if (!previews?.length) return {};\n return { previews };\n },\n\n get_signals(data) {\n const d = data as Record<string, unknown> | undefined;\n const signals = d?.signals as Array<Record<string, unknown>> | undefined;\n if (!signals?.[0]) return {};\n return {\n signals,\n signal_id: signals[0].signal_id,\n };\n },\n\n activate_signal(data) {\n const d = data as Record<string, unknown> | undefined;\n const deployments = d?.deployments as Array<Record<string, unknown>> | undefined;\n if (!deployments?.[0]) return {};\n const first = deployments[0];\n const extracted: Record<string, unknown> = { deployments };\n if (first.activation_key) extracted.activation_key = first.activation_key;\n if (first.type) extracted.deployment_type = first.type;\n return extracted;\n },\n\n sync_catalogs(data) {\n const d = data as Record<string, unknown> | undefined;\n const catalogs = d?.catalogs as Array<Record<string, unknown>> | undefined;\n if (!catalogs?.[0]) return {};\n const extracted: Record<string, unknown> = { catalogs };\n if (catalogs[0].catalog_id) extracted.catalog_id = catalogs[0].catalog_id;\n return extracted;\n },\n\n sync_audiences(data) {\n const d = data as Record<string, unknown> | undefined;\n const audiences = d?.audiences as Array<Record<string, unknown>> | undefined;\n if (!audiences?.[0]) return {};\n const extracted: Record<string, unknown> = { audiences };\n if (audiences[0].audience_id) extracted.audience_id = audiences[0].audience_id;\n return extracted;\n },\n\n sync_event_sources(data) {\n const d = data as Record<string, unknown> | undefined;\n const sources = d?.event_sources as Array<Record<string, unknown>> | undefined;\n if (!sources?.[0]) return {};\n const extracted: Record<string, unknown> = { event_sources: sources };\n if (sources[0].event_source_id) extracted.event_source_id = sources[0].event_source_id;\n return extracted;\n },\n\n si_initiate_session(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.session_id) extracted.session_id = d.session_id;\n return extracted;\n },\n\n si_get_offering(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.offering_id) extracted.offering_id = d.offering_id;\n const offerings = d?.offerings as Array<Record<string, unknown>> | undefined;\n if (offerings?.[0]?.offering_id) extracted.offering_id = offerings[0].offering_id;\n return extracted;\n },\n\n sync_plans(data) {\n const d = data as Record<string, unknown> | undefined;\n const plans = d?.plans as Array<Record<string, unknown>> | undefined;\n if (!plans?.[0]) return {};\n return { plan_id: plans[0].plan_id };\n },\n\n create_property_list(data) {\n const d = data as Record<string, unknown> | undefined;\n const list = d?.list as Record<string, unknown> | undefined;\n if (!list) return {};\n const extracted: Record<string, unknown> = {};\n if (list.list_id) extracted.property_list_id = list.list_id;\n if (list.name) extracted.property_list_name = list.name;\n // auth_token intentionally not extracted — avoid leaking credentials into\n // storyboard context which may appear in logs or compliance reports.\n return extracted;\n },\n\n create_content_standards(data) {\n const d = data as Record<string, unknown> | undefined;\n if (!d?.standards_id) return {};\n return { content_standards_id: d.standards_id };\n },\n\n get_rights(data) {\n const d = data as Record<string, unknown> | undefined;\n const rights = d?.rights as Array<Record<string, unknown>> | undefined;\n if (!rights?.[0]?.rights_id) return {};\n return { rights_id: rights[0].rights_id };\n },\n\n acquire_rights(data) {\n const d = data as Record<string, unknown> | undefined;\n if (!d?.rights_grant_id) return {};\n return { rights_grant_id: d.rights_grant_id, rights_id: d.rights_id };\n },\n\n sync_governance(data) {\n // Governance registration — no IDs to extract, just confirmation\n return { governance_synced: true, governance_response: data };\n },\n\n check_governance(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.governance_context) extracted.governance_context = d.governance_context;\n if (d?.check_id) extracted.check_id = d.check_id;\n if (d?.plan_id) extracted.plan_id = d.plan_id;\n if (d?.verdict) extracted.governance_status = d.verdict;\n return extracted;\n },\n\n report_plan_outcome(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.outcome_id) extracted.outcome_id = d.outcome_id;\n if (d?.outcome_state) extracted.outcome_status = d.outcome_state;\n return extracted;\n },\n};\n\n/**\n * Extract context values from a task response.\n */\nexport function extractContext(taskName: string, data: unknown): Record<string, unknown> {\n const extractor = CONTEXT_EXTRACTORS[taskName];\n if (!extractor) return {};\n try {\n return extractor(data);\n } catch {\n return {};\n }\n}\n\n// ────────────────────────────────────────────────────────────\n// Context injection: substitute $context.<key> in requests\n// ────────────────────────────────────────────────────────────\n\n/**\n * Per-context alias cache for `$generate:uuid_v4#<alias>` placeholders.\n *\n * A WeakMap keyed off the StoryboardContext identity avoids landing\n * implementation-detail keys on the serialized context object and avoids\n * fragility when context is shallow-cloned between steps — the cache\n * follows the context reference rather than riding as an owned key.\n *\n * Propagation across steps is handled by `forwardAliasCache` (called by\n * the runner when it rolls context forward to the next step), keeping\n * this a deliberate design choice rather than an invisible by-reference\n * leak through `{ ...context }`.\n */\nconst aliasCaches = new WeakMap<StoryboardContext, Record<string, string>>();\n\n/**\n * Ensure an alias cache exists for the given context and return it.\n */\nfunction getAliasCache(context: StoryboardContext): Record<string, string> {\n let cache = aliasCaches.get(context);\n if (!cache) {\n cache = {};\n aliasCaches.set(context, cache);\n }\n return cache;\n}\n\n/**\n * Propagate the alias cache from one context to another — call after\n * shallow-cloning context between storyboard steps so replay tests\n * (initial + replay sharing `$generate:uuid_v4#<alias>`) resolve to the\n * same UUID. No-op when `from` has no cache.\n */\nexport function forwardAliasCache(from: StoryboardContext, to: StoryboardContext): void {\n const cache = aliasCaches.get(from);\n if (cache) aliasCaches.set(to, cache);\n}\n\n/**\n * Runner-owned substitution variables.\n *\n * Parallels `$context.*` but lives outside the serialized context object so\n * implementation details (the receiver's bound URL, per-step operation ids)\n * stay off the compliance report. Expanded within strings (embedded\n * substitution), unlike `$context.*` which matches whole strings only.\n *\n * Supported patterns:\n * - `{{runner.webhook_base}}` — base URL of the receiver.\n * - `{{runner.webhook_url:<step_id>}}` — per-step webhook URL\n * (`<base>/step/<step_id>/<operation_id>`). The operation_id is minted\n * lazily on first expansion and cached for the rest of the run so the\n * matching `{{prior_step.<step_id>.operation_id}}` reference downstream\n * resolves to the same value.\n * - `{{prior_step.<step_id>.operation_id}}` — operation_id the runner\n * allocated when expanding `{{runner.webhook_url:<step_id>}}`.\n */\nexport interface RunnerVariables {\n /** Millisecond timestamp captured once at run start for deterministic enrichment. */\n runStartMs?: number;\n /** Base URL of the runner's webhook receiver, when enabled. */\n webhookBase?: string;\n /** step_id → operation_id, filled lazily on expansion. */\n stepOperationIds: Map<string, string>;\n /**\n * Free-form slot for cross-step run state that isn't user-facing. Used\n * today to share a single `InMemoryReplayStore` / `InMemoryRevocationStore`\n * across every `expect_webhook_signature_valid` call in a run so a\n * replayed (keyid, nonce) across two deliveries of the same event is\n * actually detected. Untyped here to keep the context module free of\n * signing-module imports.\n */\n runState: Map<string, unknown>;\n}\n\nexport function createRunnerVariables(opts: { webhookBase?: string } = {}): RunnerVariables {\n return {\n runStartMs: Date.now(),\n ...(opts.webhookBase !== undefined && { webhookBase: opts.webhookBase }),\n stepOperationIds: new Map(),\n runState: new Map(),\n };\n}\n\n/**\n * Deep-walk an object and replace recognized placeholder strings:\n *\n * - `$context.<key>` → value from `context[key]` (anchored whole-string match)\n * - `$generate:uuid_v4` → fresh UUID v4 per occurrence (anchored)\n * - `$generate:uuid_v4#<alias>` → fresh UUID v4 on first occurrence, then the\n * same UUID for every subsequent occurrence of the same alias within this\n * run (anchored)\n * - `{{runner.*}}` / `{{prior_step.<id>.operation_id}}` → embedded runner-\n * variable substitution (only when `runnerVars` is supplied)\n *\n * Returns a new object (does not mutate the input).\n */\nexport function injectContext(\n obj: Record<string, unknown>,\n context: StoryboardContext,\n runnerVars?: RunnerVariables\n): Record<string, unknown> {\n return deepReplace(obj, context, runnerVars) as Record<string, unknown>;\n}\n\nfunction deepReplace(value: unknown, context: StoryboardContext, runnerVars?: RunnerVariables): unknown {\n if (typeof value === 'string') {\n // Mustache first — expands in-place within the string, so anchored\n // patterns below still apply to the post-expansion result.\n const expanded = runnerVars ? expandMustache(value, runnerVars) : value;\n\n const ctxMatch = expanded.match(/^\\$context\\.(\\w+)$/);\n if (ctxMatch?.[1]) {\n const key = ctxMatch[1];\n return key in context ? context[key] : expanded;\n }\n const genMatch = expanded.match(/^\\$generate:(uuid_v4|opaque_id)(?:#([A-Za-z0-9_.-]+))?$/);\n if (genMatch) {\n const alias = genMatch[2];\n if (alias) {\n const cache = getAliasCache(context);\n if (!(alias in cache)) cache[alias] = randomUUID();\n return cache[alias];\n }\n return randomUUID();\n }\n return expanded;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => deepReplace(item, context, runnerVars));\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n result[k] = deepReplace(v, context, runnerVars);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * Expand every `{{runner.*}}` and `{{prior_step.*}}` token in a string.\n * Unknown tokens are left in place so the runner can surface a pointed\n * \"unresolved substitution\" error rather than silently shipping the\n * literal mustache tokens to an agent.\n */\n/**\n * Token shape for the outer expander. Single `[^{}]+` (excludes braces on\n * both sides) so nested or partial `{{…` can't straddle a token boundary\n * and force the engine to backtrack character-by-character. Unified prefix\n * alternation (`runner|prior_step`) keeps the two recognized names in one\n * place — the inner expander still narrows each. Closes CodeQL alert #49\n * (js/polynomial-redos).\n */\nconst MUSTACHE_TOKEN_RE = /\\{\\{((?:runner|prior_step)\\.[^{}]+)\\}\\}/g;\n\nfunction expandMustache(input: string, runnerVars: RunnerVariables): string {\n return input.replace(MUSTACHE_TOKEN_RE, (match, inner) => {\n if (inner === 'runner.webhook_base') {\n return runnerVars.webhookBase ?? match;\n }\n const webhookUrlMatch = /^runner\\.webhook_url:([A-Za-z0-9_]+)$/.exec(inner);\n if (webhookUrlMatch?.[1]) {\n if (!runnerVars.webhookBase) return match;\n const stepId = webhookUrlMatch[1];\n let opId = runnerVars.stepOperationIds.get(stepId);\n if (!opId) {\n opId = randomUUID();\n runnerVars.stepOperationIds.set(stepId, opId);\n }\n return `${runnerVars.webhookBase}/step/${stepId}/${opId}`;\n }\n const priorMatch = /^prior_step\\.([A-Za-z0-9_]+)\\.operation_id$/.exec(inner);\n if (priorMatch?.[1]) {\n return runnerVars.stepOperationIds.get(priorMatch[1]) ?? match;\n }\n return match;\n });\n}\n\n// ────────────────────────────────────────────────────────────\n// Explicit context_outputs: extract values by path\n// ────────────────────────────────────────────────────────────\n\n/**\n * Apply explicit context_outputs rules to extract values from response data.\n * Entries with `generate` set are skipped — use `applyContextOutputsWithProvenance`\n * (which accepts a context for alias-cache access) to handle those.\n *\n * Per runner-output-contract.yaml v2.0.0, paths that resolve to `undefined`,\n * `null`, or `\"\"` are equally non-resolvable — capturing null or \"\" produces\n * fabricated downstream state. The provenance-aware variant additionally\n * surfaces the failures on `ContextWriteResult.failures` so the runner can\n * synthesize a `capture_path_not_resolvable` validation result; this lower-\n * level form drops them silently and is kept for callers that don't need\n * the structured failure surface.\n */\nexport function applyContextOutputs(data: unknown, outputs: ContextOutput[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const output of outputs) {\n if (!output.path) continue;\n const value = resolvePath(data, output.path);\n if (value !== undefined && value !== null && value !== '') {\n result[output.key] = value;\n }\n }\n return result;\n}\n\n/**\n * Result of a context write with per-key provenance. The runner consumes\n * `provenance` to emit `context_value_rejected` hints when a later step's\n * seller response rejects a value that traces back to one of these keys.\n * `values` carries the same Record as the non-provenance call so the\n * runner's downstream `Object.assign(updatedContext, values)` path is\n * unchanged.\n */\nexport interface ContextWriteResult {\n values: Record<string, unknown>;\n provenance: Record<string, ContextProvenanceEntry>;\n /**\n * Convention-owned alias groups that must be removed before applying\n * `values`. Conditional groups only clear when the current context key\n * matches one of the response-derived values.\n */\n clearGroups?: Array<{\n keys: string[];\n when?: { key: string; values: unknown[] };\n }>;\n /**\n * `path:` entries whose declared response path did not resolve to a usable\n * value (absent, `null`, or `\"\"`). Per runner-output-contract.yaml v2.0.0,\n * the runner synthesizes a `capture_path_not_resolvable` validation result\n * for each entry — capturing null or \"\" produces fabricated downstream\n * state and is as incorrect as a missing path. Generator entries do not\n * appear here; they cannot fail to resolve. Absent or empty when every\n * `path:` entry produced a value.\n */\n failures?: Array<{ key: string; path: string; resolved: unknown }>;\n}\n\n/**\n * Like `extractContext`, but also returns provenance for each written key\n * tagging it as a convention-based extraction. `response_path` is absent\n * for convention extractors — they're hardcoded functions, not YAML paths.\n */\nexport function extractContextWithProvenance(taskName: string, data: unknown, stepId: string): ContextWriteResult {\n const values = extractContext(taskName, data);\n const clearGroups = (() => {\n const response = asRecord(data);\n switch (taskName) {\n case 'list_products':\n return response?.outcome === 'listed' && Array.isArray(response.products)\n ? [{ keys: PRODUCT_CONTEXT_KEYS }]\n : undefined;\n case 'request_proposals':\n return values.proposal_id ? [{ keys: PROPOSAL_CONTEXT_KEYS }] : undefined;\n case 'refine_proposals':\n return values.proposal_id ? [{ keys: PROPOSAL_CONTEXT_KEYS }] : undefined;\n case 'decline_proposals':\n const declinedIds = Array.isArray(response?.results)\n ? response.results\n .map(asRecord)\n .filter(result => result?.outcome === 'declined')\n .map(result => result?.proposal_id)\n .filter(proposalId => proposalId !== undefined)\n : [];\n return declinedIds.length\n ? [{ keys: PROPOSAL_CONTEXT_KEYS, when: { key: 'proposal_id', values: declinedIds } }]\n : undefined;\n default:\n return undefined;\n }\n })();\n const provenance: Record<string, ContextProvenanceEntry> = {};\n for (const key of Object.keys(values)) {\n provenance[key] = {\n source_step_id: stepId,\n source_kind: 'convention',\n source_task: taskName,\n };\n }\n return { values, provenance, ...(clearGroups && { clearGroups }) };\n}\n\n/**\n * Like `applyContextOutputs`, but also returns provenance for each written\n * key carrying the YAML `response_path` so diagnostics can cite it verbatim.\n *\n * Pass `context` to enable `generate:` entries with alias-cache coherence.\n * When an output declares `generate`, the runner mints a UUID v4 (or reuses\n * the value already cached under `output.key` if an inline `$generate:…#<alias>`\n * substitution ran in the same step). The generated value is written back into\n * the alias cache so that any later step referencing `$generate:opaque_id#<key>`\n * resolves to the same UUID.\n *\n * Omitting `context` disables alias-cache coherence: each generator entry mints\n * an independent UUID that cannot be matched by an inline `$generate:…` form.\n *\n * Generator entries fire regardless of whether `data` is present; path\n * entries are silently skipped when the resolved value is null/undefined.\n */\nexport function applyContextOutputsWithProvenance(\n data: unknown,\n outputs: ContextOutput[],\n stepId: string,\n taskName: string,\n context?: StoryboardContext\n): ContextWriteResult {\n const values: Record<string, unknown> = {};\n const provenance: Record<string, ContextProvenanceEntry> = {};\n const failures: Array<{ key: string; path: string; resolved: unknown }> = [];\n for (const output of outputs) {\n if (output.generate !== undefined) {\n // Generator entries require a context — without one the alias cache\n // can't be populated, so a later step's `$generate:opaque_id#<key>` would\n // mint an independent UUID that doesn't match the value stored here.\n // Loud error beats silent divergence.\n if (!context) {\n throw new Error(\n `applyContextOutputsWithProvenance: context_outputs entry '${output.key}' ` +\n `declares generate='${output.generate}' but no context was provided. ` +\n `Generator entries require a context for alias-cache coherence.`\n );\n }\n const cache = getAliasCache(context);\n let value: string;\n if (output.key in cache) {\n value = cache[output.key]!;\n } else {\n value = randomUUID();\n cache[output.key] = value;\n }\n values[output.key] = value;\n provenance[output.key] = {\n source_step_id: stepId,\n source_kind: 'generator',\n source_task: taskName,\n };\n } else if (output.path) {\n const value = resolvePath(data, output.path);\n // Per runner-output-contract.yaml v2.0.0 / storyboard-schema.yaml,\n // null, \"\", and structurally-absent paths are equally non-resolvable\n // for capture purposes — capturing null or \"\" produces fabricated\n // downstream state and is as incorrect as a missing path.\n const resolved = value === undefined || value === null || value === '';\n if (!resolved) {\n values[output.key] = value;\n provenance[output.key] = {\n source_step_id: stepId,\n source_kind: 'context_outputs',\n response_path: output.path,\n source_task: taskName,\n };\n } else {\n failures.push({\n key: output.key,\n path: output.path,\n resolved: value === undefined ? null : value,\n });\n }\n }\n }\n return { values, provenance, ...(failures.length > 0 ? { failures } : {}) };\n}\n\n// ────────────────────────────────────────────────────────────\n// Explicit context_inputs: inject values into request by path\n// ────────────────────────────────────────────────────────────\n\n/**\n * Apply explicit context_inputs rules to inject context values into a request.\n * Returns a new object (does not mutate the input).\n */\nexport function applyContextInputs(\n request: Record<string, unknown>,\n inputs: ContextInput[],\n context: StoryboardContext\n): Record<string, unknown> {\n const result = structuredClone(request);\n for (const input of inputs) {\n if (input.key in context) {\n setPath(result, input.inject_at, context[input.key]);\n }\n }\n return result;\n}\n\n// setPath is re-exported from ./path for backwards compat\nexport { setPath } from './path';\n"],"mappings":"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","names":["setPath"]}
1
+ {"version":3,"sources":["../../../../src/lib/testing/storyboard/context.ts"],"sourcesContent":["/**\n * Context propagation for storyboard steps.\n *\n * After each successful step, known IDs and references are extracted\n * from the response and accumulated in a StoryboardContext. Before\n * executing a step, context values are injected into the request via\n * \"$context.<key>\" placeholders.\n *\n * This convention-based approach avoids requiring YAML enrichment\n * (context_outputs/context_inputs) while still enabling stateful flows.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { StoryboardContext, ContextOutput, ContextInput, ContextProvenanceEntry } from './types';\nimport { resolvePath, setPath } from './path';\nimport { getAuthoritativeMediaBuyStatus } from '../../utils/media-buy-status';\n\n// ────────────────────────────────────────────────────────────\n// Context extraction: pull known IDs from task responses\n// ────────────────────────────────────────────────────────────\n\ntype ContextExtractor = (data: unknown) => Record<string, unknown>;\n\nconst PRODUCT_CONTEXT_KEYS = [\n 'product',\n 'products',\n 'product_id',\n 'pricing_option',\n 'pricing_option_id',\n 'feed_version',\n 'pricing_version',\n];\nconst PROPOSAL_CONTEXT_KEYS = [\n 'proposal',\n 'proposals',\n 'proposal_id',\n 'proposal_status',\n 'proposal_kind',\n 'terms_digest',\n 'proposal_terms_digest',\n];\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction readMediaBuyStatus(record: Record<string, unknown> | undefined): unknown {\n return getAuthoritativeMediaBuyStatus(record);\n}\n\nfunction readMediaBuyFields(data: unknown): { mediaBuyId?: unknown; status?: unknown } {\n const outer = asRecord(data);\n const nested = asRecord(outer?.media_buy);\n return {\n mediaBuyId: nested?.media_buy_id ?? outer?.media_buy_id,\n status: readMediaBuyStatus(nested) ?? readMediaBuyStatus(outer),\n };\n}\n\nfunction readProposalFields(proposal: Record<string, unknown> | undefined): Record<string, unknown> {\n if (!proposal) return {};\n const extracted: Record<string, unknown> = {};\n if (proposal.proposal_id) extracted.proposal_id = proposal.proposal_id;\n if (proposal.proposal_status) extracted.proposal_status = proposal.proposal_status;\n if (proposal.proposal_kind) extracted.proposal_kind = proposal.proposal_kind;\n if (proposal.terms_digest) {\n extracted.terms_digest = proposal.terms_digest;\n extracted.proposal_terms_digest = proposal.terms_digest;\n }\n return extracted;\n}\n\nfunction readCompactMediaBuyFields(data: unknown): Record<string, unknown> {\n const outer = asRecord(data);\n if (!outer || outer.status !== 'completed') return {};\n const mediaBuyId = outer.media_buy_id;\n // Compact responses use `status` for task completion and\n // `media_buy_status` for lifecycle state. Never reinterpret a bare\n // `status: completed` as the MediaBuy's status when the optional lifecycle\n // field is absent.\n const status = readMediaBuyStatus({ media_buy_status: outer.media_buy_status });\n const acceptedProposal = asRecord(outer.accepted_proposal);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n if (outer.revision) {\n extracted.revision = outer.revision;\n extracted.media_buy_revision = outer.revision;\n }\n if (acceptedProposal) {\n Object.assign(extracted, readProposalFields(acceptedProposal));\n }\n if (Array.isArray(outer.available_actions)) extracted.available_actions = outer.available_actions;\n return extracted;\n}\n\nexport const CONTEXT_EXTRACTORS: Record<string, ContextExtractor> = {\n sync_accounts(data) {\n const d = data as Record<string, unknown> | undefined;\n const accounts = d?.accounts as Array<Record<string, unknown>> | undefined;\n if (!accounts?.[0]) return {};\n const first = accounts[0];\n const extracted: Record<string, unknown> = {};\n if (first.account_id) extracted.account_id = first.account_id;\n if (first.status) extracted.account_status = first.status;\n // Build an account reference for downstream steps. Only include fields\n // the response actually carries — propagating `operator: undefined`\n // would serialize away on the wire (JSON.stringify drops undefined),\n // leaving the natural-key arm short of its required `operator` field\n // (#1419). The brand/operator pair stays paired or both absent.\n const accountRef: Record<string, unknown> = {};\n if (first.brand) accountRef.brand = first.brand;\n if (first.operator) accountRef.operator = first.operator;\n extracted.account = accountRef;\n return extracted;\n },\n\n list_accounts(data) {\n const d = data as Record<string, unknown> | undefined;\n const accounts = d?.accounts as Array<Record<string, unknown>> | undefined;\n if (!accounts?.[0]) return {};\n return { account_id: accounts[0].account_id };\n },\n\n get_products(data) {\n const d = asRecord(data);\n const products = d?.products as Array<Record<string, unknown>> | undefined;\n const extracted: Record<string, unknown> = {};\n if (products?.[0]) {\n extracted.products = products;\n if (products[0].product_id) extracted.product_id = products[0].product_id;\n }\n // Extract proposal_id if proposals are returned\n const proposals = d?.proposals as Array<Record<string, unknown>> | undefined;\n if (proposals?.[0]?.proposal_id) extracted.proposal_id = proposals[0].proposal_id;\n // Wholesale conditional-fetch steps need the response's scope and version\n // metadata even when `unchanged: true` legitimately omits product rows.\n if (d?.wholesale_feed_version !== undefined) extracted.wholesale_feed_version = d.wholesale_feed_version;\n if (d?.pricing_version !== undefined) extracted.pricing_version = d.pricing_version;\n if (d?.cache_scope !== undefined) extracted.cache_scope = d.cache_scope;\n return extracted;\n },\n\n list_products(data) {\n const d = asRecord(data);\n const products = d?.products as Array<Record<string, unknown>> | undefined;\n if (!products?.[0]) return {};\n const first = products[0];\n const pricingOptions = first.pricing_options as Array<Record<string, unknown>> | undefined;\n const extracted: Record<string, unknown> = {};\n if (first.product_id) extracted.product_id = first.product_id;\n if (pricingOptions?.[0]) {\n if (pricingOptions[0].pricing_option_id) extracted.pricing_option_id = pricingOptions[0].pricing_option_id;\n }\n if (d?.feed_version) extracted.feed_version = d.feed_version;\n if (d?.pricing_version) extracted.pricing_version = d.pricing_version;\n return extracted;\n },\n\n request_proposals(data) {\n const d = asRecord(data);\n const proposals = d?.proposals as Array<Record<string, unknown>> | undefined;\n if (!proposals?.[0]) return {};\n return readProposalFields(proposals[0]);\n },\n\n refine_proposals(data) {\n const d = asRecord(data);\n const results = d?.results as Array<Record<string, unknown>> | undefined;\n if (!results?.length) return {};\n const proposalResult = results.find(result => asRecord(result.proposal) || Array.isArray(result.proposals));\n const proposal =\n asRecord(proposalResult?.proposal) ??\n (proposalResult?.proposals as Array<Record<string, unknown>> | undefined)?.[0] ??\n undefined;\n return proposal ? readProposalFields(proposal) : {};\n },\n\n decline_proposals() {\n return {};\n },\n\n buy_products(data) {\n return readCompactMediaBuyFields(data);\n },\n\n accept_proposal(data) {\n return readCompactMediaBuyFields(data);\n },\n\n control_media_buy(data) {\n return readCompactMediaBuyFields(data);\n },\n\n create_media_buy(data) {\n const { mediaBuyId, status } = readMediaBuyFields(data);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n return extracted;\n },\n\n update_media_buy(data) {\n const { mediaBuyId, status } = readMediaBuyFields(data);\n const extracted: Record<string, unknown> = {};\n if (mediaBuyId) extracted.media_buy_id = mediaBuyId;\n if (status) extracted.media_buy_status = status;\n return extracted;\n },\n\n get_media_buys(data) {\n const d = data as Record<string, unknown> | undefined;\n const buys = d?.media_buys as Array<Record<string, unknown>> | undefined;\n if (!buys?.[0]) return {};\n // Don't extract a single-resource ID from a broad-list page. When\n // has_more: true the caller is mid-pagination walk and buys[0] is not\n // the canonical buy — extracting it here causes the enricher to inject\n // media_buy_ids: [that_id] on the next step, turning a continuation into\n // an ID-lookup. Conservative: === true matches the codebase convention\n // (absent has_more is treated as terminal, not as a list-in-progress).\n const pagination = d?.pagination as Record<string, unknown> | undefined;\n if (pagination?.has_more === true) return {};\n const extracted: Record<string, unknown> = {\n media_buy_id: buys[0].media_buy_id,\n media_buy_status: readMediaBuyStatus(buys[0]),\n };\n if (buys[0].revision) {\n extracted.revision = buys[0].revision;\n extracted.media_buy_revision = buys[0].revision;\n }\n if (Array.isArray(buys[0].available_actions)) extracted.available_actions = buys[0].available_actions;\n return extracted;\n },\n\n list_creative_formats(data) {\n const d = data as Record<string, unknown> | undefined;\n const formats = d?.formats as Array<Record<string, unknown>> | undefined;\n if (!formats?.[0]) return {};\n return {\n formats,\n format_id: formats[0].format_id,\n };\n },\n\n build_creative(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n // Single response: creative_manifest\n const manifest = d?.creative_manifest as Record<string, unknown> | undefined;\n if (manifest) {\n extracted.creative_manifest = manifest;\n if (manifest.format_id) extracted.format_id = manifest.format_id;\n }\n // Multi response: creative_manifests\n const manifests = d?.creative_manifests as Array<Record<string, unknown>> | undefined;\n if (manifests?.[0]) {\n extracted.creative_manifests = manifests;\n if (manifests[0].format_id) extracted.format_id = manifests[0].format_id;\n }\n // Variant response: creatives[].variants[] (BuildCreativeVariantSuccess).\n const creatives = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (creatives?.[0]) {\n extracted.creatives = creatives;\n\n const variants = creatives.flatMap(creative => {\n const creativeVariants = creative.variants as Array<Record<string, unknown>> | undefined;\n return Array.isArray(creativeVariants) ? creativeVariants : [];\n });\n if (variants[0]) {\n extracted.variants = variants;\n if (variants[0].build_variant_id) extracted.build_variant_id = variants[0].build_variant_id;\n\n const variantManifest = variants[0].creative_manifest as Record<string, unknown> | undefined;\n if (variantManifest) {\n extracted.creative_manifest ??= variantManifest;\n if (!extracted.format_id && variantManifest.format_id) extracted.format_id = variantManifest.format_id;\n }\n }\n }\n return extracted;\n },\n\n sync_creatives(data) {\n const d = data as Record<string, unknown> | undefined;\n const results = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (!results?.length) return {};\n return { creative_results: results };\n },\n\n list_creatives(data) {\n const d = data as Record<string, unknown> | undefined;\n const creatives = d?.creatives as Array<Record<string, unknown>> | undefined;\n if (!creatives?.[0]) return {};\n const extracted: Record<string, unknown> = { creatives };\n if (creatives[0].creative_id) extracted.creative_id = creatives[0].creative_id;\n return extracted;\n },\n\n preview_creative(data) {\n const d = data as Record<string, unknown> | undefined;\n const previews = d?.previews as Array<Record<string, unknown>> | undefined;\n if (!previews?.length) return {};\n return { previews };\n },\n\n get_signals(data) {\n const d = data as Record<string, unknown> | undefined;\n const signals = d?.signals as Array<Record<string, unknown>> | undefined;\n if (!signals?.[0]) return {};\n return {\n signals,\n signal_id: signals[0].signal_id,\n };\n },\n\n activate_signal(data) {\n const d = data as Record<string, unknown> | undefined;\n const deployments = d?.deployments as Array<Record<string, unknown>> | undefined;\n if (!deployments?.[0]) return {};\n const first = deployments[0];\n const extracted: Record<string, unknown> = { deployments };\n if (first.activation_key) extracted.activation_key = first.activation_key;\n if (first.type) extracted.deployment_type = first.type;\n return extracted;\n },\n\n sync_catalogs(data) {\n const d = data as Record<string, unknown> | undefined;\n const catalogs = d?.catalogs as Array<Record<string, unknown>> | undefined;\n if (!catalogs?.[0]) return {};\n const extracted: Record<string, unknown> = { catalogs };\n if (catalogs[0].catalog_id) extracted.catalog_id = catalogs[0].catalog_id;\n return extracted;\n },\n\n sync_audiences(data) {\n const d = data as Record<string, unknown> | undefined;\n const audiences = d?.audiences as Array<Record<string, unknown>> | undefined;\n if (!audiences?.[0]) return {};\n const extracted: Record<string, unknown> = { audiences };\n if (audiences[0].audience_id) extracted.audience_id = audiences[0].audience_id;\n return extracted;\n },\n\n sync_event_sources(data) {\n const d = data as Record<string, unknown> | undefined;\n const sources = d?.event_sources as Array<Record<string, unknown>> | undefined;\n if (!sources?.[0]) return {};\n const extracted: Record<string, unknown> = { event_sources: sources };\n if (sources[0].event_source_id) extracted.event_source_id = sources[0].event_source_id;\n return extracted;\n },\n\n si_initiate_session(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.session_id) extracted.session_id = d.session_id;\n return extracted;\n },\n\n si_get_offering(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.offering_id) extracted.offering_id = d.offering_id;\n const offerings = d?.offerings as Array<Record<string, unknown>> | undefined;\n if (offerings?.[0]?.offering_id) extracted.offering_id = offerings[0].offering_id;\n return extracted;\n },\n\n sync_plans(data) {\n const d = data as Record<string, unknown> | undefined;\n const plans = d?.plans as Array<Record<string, unknown>> | undefined;\n if (!plans?.[0]) return {};\n return { plan_id: plans[0].plan_id };\n },\n\n create_property_list(data) {\n const d = data as Record<string, unknown> | undefined;\n const list = d?.list as Record<string, unknown> | undefined;\n if (!list) return {};\n const extracted: Record<string, unknown> = {};\n if (list.list_id) extracted.property_list_id = list.list_id;\n if (list.name) extracted.property_list_name = list.name;\n // auth_token intentionally not extracted — avoid leaking credentials into\n // storyboard context which may appear in logs or compliance reports.\n return extracted;\n },\n\n create_content_standards(data) {\n const d = data as Record<string, unknown> | undefined;\n if (!d?.standards_id) return {};\n return { content_standards_id: d.standards_id };\n },\n\n get_rights(data) {\n const d = data as Record<string, unknown> | undefined;\n const rights = d?.rights as Array<Record<string, unknown>> | undefined;\n if (!rights?.[0]?.rights_id) return {};\n return { rights_id: rights[0].rights_id };\n },\n\n acquire_rights(data) {\n const d = data as Record<string, unknown> | undefined;\n if (!d?.rights_grant_id) return {};\n return { rights_grant_id: d.rights_grant_id, rights_id: d.rights_id };\n },\n\n sync_governance(data) {\n // Governance registration — no IDs to extract, just confirmation\n return { governance_synced: true, governance_response: data };\n },\n\n check_governance(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.governance_context) extracted.governance_context = d.governance_context;\n if (d?.check_id) extracted.check_id = d.check_id;\n if (d?.plan_id) extracted.plan_id = d.plan_id;\n if (d?.verdict) extracted.governance_status = d.verdict;\n return extracted;\n },\n\n report_plan_outcome(data) {\n const d = data as Record<string, unknown> | undefined;\n const extracted: Record<string, unknown> = {};\n if (d?.outcome_id) extracted.outcome_id = d.outcome_id;\n if (d?.outcome_state) extracted.outcome_status = d.outcome_state;\n return extracted;\n },\n};\n\n/**\n * Extract context values from a task response.\n */\nexport function extractContext(taskName: string, data: unknown): Record<string, unknown> {\n const extractor = CONTEXT_EXTRACTORS[taskName];\n if (!extractor) return {};\n try {\n return extractor(data);\n } catch {\n return {};\n }\n}\n\n// ────────────────────────────────────────────────────────────\n// Context injection: substitute $context.<key> in requests\n// ────────────────────────────────────────────────────────────\n\n/**\n * Per-context alias cache for `$generate:uuid_v4#<alias>` placeholders.\n *\n * A WeakMap keyed off the StoryboardContext identity avoids landing\n * implementation-detail keys on the serialized context object and avoids\n * fragility when context is shallow-cloned between steps — the cache\n * follows the context reference rather than riding as an owned key.\n *\n * Propagation across steps is handled by `forwardAliasCache` (called by\n * the runner when it rolls context forward to the next step), keeping\n * this a deliberate design choice rather than an invisible by-reference\n * leak through `{ ...context }`.\n */\nconst aliasCaches = new WeakMap<StoryboardContext, Record<string, string>>();\n\n/**\n * Ensure an alias cache exists for the given context and return it.\n */\nfunction getAliasCache(context: StoryboardContext): Record<string, string> {\n let cache = aliasCaches.get(context);\n if (!cache) {\n cache = {};\n aliasCaches.set(context, cache);\n }\n return cache;\n}\n\n/**\n * Propagate the alias cache from one context to another — call after\n * shallow-cloning context between storyboard steps so replay tests\n * (initial + replay sharing `$generate:uuid_v4#<alias>`) resolve to the\n * same UUID. No-op when `from` has no cache.\n */\nexport function forwardAliasCache(from: StoryboardContext, to: StoryboardContext): void {\n const cache = aliasCaches.get(from);\n if (cache) aliasCaches.set(to, cache);\n}\n\n/**\n * Runner-owned substitution variables.\n *\n * Parallels `$context.*` but lives outside the serialized context object so\n * implementation details (the receiver's bound URL, per-step operation ids)\n * stay off the compliance report. Expanded within strings (embedded\n * substitution), unlike `$context.*` which matches whole strings only.\n *\n * Supported patterns:\n * - `{{runner.webhook_base}}` — base URL of the receiver.\n * - `{{runner.webhook_url:<step_id>}}` — per-step webhook URL\n * (`<base>/step/<step_id>/<operation_id>`). The operation_id is minted\n * lazily on first expansion and cached for the rest of the run so the\n * matching `{{prior_step.<step_id>.operation_id}}` reference downstream\n * resolves to the same value.\n * - `{{prior_step.<step_id>.operation_id}}` — operation_id the runner\n * allocated when expanding `{{runner.webhook_url:<step_id>}}`.\n */\nexport interface RunnerVariables {\n /** Millisecond timestamp captured once at run start for deterministic enrichment. */\n runStartMs?: number;\n /** Base URL of the runner's webhook receiver, when enabled. */\n webhookBase?: string;\n /** step_id → operation_id, filled lazily on expansion. */\n stepOperationIds: Map<string, string>;\n /**\n * Free-form slot for cross-step run state that isn't user-facing. Used\n * today to share a single `InMemoryReplayStore` / `InMemoryRevocationStore`\n * across every `expect_webhook_signature_valid` call in a run so a\n * replayed (keyid, nonce) across two deliveries of the same event is\n * actually detected. Untyped here to keep the context module free of\n * signing-module imports.\n */\n runState: Map<string, unknown>;\n}\n\nexport function createRunnerVariables(opts: { webhookBase?: string } = {}): RunnerVariables {\n return {\n runStartMs: Date.now(),\n ...(opts.webhookBase !== undefined && { webhookBase: opts.webhookBase }),\n stepOperationIds: new Map(),\n runState: new Map(),\n };\n}\n\n/**\n * Deep-walk an object and replace recognized placeholder strings:\n *\n * - `$context.<key>` → value from `context[key]` (anchored whole-string match)\n * - `$generate:uuid_v4` → fresh UUID v4 per occurrence (anchored)\n * - `$generate:uuid_v4#<alias>` → fresh UUID v4 on first occurrence, then the\n * same UUID for every subsequent occurrence of the same alias within this\n * run (anchored)\n * - `{{runner.*}}` / `{{prior_step.<id>.operation_id}}` → embedded runner-\n * variable substitution (only when `runnerVars` is supplied)\n *\n * Returns a new object (does not mutate the input).\n */\nexport function injectContext(\n obj: Record<string, unknown>,\n context: StoryboardContext,\n runnerVars?: RunnerVariables\n): Record<string, unknown> {\n return deepReplace(obj, context, runnerVars) as Record<string, unknown>;\n}\n\nfunction deepReplace(value: unknown, context: StoryboardContext, runnerVars?: RunnerVariables): unknown {\n if (typeof value === 'string') {\n // Mustache first — expands in-place within the string, so anchored\n // patterns below still apply to the post-expansion result.\n const expanded = runnerVars ? expandMustache(value, runnerVars) : value;\n\n const ctxMatch = expanded.match(/^\\$context\\.(\\w+)$/);\n if (ctxMatch?.[1]) {\n const key = ctxMatch[1];\n return key in context ? context[key] : expanded;\n }\n const genMatch = expanded.match(/^\\$generate:(uuid_v4|opaque_id)(?:#([A-Za-z0-9_.-]+))?$/);\n if (genMatch) {\n const alias = genMatch[2];\n if (alias) {\n const cache = getAliasCache(context);\n if (!(alias in cache)) cache[alias] = randomUUID();\n return cache[alias];\n }\n return randomUUID();\n }\n return expanded;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => deepReplace(item, context, runnerVars));\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n result[k] = deepReplace(v, context, runnerVars);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * Expand every `{{runner.*}}` and `{{prior_step.*}}` token in a string.\n * Unknown tokens are left in place so the runner can surface a pointed\n * \"unresolved substitution\" error rather than silently shipping the\n * literal mustache tokens to an agent.\n */\n/**\n * Token shape for the outer expander. Single `[^{}]+` (excludes braces on\n * both sides) so nested or partial `{{…` can't straddle a token boundary\n * and force the engine to backtrack character-by-character. Unified prefix\n * alternation (`runner|prior_step`) keeps the two recognized names in one\n * place — the inner expander still narrows each. Closes CodeQL alert #49\n * (js/polynomial-redos).\n */\nconst MUSTACHE_TOKEN_RE = /\\{\\{((?:runner|prior_step)\\.[^{}]+)\\}\\}/g;\n\nfunction expandMustache(input: string, runnerVars: RunnerVariables): string {\n return input.replace(MUSTACHE_TOKEN_RE, (match, inner) => {\n if (inner === 'runner.webhook_base') {\n return runnerVars.webhookBase ?? match;\n }\n const webhookUrlMatch = /^runner\\.webhook_url:([A-Za-z0-9_]+)$/.exec(inner);\n if (webhookUrlMatch?.[1]) {\n if (!runnerVars.webhookBase) return match;\n const stepId = webhookUrlMatch[1];\n let opId = runnerVars.stepOperationIds.get(stepId);\n if (!opId) {\n opId = randomUUID();\n runnerVars.stepOperationIds.set(stepId, opId);\n }\n return `${runnerVars.webhookBase}/step/${stepId}/${opId}`;\n }\n const priorMatch = /^prior_step\\.([A-Za-z0-9_]+)\\.operation_id$/.exec(inner);\n if (priorMatch?.[1]) {\n return runnerVars.stepOperationIds.get(priorMatch[1]) ?? match;\n }\n return match;\n });\n}\n\n// ────────────────────────────────────────────────────────────\n// Explicit context_outputs: extract values by path\n// ────────────────────────────────────────────────────────────\n\n/**\n * Apply explicit context_outputs rules to extract values from response data.\n * Entries with `generate` set are skipped — use `applyContextOutputsWithProvenance`\n * (which accepts a context for alias-cache access) to handle those.\n *\n * Per runner-output-contract.yaml v2.0.0, paths that resolve to `undefined`,\n * `null`, or `\"\"` are equally non-resolvable — capturing null or \"\" produces\n * fabricated downstream state. The provenance-aware variant additionally\n * surfaces the failures on `ContextWriteResult.failures` so the runner can\n * synthesize a `capture_path_not_resolvable` validation result; this lower-\n * level form drops them silently and is kept for callers that don't need\n * the structured failure surface.\n */\nexport function applyContextOutputs(data: unknown, outputs: ContextOutput[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const output of outputs) {\n if (!output.path) continue;\n const value = resolvePath(data, output.path);\n if (value !== undefined && value !== null && value !== '') {\n result[output.key] = value;\n }\n }\n return result;\n}\n\n/**\n * Result of a context write with per-key provenance. The runner consumes\n * `provenance` to emit `context_value_rejected` hints when a later step's\n * seller response rejects a value that traces back to one of these keys.\n * `values` carries the same Record as the non-provenance call so the\n * runner's downstream `Object.assign(updatedContext, values)` path is\n * unchanged.\n */\nexport interface ContextWriteResult {\n values: Record<string, unknown>;\n provenance: Record<string, ContextProvenanceEntry>;\n /**\n * Convention-owned alias groups that must be removed before applying\n * `values`. Conditional groups only clear when the current context key\n * matches one of the response-derived values.\n */\n clearGroups?: Array<{\n keys: string[];\n when?: { key: string; values: unknown[] };\n }>;\n /**\n * `path:` entries whose declared response path did not resolve to a usable\n * value (absent, `null`, or `\"\"`). Per runner-output-contract.yaml v2.0.0,\n * the runner synthesizes a `capture_path_not_resolvable` validation result\n * for each entry — capturing null or \"\" produces fabricated downstream\n * state and is as incorrect as a missing path. Generator entries do not\n * appear here; they cannot fail to resolve. Absent or empty when every\n * `path:` entry produced a value.\n */\n failures?: Array<{ key: string; path: string; resolved: unknown }>;\n}\n\n/**\n * Like `extractContext`, but also returns provenance for each written key\n * tagging it as a convention-based extraction. `response_path` is absent\n * for convention extractors — they're hardcoded functions, not YAML paths.\n */\nexport function extractContextWithProvenance(taskName: string, data: unknown, stepId: string): ContextWriteResult {\n const values = extractContext(taskName, data);\n const clearGroups = (() => {\n const response = asRecord(data);\n switch (taskName) {\n case 'list_products':\n return response?.outcome === 'listed' && Array.isArray(response.products)\n ? [{ keys: PRODUCT_CONTEXT_KEYS }]\n : undefined;\n case 'request_proposals':\n return values.proposal_id ? [{ keys: PROPOSAL_CONTEXT_KEYS }] : undefined;\n case 'refine_proposals':\n return values.proposal_id ? [{ keys: PROPOSAL_CONTEXT_KEYS }] : undefined;\n case 'decline_proposals':\n const declinedIds = Array.isArray(response?.results)\n ? response.results\n .map(asRecord)\n .filter(result => result?.outcome === 'declined')\n .map(result => result?.proposal_id)\n .filter(proposalId => proposalId !== undefined)\n : [];\n return declinedIds.length\n ? [{ keys: PROPOSAL_CONTEXT_KEYS, when: { key: 'proposal_id', values: declinedIds } }]\n : undefined;\n default:\n return undefined;\n }\n })();\n const provenance: Record<string, ContextProvenanceEntry> = {};\n for (const key of Object.keys(values)) {\n provenance[key] = {\n source_step_id: stepId,\n source_kind: 'convention',\n source_task: taskName,\n };\n }\n return { values, provenance, ...(clearGroups && { clearGroups }) };\n}\n\n/**\n * Like `applyContextOutputs`, but also returns provenance for each written\n * key carrying the YAML `response_path` so diagnostics can cite it verbatim.\n *\n * Pass `context` to enable `generate:` entries with alias-cache coherence.\n * When an output declares `generate`, the runner mints a UUID v4 (or reuses\n * the value already cached under `output.key` if an inline `$generate:…#<alias>`\n * substitution ran in the same step). The generated value is written back into\n * the alias cache so that any later step referencing `$generate:opaque_id#<key>`\n * resolves to the same UUID.\n *\n * Omitting `context` disables alias-cache coherence: each generator entry mints\n * an independent UUID that cannot be matched by an inline `$generate:…` form.\n *\n * Generator entries fire regardless of whether `data` is present; path\n * entries are silently skipped when the resolved value is null/undefined.\n */\nexport function applyContextOutputsWithProvenance(\n data: unknown,\n outputs: ContextOutput[],\n stepId: string,\n taskName: string,\n context?: StoryboardContext\n): ContextWriteResult {\n const values: Record<string, unknown> = {};\n const provenance: Record<string, ContextProvenanceEntry> = {};\n const failures: Array<{ key: string; path: string; resolved: unknown }> = [];\n for (const output of outputs) {\n if (output.generate !== undefined) {\n // Generator entries require a context — without one the alias cache\n // can't be populated, so a later step's `$generate:opaque_id#<key>` would\n // mint an independent UUID that doesn't match the value stored here.\n // Loud error beats silent divergence.\n if (!context) {\n throw new Error(\n `applyContextOutputsWithProvenance: context_outputs entry '${output.key}' ` +\n `declares generate='${output.generate}' but no context was provided. ` +\n `Generator entries require a context for alias-cache coherence.`\n );\n }\n const cache = getAliasCache(context);\n let value: string;\n if (output.key in cache) {\n value = cache[output.key]!;\n } else {\n value = randomUUID();\n cache[output.key] = value;\n }\n values[output.key] = value;\n provenance[output.key] = {\n source_step_id: stepId,\n source_kind: 'generator',\n source_task: taskName,\n };\n } else if (output.path) {\n const value = resolvePath(data, output.path);\n // Per runner-output-contract.yaml v2.0.0 / storyboard-schema.yaml,\n // null, \"\", and structurally-absent paths are equally non-resolvable\n // for capture purposes — capturing null or \"\" produces fabricated\n // downstream state and is as incorrect as a missing path.\n const resolved = value === undefined || value === null || value === '';\n if (!resolved) {\n values[output.key] = value;\n provenance[output.key] = {\n source_step_id: stepId,\n source_kind: 'context_outputs',\n response_path: output.path,\n source_task: taskName,\n };\n } else {\n failures.push({\n key: output.key,\n path: output.path,\n resolved: value === undefined ? null : value,\n });\n }\n }\n }\n return { values, provenance, ...(failures.length > 0 ? { failures } : {}) };\n}\n\n// ────────────────────────────────────────────────────────────\n// Explicit context_inputs: inject values into request by path\n// ────────────────────────────────────────────────────────────\n\n/**\n * Apply explicit context_inputs rules to inject context values into a request.\n * Returns a new object (does not mutate the input).\n */\nexport function applyContextInputs(\n request: Record<string, unknown>,\n inputs: ContextInput[],\n context: StoryboardContext\n): Record<string, unknown> {\n const result = structuredClone(request);\n for (const input of inputs) {\n if (input.key in context) {\n setPath(result, input.inject_at, context[input.key]);\n }\n }\n return result;\n}\n\n// setPath is re-exported from ./path for backwards compat\nexport { setPath } from './path';\n"],"mappings":"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","names":["setPath"]}
@@ -1 +1 @@
1
- {"version":3,"file":"request-builder.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/request-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAk8BhE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,eAAe,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4BzB;AAED,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE5D;AAQD,6DAA6D;AAC7D,eAAO,MAAM,YAAY,sBAAgB,CAAC;AAE1C,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,2BAAqB,CAAC"}
1
+ {"version":3,"file":"request-builder.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/request-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAu+BhE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,eAAe,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4BzB;AAED,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE5D;AAQD,6DAA6D;AAC7D,eAAO,MAAM,YAAY,sBAAgB,CAAC;AAE1C,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,2BAAqB,CAAC"}
@@ -34,6 +34,8 @@ const FIXTURE_AWARE_ENRICHERS = /* @__PURE__ */ new Set([
34
34
  // merges discovery-derived product_id / pricing_option_id INTO fixture packages[0]
35
35
  "comply_test_controller",
36
36
  // forces account.sandbox: true regardless of fixture
37
+ "get_products",
38
+ // preserves wholesale fixture fields while keeping resolved account scope authoritative
37
39
  "update_media_buy",
38
40
  // resolves account via resolveAccount(options) so sandbox routing matches create_media_buy
39
41
  "get_media_buys",
@@ -41,6 +43,14 @@ const FIXTURE_AWARE_ENRICHERS = /* @__PURE__ */ new Set([
41
43
  "get_media_buy_delivery"
42
44
  // resolves account via resolveAccount(options) so sandbox routing matches create_media_buy
43
45
  ]);
46
+ function hasUnresolvedContextReference(value) {
47
+ if (typeof value === "string") return /^\$context\.\w+$/.test(value);
48
+ if (Array.isArray(value)) return value.some(hasUnresolvedContextReference);
49
+ if (value && typeof value === "object") {
50
+ return Object.values(value).some(hasUnresolvedContextReference);
51
+ }
52
+ return false;
53
+ }
44
54
  const PRODUCT_ID_SENTINELS = /* @__PURE__ */ new Set(["test-product"]);
45
55
  const PRICING_OPTION_ID_SENTINELS = /* @__PURE__ */ new Set(["test-pricing"]);
46
56
  const DAY_MS = 24 * 60 * 60 * 1e3;
@@ -149,23 +159,37 @@ const REQUEST_ENRICHERS = {
149
159
  },
150
160
  // ── Product Discovery ──────────────────────────────────
151
161
  get_products(step, context, options) {
162
+ const fixtureFields = step.sample_request ? omitEnvelopeFields(
163
+ (0, import_context.injectContext)({ ...step.sample_request }, context)
164
+ ) : {};
165
+ const fixtureAccount = fixtureFields.account;
166
+ const resolvedAccount = fixtureAccount !== void 0 && !hasUnresolvedContextReference(fixtureAccount) ? fixtureAccount : context.account ?? (0, import_client.resolveAccount)(options);
167
+ if (fixtureFields.buying_mode === "wholesale") {
168
+ return {
169
+ ...fixtureFields,
170
+ account: resolvedAccount
171
+ };
172
+ }
152
173
  if (step.sample_request?.buying_mode === "refine" && context.products) {
153
174
  return {
175
+ ...fixtureFields,
154
176
  buying_mode: "refine",
155
- refine: [
177
+ refine: fixtureFields.refine ?? [
156
178
  {
157
179
  scope: "request",
158
180
  ask: "Only guaranteed packages with premium placement."
159
181
  }
160
182
  ],
161
- brand: (0, import_client.resolveBrand)(options),
162
- account: context.account ?? (0, import_client.resolveAccount)(options)
183
+ brand: fixtureFields.brand ?? (0, import_client.resolveBrand)(options),
184
+ account: resolvedAccount
163
185
  };
164
186
  }
165
187
  return {
166
188
  buying_mode: "brief",
167
189
  brief: options.brief || "Show me all available advertising products across all channels",
168
- brand: (0, import_client.resolveBrand)(options)
190
+ brand: (0, import_client.resolveBrand)(options),
191
+ ...fixtureFields,
192
+ account: resolvedAccount
169
193
  };
170
194
  },
171
195
  // ── Media Buy ──────────────────────────────────────────