@adcp/sdk 13.0.0-rc.8 → 13.0.0-rc.9
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.
- package/dist/lib/adapters/roster-account-store.d.mts +9 -8
- package/dist/lib/adapters/roster-account-store.d.ts +9 -8
- package/dist/lib/adapters/roster-account-store.d.ts.map +1 -1
- package/dist/lib/adapters/roster-account-store.js +2 -1
- package/dist/lib/adapters/roster-account-store.js.map +1 -1
- package/dist/lib/adapters/roster-account-store.mjs +2 -1
- package/dist/lib/adapters/roster-account-store.mjs.map +1 -1
- package/dist/lib/net/address-guards.d.ts.map +1 -1
- package/dist/lib/net/address-guards.js +6 -0
- package/dist/lib/net/address-guards.js.map +1 -1
- package/dist/lib/net/address-guards.mjs +6 -0
- package/dist/lib/net/address-guards.mjs.map +1 -1
- package/dist/lib/net/ssrf-fetch.d.ts.map +1 -1
- package/dist/lib/net/ssrf-fetch.js +66 -53
- package/dist/lib/net/ssrf-fetch.js.map +1 -1
- package/dist/lib/net/ssrf-fetch.mjs +66 -53
- package/dist/lib/net/ssrf-fetch.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/account-mode.d.mts +2 -1
- package/dist/lib/server/account-mode.d.ts +2 -1
- package/dist/lib/server/account-mode.d.ts.map +1 -1
- package/dist/lib/server/account-mode.js +1 -0
- package/dist/lib/server/account-mode.js.map +1 -1
- package/dist/lib/server/account-mode.mjs +1 -0
- package/dist/lib/server/account-mode.mjs.map +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +10 -6
- package/dist/lib/server/create-adcp-server.d.ts +10 -6
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +2 -1
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +2 -1
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/decisioning/account.d.mts +16 -11
- package/dist/lib/server/decisioning/account.d.ts +16 -11
- package/dist/lib/server/decisioning/account.d.ts.map +1 -1
- package/dist/lib/server/decisioning/account.js.map +1 -1
- package/dist/lib/server/decisioning/account.mjs.map +1 -1
- package/dist/lib/server/decisioning/pagination.d.mts +2 -0
- package/dist/lib/server/decisioning/pagination.d.ts +2 -0
- package/dist/lib/server/decisioning/pagination.d.ts.map +1 -1
- package/dist/lib/server/decisioning/pagination.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +20 -14
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +20 -14
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +32 -6
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +32 -6
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.mts +16 -4
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +16 -4
- package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/server/index.mjs.map +1 -1
- package/dist/lib/server/legacy/v5/index.d.mts +2 -1
- package/dist/lib/server/legacy/v5/index.d.ts +2 -1
- package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
- package/dist/lib/server/legacy/v5/index.js.map +1 -1
- package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
- package/dist/lib/testing/compliance/comply.d.mts +2 -0
- package/dist/lib/testing/compliance/comply.d.ts +2 -0
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +45 -14
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/comply.mjs +45 -14
- package/dist/lib/testing/compliance/comply.mjs.map +1 -1
- package/dist/lib/testing/compliance/index.d.mts +1 -1
- package/dist/lib/testing/compliance/index.d.ts +1 -1
- package/dist/lib/testing/compliance/index.d.ts.map +1 -1
- package/dist/lib/testing/compliance/index.js.map +1 -1
- package/dist/lib/testing/compliance/index.mjs.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.js +9 -1
- package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -1
- package/dist/lib/testing/compliance/storyboard-tracks.mjs +9 -1
- package/dist/lib/testing/compliance/storyboard-tracks.mjs.map +1 -1
- package/dist/lib/testing/compliance/types.d.mts +26 -25
- package/dist/lib/testing/compliance/types.d.ts +26 -25
- package/dist/lib/testing/compliance/types.d.ts.map +1 -1
- package/dist/lib/testing/compliance/types.js.map +1 -1
- package/dist/lib/testing/index.d.mts +2 -2
- package/dist/lib/testing/index.d.ts +2 -2
- package/dist/lib/testing/index.d.ts.map +1 -1
- package/dist/lib/testing/index.js +16 -0
- package/dist/lib/testing/index.js.map +1 -1
- package/dist/lib/testing/index.mjs +16 -0
- package/dist/lib/testing/index.mjs.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.d.ts.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.js +20 -12
- package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
- package/dist/lib/testing/scenarios/media-buy.mjs +20 -12
- package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
- package/dist/lib/testing/storyboard/creative-assets.d.mts +23 -0
- package/dist/lib/testing/storyboard/creative-assets.d.ts +23 -0
- package/dist/lib/testing/storyboard/creative-assets.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/creative-assets.js +322 -45
- package/dist/lib/testing/storyboard/creative-assets.js.map +1 -1
- package/dist/lib/testing/storyboard/creative-assets.mjs +321 -45
- package/dist/lib/testing/storyboard/creative-assets.mjs.map +1 -1
- package/dist/lib/testing/storyboard/index.d.mts +4 -1
- package/dist/lib/testing/storyboard/index.d.ts +4 -1
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/index.js +20 -0
- package/dist/lib/testing/storyboard/index.js.map +1 -1
- package/dist/lib/testing/storyboard/index.mjs +19 -0
- package/dist/lib/testing/storyboard/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.mts +21 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts +22 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js +668 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs +638 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.mts +5 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.ts +6 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.js +44 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.js.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.mjs +20 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/index.mjs.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.mts +38 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.ts +39 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.js +17 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.js.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.mjs +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/types.mjs.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.mts +32 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.ts +33 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.js +105 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.js.map +1 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.mjs +80 -0
- package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.mjs.map +1 -0
- package/dist/lib/testing/storyboard/probes.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/probes.js +2 -1
- package/dist/lib/testing/storyboard/probes.js.map +1 -1
- package/dist/lib/testing/storyboard/probes.mjs +2 -1
- package/dist/lib/testing/storyboard/probes.mjs.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +382 -69
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.mjs +387 -70
- package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
- package/dist/lib/testing/storyboard/seeding.js +3 -1
- package/dist/lib/testing/storyboard/seeding.js.map +1 -1
- package/dist/lib/testing/storyboard/seeding.mjs +3 -1
- package/dist/lib/testing/storyboard/seeding.mjs.map +1 -1
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/task-map.js +16 -2
- package/dist/lib/testing/storyboard/task-map.js.map +1 -1
- package/dist/lib/testing/storyboard/task-map.mjs +16 -2
- package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
- package/dist/lib/testing/storyboard/trusted-match-context-replay.d.mts +11 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.d.ts +12 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.js +340 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.js.map +1 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.mjs +316 -0
- package/dist/lib/testing/storyboard/trusted-match-context-replay.mjs.map +1 -0
- package/dist/lib/testing/storyboard/types.d.mts +84 -15
- package/dist/lib/testing/storyboard/types.d.ts +84 -15
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/types.js +2 -0
- package/dist/lib/testing/storyboard/types.js.map +1 -1
- package/dist/lib/testing/storyboard/types.mjs +2 -0
- package/dist/lib/testing/storyboard/types.mjs.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +3 -0
- package/dist/lib/testing/storyboard/validations.d.ts +3 -0
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/validations.js +64 -24
- package/dist/lib/testing/storyboard/validations.js.map +1 -1
- package/dist/lib/testing/storyboard/validations.mjs +64 -24
- package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
- package/dist/lib/types/server-payload-aliases.d.mts +8 -2
- package/dist/lib/types/server-payload-aliases.d.ts +8 -2
- package/dist/lib/types/server-payload-aliases.d.ts.map +1 -1
- package/dist/lib/types/server-payload-aliases.js.map +1 -1
- package/dist/lib/upstream-recorder/recorder.d.mts +7 -18
- package/dist/lib/upstream-recorder/recorder.d.ts +7 -18
- package/dist/lib/upstream-recorder/recorder.d.ts.map +1 -1
- package/dist/lib/upstream-recorder/recorder.js +17 -10
- package/dist/lib/upstream-recorder/recorder.js.map +1 -1
- package/dist/lib/upstream-recorder/recorder.mjs +12 -5
- package/dist/lib/upstream-recorder/recorder.mjs.map +1 -1
- package/dist/lib/utils/redact-secrets.d.ts.map +1 -1
- package/dist/lib/utils/redact-secrets.js +7 -1
- package/dist/lib/utils/redact-secrets.js.map +1 -1
- package/dist/lib/utils/redact-secrets.mjs +7 -1
- package/dist/lib/utils/redact-secrets.mjs.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/docs/guides/BUILD-AN-AGENT.md +4 -2
- package/docs/llms.txt +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/testing/storyboard/task-map.ts"],"sourcesContent":["/**\n * Maps AdCP task names (from storyboard YAML) to SingleAgentClient method names.\n *\n * Each storyboard step has a `task` field like \"sync_accounts\" or \"get_products\".\n * This map resolves those to the camelCase method on SingleAgentClient.\n *\n * Tasks without a dedicated method fall through to `executeTask()`.\n */\n\nimport type { TaskResult } from '../types';\nimport type { AdcpErrorInfo } from '../../core/ConversationTypes';\nimport { isTerminalAdcpError, readExtractionPath } from '../../utils/response-unwrapper';\n\n/**\n * Map of AdCP task names to SingleAgentClient method names.\n * Only includes tasks that have dedicated typed methods.\n */\nexport const TASK_TO_METHOD: Record<string, string> = {\n // Account & audience\n sync_accounts: 'syncAccounts',\n list_accounts: 'listAccounts',\n sync_audiences: 'syncAudiences',\n\n // Product discovery & media buy\n get_products: 'getProducts',\n create_media_buy: 'createMediaBuy',\n update_media_buy: 'updateMediaBuy',\n get_media_buys: 'getMediaBuys',\n get_media_buy_delivery: 'getMediaBuyDelivery',\n provide_performance_feedback: 'providePerformanceFeedback',\n\n // Creative\n list_creative_formats: 'listCreativeFormats',\n build_creative: 'buildCreativeLegacy',\n preview_creative: 'previewCreativeLegacy',\n sync_creatives: 'syncCreatives',\n list_creatives: 'listCreatives',\n\n // Signals\n get_signals: 'getSignals',\n activate_signal: 'activateSignal',\n\n // Capabilities\n get_adcp_capabilities: 'getAdcpCapabilities',\n\n // Governance\n sync_plans: 'syncPlans',\n check_governance: 'checkGovernance',\n get_plan_audit_logs: 'getPlanAuditLogs',\n create_property_list: 'createPropertyList',\n get_property_list: 'getPropertyList',\n update_property_list: 'updatePropertyList',\n list_property_lists: 'listPropertyLists',\n delete_property_list: 'deletePropertyList',\n list_collection_lists: 'listCollectionLists',\n list_content_standards: 'listContentStandards',\n get_content_standards: 'getContentStandards',\n create_content_standards: 'createContentStandards',\n update_content_standards: 'updateContentStandards',\n calibrate_content: 'calibrateContent',\n validate_content_delivery: 'validateContentDelivery',\n\n // Account\n get_account_financials: 'getAccountFinancials',\n log_event: 'logEvent',\n\n // Sponsored Intelligence\n si_get_offering: 'siGetOffering',\n si_initiate_session: 'siInitiateSession',\n si_send_message: 'siSendMessage',\n si_terminate_session: 'siTerminateSession',\n};\n\n/** Storyboards grade the selected protocol wire, not the SDK's canonical API. */\nconst LEGACY_CREATIVE_TASK_TO_METHOD: Readonly<Record<string, string>> = {\n get_products: 'getProductsLegacy',\n create_media_buy: 'createMediaBuyLegacy',\n update_media_buy: 'updateMediaBuyLegacy',\n sync_creatives: 'syncCreativesLegacy',\n list_creatives: 'listCreativesLegacy',\n};\n\nfunction gradesLegacyCreativeWire(client: unknown): boolean {\n if (client === null || typeof client !== 'object') return false;\n const getAdcpVersion = (client as { getAdcpVersion?: unknown }).getAdcpVersion;\n if (typeof getAdcpVersion !== 'function') return false;\n let version: unknown;\n try {\n version = getAdcpVersion.call(client);\n } catch {\n return false;\n }\n if (typeof version !== 'string') return false;\n const match = /^v?(\\d+)(?:\\.(\\d+))?/.exec(version.trim());\n if (!match) return false;\n const major = Number(match[1]);\n const minor = Number(match[2] ?? 0);\n return major < 3 || (major === 3 && minor < 2);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction withLegacyCreativeWireHint(params: Record<string, unknown>): Record<string, unknown> {\n const ext = isRecord(params.ext) ? params.ext : {};\n const adcp = isRecord(ext.adcp) ? ext.adcp : {};\n if (adcp.creative_wire === 'legacy' || adcp.creative_wire === 'canonical') return params;\n return {\n ...params,\n ext: {\n ...ext,\n adcp: { ...adcp, creative_wire: 'legacy' },\n },\n };\n}\n\nfunction readAdcpError(value: unknown): AdcpErrorInfo | undefined {\n if (!isRecord(value)) return undefined;\n const error = value.adcp_error;\n if (!isRecord(error) || typeof error.code !== 'string') return undefined;\n return error as unknown as AdcpErrorInfo;\n}\n\nfunction readFirstError(value: unknown): AdcpErrorInfo | undefined {\n if (!isRecord(value) || !Array.isArray(value.errors)) return undefined;\n const first = value.errors[0];\n if (!isRecord(first) || typeof first.code !== 'string') return undefined;\n return {\n code: first.code,\n message: typeof first.message === 'string' ? first.message : String(first.code),\n ...(typeof first.recovery === 'string' && { recovery: first.recovery as AdcpErrorInfo['recovery'] }),\n ...(typeof first.field === 'string' && { field: first.field }),\n ...(typeof first.suggestion === 'string' && { suggestion: first.suggestion }),\n ...(typeof first.retry_after === 'number' && { retry_after: first.retry_after }),\n ...(isRecord(first.details) && { details: first.details }),\n };\n}\n\nfunction errorMessageFrom(error: AdcpErrorInfo | undefined, fallback: unknown): string | undefined {\n if (typeof error?.message === 'string' && error.message.length > 0) return error.message;\n if (typeof error?.code === 'string') return error.code;\n return typeof fallback === 'string' && fallback.length > 0 ? fallback : undefined;\n}\n\nfunction normalizeStoryboardTaskSuccess(\n result: unknown,\n taskName: string,\n terminalDataError?: boolean,\n adcpError?: AdcpErrorInfo\n): boolean {\n if (!isRecord(result)) return true;\n if (typeof result.success === 'boolean') return result.success;\n if (result.status === 'failed' || result.status === 'rejected') return false;\n if (adcpError || result.adcpError || result.adcp_error) return false;\n if (terminalDataError ?? isTerminalAdcpError(result.data, taskName)) return false;\n return true;\n}\n\n/**\n * Execute a storyboard task against a SingleAgentClient.\n *\n * Uses the typed method if one exists, otherwise falls back to executeTask().\n * When the agent returns an async status (working/submitted), waits for\n * completion before returning — storyboard steps expect final results.\n */\nexport async function executeStoryboardTask(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic dispatch requires any\n client: any,\n taskName: string,\n params: Record<string, unknown>,\n opts: { skipIdempotencyAutoInject?: boolean; skipAccountValidation?: boolean; signal?: AbortSignal } = {}\n): Promise<TaskResult> {\n const legacyMethodName = gradesLegacyCreativeWire(client) ? LEGACY_CREATIVE_TASK_TO_METHOD[taskName] : undefined;\n const methodName =\n legacyMethodName ?? (Object.hasOwn(TASK_TO_METHOD, taskName) ? TASK_TO_METHOD[taskName] : undefined);\n const callParams = legacyMethodName ? withLegacyCreativeWireHint(params) : params;\n\n // Only pass TaskOptions when a flag is actually set — avoids changing\n // behavior for the common path that relies on method defaults.\n const taskOptions =\n opts.skipIdempotencyAutoInject || opts.skipAccountValidation\n ? {\n ...(opts.skipIdempotencyAutoInject && { skipIdempotencyAutoInject: true }),\n ...(opts.skipAccountValidation && { skipAccountValidation: true }),\n }\n : undefined;\n\n let result;\n const invoke = async () => {\n if (methodName && typeof client[methodName] === 'function') {\n // Typed methods take (params, inputHandler?, options?). Pass options\n // only when set, otherwise they take their defaults.\n return taskOptions ? client[methodName](callParams, undefined, taskOptions) : client[methodName](callParams);\n }\n return client.executeTask(taskName, callParams, undefined, taskOptions);\n };\n\n // Retry with exponential backoff on rate limit errors\n const MAX_RETRIES = 3;\n const BASE_DELAY_MS = 2000;\n for (let attempt = 0; ; attempt++) {\n try {\n result = await raceWithSignal(invoke(), opts.signal);\n break;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isRateLimit =\n /rate limit/i.test(msg) || (/\"code\":\\s*-32000/.test(msg) && /rate.?limit|too many|throttl/i.test(msg));\n if (isRateLimit && attempt < MAX_RETRIES) {\n const jitter = Math.random() * 1000;\n const delay = BASE_DELAY_MS * 2 ** attempt + jitter;\n await raceWithSignal(new Promise(resolve => setTimeout(resolve, delay)), opts.signal);\n continue;\n }\n throw err;\n }\n }\n\n // If the agent returned an async status but included data in the initial\n // response (common for agents that process synchronously but report as\n // submitted), use that data. Only poll when there's no data at all.\n const hasData = result.data !== undefined && result.data !== null;\n const isAsync = result.status === 'submitted' || result.status === 'working';\n const prePollingDebugLogs = Array.isArray(result.debug_logs) ? [...result.debug_logs] : [];\n let replacedByPolling = false;\n if (!hasData && isAsync && result.submitted?.waitForCompletion) {\n try {\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Task polling timeout')), 30_000)\n );\n result = await raceWithSignal(\n Promise.race([result.submitted.waitForCompletion(2000, opts.signal), timeout]),\n opts.signal\n );\n replacedByPolling = true;\n } catch (err) {\n if (opts.signal?.aborted) throw err;\n // Polling failed or timed out — return the intermediate result as-is\n }\n }\n\n const terminalDataError = isTerminalAdcpError(result.data, taskName);\n const adcpError =\n result.adcpError ??\n result.adcp_error ??\n readAdcpError(result.data) ??\n (terminalDataError ? readFirstError(result.data) : undefined);\n const data = result.data ?? (adcpError ? { adcp_error: adcpError } : undefined);\n const success = normalizeStoryboardTaskSuccess(result, taskName, terminalDataError, adcpError);\n const error = result.error ?? (!success ? errorMessageFrom(adcpError, undefined) : undefined);\n const extractionPath = readExtractionPath(data);\n const debugLogs = Array.isArray(result.debug_logs) ? result.debug_logs : [];\n const mergedDebugLogs = replacedByPolling ? [...prePollingDebugLogs, ...debugLogs] : debugLogs;\n return {\n success,\n data,\n error,\n ...(adcpError && { adcp_error: adcpError }),\n ...(extractionPath !== undefined && { _extraction_path: extractionPath }),\n ...(mergedDebugLogs.length > 0 && { debug_logs: mergedDebugLogs }),\n };\n}\n\nfunction raceWithSignal<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) return Promise.reject(signal.reason ?? new Error('aborted'));\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason ?? new Error('aborted'));\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n value => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n err => {\n signal.removeEventListener('abort', onAbort);\n reject(err);\n }\n );\n });\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/testing/storyboard/task-map.ts"],"sourcesContent":["/**\n * Maps AdCP task names (from storyboard YAML) to SingleAgentClient method names.\n *\n * Each storyboard step has a `task` field like \"sync_accounts\" or \"get_products\".\n * This map resolves those to the camelCase method on SingleAgentClient.\n *\n * Tasks without a dedicated method fall through to `executeTask()`.\n */\n\nimport type { TaskResult } from '../types';\nimport type { AdcpErrorInfo } from '../../core/ConversationTypes';\nimport { isTerminalAdcpError, readExtractionPath } from '../../utils/response-unwrapper';\nimport { BUILD_ASSETS_FROM_FORMAT_DIRECTIVE, findUnresolvedCreativeAssetDirectives } from './creative-assets';\n\n/**\n * Map of AdCP task names to SingleAgentClient method names.\n * Only includes tasks that have dedicated typed methods.\n */\nexport const TASK_TO_METHOD: Record<string, string> = {\n // Account & audience\n sync_accounts: 'syncAccounts',\n list_accounts: 'listAccounts',\n sync_audiences: 'syncAudiences',\n\n // Product discovery & media buy\n get_products: 'getProducts',\n create_media_buy: 'createMediaBuy',\n update_media_buy: 'updateMediaBuy',\n get_media_buys: 'getMediaBuys',\n get_media_buy_delivery: 'getMediaBuyDelivery',\n provide_performance_feedback: 'providePerformanceFeedback',\n\n // Creative\n list_creative_formats: 'listCreativeFormats',\n build_creative: 'buildCreativeLegacy',\n preview_creative: 'previewCreativeLegacy',\n sync_creatives: 'syncCreatives',\n list_creatives: 'listCreatives',\n\n // Signals\n get_signals: 'getSignals',\n activate_signal: 'activateSignal',\n\n // Capabilities\n get_adcp_capabilities: 'getAdcpCapabilities',\n\n // Governance\n sync_plans: 'syncPlans',\n check_governance: 'checkGovernance',\n get_plan_audit_logs: 'getPlanAuditLogs',\n create_property_list: 'createPropertyList',\n get_property_list: 'getPropertyList',\n update_property_list: 'updatePropertyList',\n list_property_lists: 'listPropertyLists',\n delete_property_list: 'deletePropertyList',\n list_collection_lists: 'listCollectionLists',\n list_content_standards: 'listContentStandards',\n get_content_standards: 'getContentStandards',\n create_content_standards: 'createContentStandards',\n update_content_standards: 'updateContentStandards',\n calibrate_content: 'calibrateContent',\n validate_content_delivery: 'validateContentDelivery',\n\n // Account\n get_account_financials: 'getAccountFinancials',\n log_event: 'logEvent',\n\n // Sponsored Intelligence\n si_get_offering: 'siGetOffering',\n si_initiate_session: 'siInitiateSession',\n si_send_message: 'siSendMessage',\n si_terminate_session: 'siTerminateSession',\n};\n\n/** Storyboards grade the selected protocol wire, not the SDK's canonical API. */\nconst LEGACY_CREATIVE_TASK_TO_METHOD: Readonly<Record<string, string>> = {\n get_products: 'getProductsLegacy',\n create_media_buy: 'createMediaBuyLegacy',\n update_media_buy: 'updateMediaBuyLegacy',\n sync_creatives: 'syncCreativesLegacy',\n list_creatives: 'listCreativesLegacy',\n};\n\nfunction gradesLegacyCreativeWire(client: unknown): boolean {\n if (client === null || typeof client !== 'object') return false;\n const getAdcpVersion = (client as { getAdcpVersion?: unknown }).getAdcpVersion;\n if (typeof getAdcpVersion !== 'function') return false;\n let version: unknown;\n try {\n version = getAdcpVersion.call(client);\n } catch {\n return false;\n }\n if (typeof version !== 'string') return false;\n const match = /^v?(\\d+)(?:\\.(\\d+))?/.exec(version.trim());\n if (!match) return false;\n const major = Number(match[1]);\n const minor = Number(match[2] ?? 0);\n return major < 3 || (major === 3 && minor < 2);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction readCreativeWireHint(params: Record<string, unknown>): 'legacy' | 'canonical' | undefined {\n if (!isRecord(params.ext) || !isRecord(params.ext.adcp)) return undefined;\n const wire = params.ext.adcp.creative_wire;\n return wire === 'legacy' || wire === 'canonical' ? wire : undefined;\n}\n\nfunction withLegacyCreativeWireHint(params: Record<string, unknown>): Record<string, unknown> {\n if (readCreativeWireHint(params)) return params;\n const ext = isRecord(params.ext) ? params.ext : {};\n const adcp = isRecord(ext.adcp) ? ext.adcp : {};\n return {\n ...params,\n ext: {\n ...ext,\n adcp: { ...adcp, creative_wire: 'legacy' },\n },\n };\n}\n\nfunction readAdcpError(value: unknown): AdcpErrorInfo | undefined {\n if (!isRecord(value)) return undefined;\n const error = value.adcp_error;\n if (!isRecord(error) || typeof error.code !== 'string') return undefined;\n return error as unknown as AdcpErrorInfo;\n}\n\nfunction readFirstError(value: unknown): AdcpErrorInfo | undefined {\n if (!isRecord(value) || !Array.isArray(value.errors)) return undefined;\n const first = value.errors[0];\n if (!isRecord(first) || typeof first.code !== 'string') return undefined;\n return {\n code: first.code,\n message: typeof first.message === 'string' ? first.message : String(first.code),\n ...(typeof first.recovery === 'string' && { recovery: first.recovery as AdcpErrorInfo['recovery'] }),\n ...(typeof first.field === 'string' && { field: first.field }),\n ...(typeof first.suggestion === 'string' && { suggestion: first.suggestion }),\n ...(typeof first.retry_after === 'number' && { retry_after: first.retry_after }),\n ...(isRecord(first.details) && { details: first.details }),\n };\n}\n\nfunction errorMessageFrom(error: AdcpErrorInfo | undefined, fallback: unknown): string | undefined {\n if (typeof error?.message === 'string' && error.message.length > 0) return error.message;\n if (typeof error?.code === 'string') return error.code;\n return typeof fallback === 'string' && fallback.length > 0 ? fallback : undefined;\n}\n\nfunction normalizeStoryboardTaskSuccess(\n result: unknown,\n taskName: string,\n terminalDataError?: boolean,\n adcpError?: AdcpErrorInfo\n): boolean {\n if (!isRecord(result)) return true;\n if (typeof result.success === 'boolean') return result.success;\n if (result.status === 'failed' || result.status === 'rejected') return false;\n if (adcpError || result.adcpError || result.adcp_error) return false;\n if (terminalDataError ?? isTerminalAdcpError(result.data, taskName)) return false;\n return true;\n}\n\n/**\n * Execute a storyboard task against a SingleAgentClient.\n *\n * Uses the typed method if one exists, otherwise falls back to executeTask().\n * When the agent returns an async status (working/submitted), waits for\n * completion before returning — storyboard steps expect final results.\n */\nexport async function executeStoryboardTask(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic dispatch requires any\n client: any,\n taskName: string,\n params: Record<string, unknown>,\n opts: { skipIdempotencyAutoInject?: boolean; skipAccountValidation?: boolean; signal?: AbortSignal } = {}\n): Promise<TaskResult> {\n const unresolvedAssetDirectives = findUnresolvedCreativeAssetDirectives(params);\n if (unresolvedAssetDirectives.length > 0) {\n return {\n success: false,\n error:\n `Request contains unexpanded storyboard directive '${BUILD_ASSETS_FROM_FORMAT_DIRECTIVE}' at ` +\n `${unresolvedAssetDirectives.join(', ')}. ` +\n 'Call expandCreativeAssetDirectives(params, context, testKit) before passing params to executeStoryboardTask.',\n };\n }\n\n // AdCP 3.1 transition storyboards default to the legacy creative wire, but\n // canonical-specific storyboards must be able to opt into the canonical API.\n const useLegacyCreativeMethod = gradesLegacyCreativeWire(client) && readCreativeWireHint(params) !== 'canonical';\n const legacyMethodName = useLegacyCreativeMethod ? LEGACY_CREATIVE_TASK_TO_METHOD[taskName] : undefined;\n const methodName =\n legacyMethodName ?? (Object.hasOwn(TASK_TO_METHOD, taskName) ? TASK_TO_METHOD[taskName] : undefined);\n const callParams = legacyMethodName ? withLegacyCreativeWireHint(params) : params;\n\n // Only pass TaskOptions when a flag is actually set — avoids changing\n // behavior for the common path that relies on method defaults.\n const taskOptions =\n opts.skipIdempotencyAutoInject || opts.skipAccountValidation\n ? {\n ...(opts.skipIdempotencyAutoInject && { skipIdempotencyAutoInject: true }),\n ...(opts.skipAccountValidation && { skipAccountValidation: true }),\n }\n : undefined;\n\n let result;\n const invoke = async () => {\n if (methodName && typeof client[methodName] === 'function') {\n // Typed methods take (params, inputHandler?, options?). Pass options\n // only when set, otherwise they take their defaults.\n return taskOptions ? client[methodName](callParams, undefined, taskOptions) : client[methodName](callParams);\n }\n return client.executeTask(taskName, callParams, undefined, taskOptions);\n };\n\n // Retry with exponential backoff on rate limit errors\n const MAX_RETRIES = 3;\n const BASE_DELAY_MS = 2000;\n for (let attempt = 0; ; attempt++) {\n try {\n result = await raceWithSignal(invoke(), opts.signal);\n break;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isRateLimit =\n /rate limit/i.test(msg) || (/\"code\":\\s*-32000/.test(msg) && /rate.?limit|too many|throttl/i.test(msg));\n if (isRateLimit && attempt < MAX_RETRIES) {\n const jitter = Math.random() * 1000;\n const delay = BASE_DELAY_MS * 2 ** attempt + jitter;\n await raceWithSignal(new Promise(resolve => setTimeout(resolve, delay)), opts.signal);\n continue;\n }\n throw err;\n }\n }\n\n // If the agent returned an async status but included data in the initial\n // response (common for agents that process synchronously but report as\n // submitted), use that data. Only poll when there's no data at all.\n const hasData = result.data !== undefined && result.data !== null;\n const isAsync = result.status === 'submitted' || result.status === 'working';\n const prePollingDebugLogs = Array.isArray(result.debug_logs) ? [...result.debug_logs] : [];\n let replacedByPolling = false;\n if (!hasData && isAsync && result.submitted?.waitForCompletion) {\n try {\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Task polling timeout')), 30_000)\n );\n result = await raceWithSignal(\n Promise.race([result.submitted.waitForCompletion(2000, opts.signal), timeout]),\n opts.signal\n );\n replacedByPolling = true;\n } catch (err) {\n if (opts.signal?.aborted) throw err;\n // Polling failed or timed out — return the intermediate result as-is\n }\n }\n\n const terminalDataError = isTerminalAdcpError(result.data, taskName);\n const adcpError =\n result.adcpError ??\n result.adcp_error ??\n readAdcpError(result.data) ??\n (terminalDataError ? readFirstError(result.data) : undefined);\n const data = result.data ?? (adcpError ? { adcp_error: adcpError } : undefined);\n const success = normalizeStoryboardTaskSuccess(result, taskName, terminalDataError, adcpError);\n const error = result.error ?? (!success ? errorMessageFrom(adcpError, undefined) : undefined);\n const extractionPath = readExtractionPath(data);\n const debugLogs = Array.isArray(result.debug_logs) ? result.debug_logs : [];\n const mergedDebugLogs = replacedByPolling ? [...prePollingDebugLogs, ...debugLogs] : debugLogs;\n return {\n success,\n data,\n error,\n ...(adcpError && { adcp_error: adcpError }),\n ...(extractionPath !== undefined && { _extraction_path: extractionPath }),\n ...(mergedDebugLogs.length > 0 && { debug_logs: mergedDebugLogs }),\n };\n}\n\nfunction raceWithSignal<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) return Promise.reject(signal.reason ?? new Error('aborted'));\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason ?? new Error('aborted'));\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n value => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n err => {\n signal.removeEventListener('abort', onAbort);\n reject(err);\n }\n );\n });\n}\n"],"mappings":"AAWA,SAAS,qBAAqB,0BAA0B;AACxD,SAAS,oCAAoC,6CAA6C;AAMnF,MAAM,iBAAyC;AAAA;AAAA,EAEpD,eAAe;AAAA,EACf,eAAe;AAAA,EACf,gBAAgB;AAAA;AAAA,EAGhB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,wBAAwB;AAAA,EACxB,8BAA8B;AAAA;AAAA,EAG9B,uBAAuB;AAAA,EACvB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA;AAAA,EAGhB,aAAa;AAAA,EACb,iBAAiB;AAAA;AAAA,EAGjB,uBAAuB;AAAA;AAAA,EAGvB,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,2BAA2B;AAAA;AAAA,EAG3B,wBAAwB;AAAA,EACxB,WAAW;AAAA;AAAA,EAGX,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,iBAAiB;AAAA,EACjB,sBAAsB;AACxB;AAGA,MAAM,iCAAmE;AAAA,EACvE,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,gBAAgB;AAClB;AAEA,SAAS,yBAAyB,QAA0B;AAC1D,MAAI,WAAW,QAAQ,OAAO,WAAW,SAAU,QAAO;AAC1D,QAAM,iBAAkB,OAAwC;AAChE,MAAI,OAAO,mBAAmB,WAAY,QAAO;AACjD,MAAI;AACJ,MAAI;AACF,cAAU,eAAe,KAAK,MAAM;AAAA,EACtC,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,QAAM,QAAQ,uBAAuB,KAAK,QAAQ,KAAK,CAAC;AACxD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAQ,OAAO,MAAM,CAAC,CAAC;AAC7B,QAAM,QAAQ,OAAO,MAAM,CAAC,KAAK,CAAC;AAClC,SAAO,QAAQ,KAAM,UAAU,KAAK,QAAQ;AAC9C;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,qBAAqB,QAAqE;AACjG,MAAI,CAAC,SAAS,OAAO,GAAG,KAAK,CAAC,SAAS,OAAO,IAAI,IAAI,EAAG,QAAO;AAChE,QAAM,OAAO,OAAO,IAAI,KAAK;AAC7B,SAAO,SAAS,YAAY,SAAS,cAAc,OAAO;AAC5D;AAEA,SAAS,2BAA2B,QAA0D;AAC5F,MAAI,qBAAqB,MAAM,EAAG,QAAO;AACzC,QAAM,MAAM,SAAS,OAAO,GAAG,IAAI,OAAO,MAAM,CAAC;AACjD,QAAM,OAAO,SAAS,IAAI,IAAI,IAAI,IAAI,OAAO,CAAC;AAC9C,SAAO;AAAA,IACL,GAAG;AAAA,IACH,KAAK;AAAA,MACH,GAAG;AAAA,MACH,MAAM,EAAE,GAAG,MAAM,eAAe,SAAS;AAAA,IAC3C;AAAA,EACF;AACF;AAEA,SAAS,cAAc,OAA2C;AAChE,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAC7B,QAAM,QAAQ,MAAM;AACpB,MAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,SAAU,QAAO;AAC/D,SAAO;AACT;AAEA,SAAS,eAAe,OAA2C;AACjE,MAAI,CAAC,SAAS,KAAK,KAAK,CAAC,MAAM,QAAQ,MAAM,MAAM,EAAG,QAAO;AAC7D,QAAM,QAAQ,MAAM,OAAO,CAAC;AAC5B,MAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,SAAU,QAAO;AAC/D,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU,OAAO,MAAM,IAAI;AAAA,IAC9E,GAAI,OAAO,MAAM,aAAa,YAAY,EAAE,UAAU,MAAM,SAAsC;AAAA,IAClG,GAAI,OAAO,MAAM,UAAU,YAAY,EAAE,OAAO,MAAM,MAAM;AAAA,IAC5D,GAAI,OAAO,MAAM,eAAe,YAAY,EAAE,YAAY,MAAM,WAAW;AAAA,IAC3E,GAAI,OAAO,MAAM,gBAAgB,YAAY,EAAE,aAAa,MAAM,YAAY;AAAA,IAC9E,GAAI,SAAS,MAAM,OAAO,KAAK,EAAE,SAAS,MAAM,QAAQ;AAAA,EAC1D;AACF;AAEA,SAAS,iBAAiB,OAAkC,UAAuC;AACjG,MAAI,OAAO,OAAO,YAAY,YAAY,MAAM,QAAQ,SAAS,EAAG,QAAO,MAAM;AACjF,MAAI,OAAO,OAAO,SAAS,SAAU,QAAO,MAAM;AAClD,SAAO,OAAO,aAAa,YAAY,SAAS,SAAS,IAAI,WAAW;AAC1E;AAEA,SAAS,+BACP,QACA,UACA,mBACA,WACS;AACT,MAAI,CAAC,SAAS,MAAM,EAAG,QAAO;AAC9B,MAAI,OAAO,OAAO,YAAY,UAAW,QAAO,OAAO;AACvD,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,WAAY,QAAO;AACvE,MAAI,aAAa,OAAO,aAAa,OAAO,WAAY,QAAO;AAC/D,MAAI,qBAAqB,oBAAoB,OAAO,MAAM,QAAQ,EAAG,QAAO;AAC5E,SAAO;AACT;AASA,eAAsB,sBAEpB,QACA,UACA,QACA,OAAuG,CAAC,GACnF;AACrB,QAAM,4BAA4B,sCAAsC,MAAM;AAC9E,MAAI,0BAA0B,SAAS,GAAG;AACxC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OACE,qDAAqD,kCAAkC,QACpF,0BAA0B,KAAK,IAAI,CAAC;AAAA,IAE3C;AAAA,EACF;AAIA,QAAM,0BAA0B,yBAAyB,MAAM,KAAK,qBAAqB,MAAM,MAAM;AACrG,QAAM,mBAAmB,0BAA0B,+BAA+B,QAAQ,IAAI;AAC9F,QAAM,aACJ,qBAAqB,OAAO,OAAO,gBAAgB,QAAQ,IAAI,eAAe,QAAQ,IAAI;AAC5F,QAAM,aAAa,mBAAmB,2BAA2B,MAAM,IAAI;AAI3E,QAAM,cACJ,KAAK,6BAA6B,KAAK,wBACnC;AAAA,IACE,GAAI,KAAK,6BAA6B,EAAE,2BAA2B,KAAK;AAAA,IACxE,GAAI,KAAK,yBAAyB,EAAE,uBAAuB,KAAK;AAAA,EAClE,IACA;AAEN,MAAI;AACJ,QAAM,SAAS,YAAY;AACzB,QAAI,cAAc,OAAO,OAAO,UAAU,MAAM,YAAY;AAG1D,aAAO,cAAc,OAAO,UAAU,EAAE,YAAY,QAAW,WAAW,IAAI,OAAO,UAAU,EAAE,UAAU;AAAA,IAC7G;AACA,WAAO,OAAO,YAAY,UAAU,YAAY,QAAW,WAAW;AAAA,EACxE;AAGA,QAAM,cAAc;AACpB,QAAM,gBAAgB;AACtB,WAAS,UAAU,KAAK,WAAW;AACjC,QAAI;AACF,eAAS,MAAM,eAAe,OAAO,GAAG,KAAK,MAAM;AACnD;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAM,cACJ,cAAc,KAAK,GAAG,KAAM,mBAAmB,KAAK,GAAG,KAAK,gCAAgC,KAAK,GAAG;AACtG,UAAI,eAAe,UAAU,aAAa;AACxC,cAAM,SAAS,KAAK,OAAO,IAAI;AAC/B,cAAM,QAAQ,gBAAgB,KAAK,UAAU;AAC7C,cAAM,eAAe,IAAI,QAAQ,aAAW,WAAW,SAAS,KAAK,CAAC,GAAG,KAAK,MAAM;AACpF;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAKA,QAAM,UAAU,OAAO,SAAS,UAAa,OAAO,SAAS;AAC7D,QAAM,UAAU,OAAO,WAAW,eAAe,OAAO,WAAW;AACnE,QAAM,sBAAsB,MAAM,QAAQ,OAAO,UAAU,IAAI,CAAC,GAAG,OAAO,UAAU,IAAI,CAAC;AACzF,MAAI,oBAAoB;AACxB,MAAI,CAAC,WAAW,WAAW,OAAO,WAAW,mBAAmB;AAC9D,QAAI;AACF,YAAM,UAAU,IAAI;AAAA,QAAe,CAAC,GAAG,WACrC,WAAW,MAAM,OAAO,IAAI,MAAM,sBAAsB,CAAC,GAAG,GAAM;AAAA,MACpE;AACA,eAAS,MAAM;AAAA,QACb,QAAQ,KAAK,CAAC,OAAO,UAAU,kBAAkB,KAAM,KAAK,MAAM,GAAG,OAAO,CAAC;AAAA,QAC7E,KAAK;AAAA,MACP;AACA,0BAAoB;AAAA,IACtB,SAAS,KAAK;AACZ,UAAI,KAAK,QAAQ,QAAS,OAAM;AAAA,IAElC;AAAA,EACF;AAEA,QAAM,oBAAoB,oBAAoB,OAAO,MAAM,QAAQ;AACnE,QAAM,YACJ,OAAO,aACP,OAAO,cACP,cAAc,OAAO,IAAI,MACxB,oBAAoB,eAAe,OAAO,IAAI,IAAI;AACrD,QAAM,OAAO,OAAO,SAAS,YAAY,EAAE,YAAY,UAAU,IAAI;AACrE,QAAM,UAAU,+BAA+B,QAAQ,UAAU,mBAAmB,SAAS;AAC7F,QAAM,QAAQ,OAAO,UAAU,CAAC,UAAU,iBAAiB,WAAW,MAAS,IAAI;AACnF,QAAM,iBAAiB,mBAAmB,IAAI;AAC9C,QAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,IAAI,OAAO,aAAa,CAAC;AAC1E,QAAM,kBAAkB,oBAAoB,CAAC,GAAG,qBAAqB,GAAG,SAAS,IAAI;AACrF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,aAAa,EAAE,YAAY,UAAU;AAAA,IACzC,GAAI,mBAAmB,UAAa,EAAE,kBAAkB,eAAe;AAAA,IACvE,GAAI,gBAAgB,SAAS,KAAK,EAAE,YAAY,gBAAgB;AAAA,EAClE;AACF;AAEA,SAAS,eAAkB,SAAqB,QAAkC;AAChF,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,OAAO,QAAS,QAAO,QAAQ,OAAO,OAAO,UAAU,IAAI,MAAM,SAAS,CAAC;AAE/E,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,UAAM,UAAU,MAAM,OAAO,OAAO,UAAU,IAAI,MAAM,SAAS,CAAC;AAClE,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACxD,YAAQ;AAAA,MACN,WAAS;AACP,eAAO,oBAAoB,SAAS,OAAO;AAC3C,gBAAQ,KAAK;AAAA,MACf;AAAA,MACA,SAAO;AACL,eAAO,oBAAoB,SAAS,OAAO;AAC3C,eAAO,GAAG;AAAA,MACZ;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HttpProbeResult, StoryboardStep, TrustedMatchContextRouterRunnerOptions } from './types.mjs';
|
|
2
|
+
export interface TrustedMatchContextReplayResult {
|
|
3
|
+
httpResult: HttpProbeResult;
|
|
4
|
+
request: Record<string, unknown>;
|
|
5
|
+
vectorSource?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function replayTrustedMatchContextVector(step: StoryboardStep, options: TrustedMatchContextRouterRunnerOptions, params?: {
|
|
8
|
+
requestOverride?: Record<string, unknown>;
|
|
9
|
+
adcpVersion?: string;
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
}): Promise<TrustedMatchContextReplayResult>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HttpProbeResult, StoryboardStep, TrustedMatchContextRouterRunnerOptions } from './types';
|
|
2
|
+
export interface TrustedMatchContextReplayResult {
|
|
3
|
+
httpResult: HttpProbeResult;
|
|
4
|
+
request: Record<string, unknown>;
|
|
5
|
+
vectorSource?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function replayTrustedMatchContextVector(step: StoryboardStep, options: TrustedMatchContextRouterRunnerOptions, params?: {
|
|
8
|
+
requestOverride?: Record<string, unknown>;
|
|
9
|
+
adcpVersion?: string;
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
}): Promise<TrustedMatchContextReplayResult>;
|
|
12
|
+
//# sourceMappingURL=trusted-match-context-replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trusted-match-context-replay.d.ts","sourceRoot":"","sources":["../../../../src/lib/testing/storyboard/trusted-match-context-replay.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAEd,sCAAsC,EACvC,MAAM,SAAS,CAAC;AAiBjB,MAAM,WAAW,+BAA+B;IAC9C,UAAU,EAAE,eAAe,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,sCAAsC,EAC/C,MAAM,GAAE;IACN,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;CACjB,GACL,OAAO,CAAC,+BAA+B,CAAC,CA+D1C"}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var trusted_match_context_replay_exports = {};
|
|
20
|
+
__export(trusted_match_context_replay_exports, {
|
|
21
|
+
replayTrustedMatchContextVector: () => replayTrustedMatchContextVector
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(trusted_match_context_replay_exports);
|
|
24
|
+
var import_node_http = require("node:http");
|
|
25
|
+
var import_node_fs = require("node:fs");
|
|
26
|
+
var import_node_path = require("node:path");
|
|
27
|
+
var import_compliance = require('./compliance.js');
|
|
28
|
+
const DEFAULT_VECTOR_REF = "test-vectors/trusted-match-context-merge/vectors.json";
|
|
29
|
+
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
30
|
+
const MAX_ROUTER_RESPONSE_BYTES = 1024 * 1024;
|
|
31
|
+
const MAX_PROVIDER_REQUEST_BYTES = 64 * 1024;
|
|
32
|
+
async function replayTrustedMatchContextVector(step, options, params = {}) {
|
|
33
|
+
const vectorResult = loadVector(step.vector_ref, options.vectorsRoot, params.adcpVersion);
|
|
34
|
+
const emptyRequest = params.requestOverride ?? step.sample_request ?? {};
|
|
35
|
+
if ("error" in vectorResult) {
|
|
36
|
+
return {
|
|
37
|
+
request: emptyRequest,
|
|
38
|
+
httpResult: failedProbe(options.router_url, vectorResult.error)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const request = params.requestOverride ?? vectorResult.vector.request ?? step.sample_request;
|
|
42
|
+
if (!request || typeof request !== "object" || Array.isArray(request)) {
|
|
43
|
+
return {
|
|
44
|
+
request: {},
|
|
45
|
+
vectorSource: vectorResult.path,
|
|
46
|
+
httpResult: failedProbe(
|
|
47
|
+
options.router_url,
|
|
48
|
+
"`replay_trusted_match_context_vector` requires vector.request or step.sample_request."
|
|
49
|
+
)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
let fixtureServer;
|
|
53
|
+
let cleanupRegistration = void 0;
|
|
54
|
+
let result;
|
|
55
|
+
try {
|
|
56
|
+
fixtureServer = await createProviderFixtureServer(vectorResult.vector, options.provider_server);
|
|
57
|
+
cleanupRegistration = await options.registerProviders({
|
|
58
|
+
profile: vectorResult.vector.profile,
|
|
59
|
+
providers: fixtureServer.providers,
|
|
60
|
+
request: structuredClone(request)
|
|
61
|
+
});
|
|
62
|
+
const httpResult = await postRouterContext(options, request, params.signal);
|
|
63
|
+
result = { httpResult, request, vectorSource: vectorResult.path };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
result = {
|
|
66
|
+
request,
|
|
67
|
+
vectorSource: vectorResult.path,
|
|
68
|
+
httpResult: failedProbe(options.router_url, error instanceof Error ? error.message : String(error))
|
|
69
|
+
};
|
|
70
|
+
} finally {
|
|
71
|
+
const cleanupErrors = [];
|
|
72
|
+
try {
|
|
73
|
+
if (cleanupRegistration !== void 0) {
|
|
74
|
+
if (typeof cleanupRegistration !== "function") {
|
|
75
|
+
throw new Error("registerProviders must return void or a cleanup function.");
|
|
76
|
+
}
|
|
77
|
+
await cleanupRegistration();
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
cleanupErrors.push(`registration cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
await fixtureServer?.close();
|
|
84
|
+
} catch (error) {
|
|
85
|
+
cleanupErrors.push(`provider fixture cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
86
|
+
}
|
|
87
|
+
if (cleanupErrors.length > 0) {
|
|
88
|
+
const priorError = result.httpResult.error;
|
|
89
|
+
result.httpResult.error = [...priorError ? [priorError] : [], ...cleanupErrors].join("; ");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
function loadVector(vectorRef, vectorsRoot, adcpVersion) {
|
|
95
|
+
const rawRef = (vectorRef ?? DEFAULT_VECTOR_REF).split("#", 1)[0];
|
|
96
|
+
if (!rawRef || (0, import_node_path.isAbsolute)(rawRef) || rawRef.split(/[\\/]/).includes("..")) {
|
|
97
|
+
return { error: `Invalid Trusted Match Context vector_ref: ${vectorRef ?? rawRef}` };
|
|
98
|
+
}
|
|
99
|
+
const withoutStatic = rawRef.replace(/^static\//, "").replace(/^compliance\/source\//, "");
|
|
100
|
+
const candidates = [];
|
|
101
|
+
if (vectorsRoot) {
|
|
102
|
+
candidates.push((0, import_node_path.join)(vectorsRoot, rawRef), (0, import_node_path.join)(vectorsRoot, withoutStatic), (0, import_node_path.join)(vectorsRoot, (0, import_node_path.basename)(rawRef)));
|
|
103
|
+
}
|
|
104
|
+
const complianceDir = (0, import_compliance.getComplianceCacheDir)({ ...adcpVersion && { version: adcpVersion } });
|
|
105
|
+
candidates.push(
|
|
106
|
+
(0, import_node_path.join)(complianceDir, withoutStatic),
|
|
107
|
+
(0, import_node_path.join)(complianceDir, rawRef),
|
|
108
|
+
(0, import_node_path.join)(process.cwd(), rawRef),
|
|
109
|
+
(0, import_node_path.join)(process.cwd(), withoutStatic)
|
|
110
|
+
);
|
|
111
|
+
for (const candidate of [...new Set(candidates)]) {
|
|
112
|
+
if (!(0, import_node_fs.existsSync)(candidate)) continue;
|
|
113
|
+
try {
|
|
114
|
+
const parsed = JSON.parse((0, import_node_fs.readFileSync)(candidate, "utf8"));
|
|
115
|
+
const validationError = validateVector(parsed);
|
|
116
|
+
if (validationError) return { error: `${candidate}: ${validationError}` };
|
|
117
|
+
return { vector: parsed, path: candidate };
|
|
118
|
+
} catch (error) {
|
|
119
|
+
return { error: `Failed to read Trusted Match Context vector ${candidate}: ${String(error)}` };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { error: `Trusted Match Context vector file not found for ${rawRef}` };
|
|
123
|
+
}
|
|
124
|
+
function validateVector(value) {
|
|
125
|
+
if (!isRecord(value)) return "vector must be an object";
|
|
126
|
+
if (typeof value.profile !== "string" || value.profile.length === 0) return "profile must be a non-empty string";
|
|
127
|
+
if (!Array.isArray(value.registrations) || value.registrations.length === 0) {
|
|
128
|
+
return "registrations must be a non-empty array";
|
|
129
|
+
}
|
|
130
|
+
if (!Array.isArray(value.provider_responses) || value.provider_responses.length === 0) {
|
|
131
|
+
return "provider_responses must be a non-empty array";
|
|
132
|
+
}
|
|
133
|
+
const ids = /* @__PURE__ */ new Set();
|
|
134
|
+
for (const registration of value.registrations) {
|
|
135
|
+
if (!isRecord(registration) || typeof registration.provider_id !== "string" || !registration.provider_id) {
|
|
136
|
+
return "every registration requires a non-empty provider_id";
|
|
137
|
+
}
|
|
138
|
+
if (ids.has(registration.provider_id)) return `duplicate provider_id: ${registration.provider_id}`;
|
|
139
|
+
ids.add(registration.provider_id);
|
|
140
|
+
}
|
|
141
|
+
const responseIds = /* @__PURE__ */ new Set();
|
|
142
|
+
for (const entry of value.provider_responses) {
|
|
143
|
+
if (!isRecord(entry) || typeof entry.registration_provider_id !== "string" || !isRecord(entry.response)) {
|
|
144
|
+
return "every provider response requires registration_provider_id and an object response";
|
|
145
|
+
}
|
|
146
|
+
if (!ids.has(entry.registration_provider_id)) {
|
|
147
|
+
return `provider response has no matching registration: ${entry.registration_provider_id}`;
|
|
148
|
+
}
|
|
149
|
+
if (responseIds.has(entry.registration_provider_id)) {
|
|
150
|
+
return `duplicate provider response: ${entry.registration_provider_id}`;
|
|
151
|
+
}
|
|
152
|
+
responseIds.add(entry.registration_provider_id);
|
|
153
|
+
}
|
|
154
|
+
for (const providerId of ids) {
|
|
155
|
+
if (!responseIds.has(providerId)) return `registration has no provider response: ${providerId}`;
|
|
156
|
+
}
|
|
157
|
+
if ("request" in value && !isRecord(value.request)) return "request must be an object when present";
|
|
158
|
+
return void 0;
|
|
159
|
+
}
|
|
160
|
+
async function createProviderFixtureServer(vector, config) {
|
|
161
|
+
const host = config?.host ?? "127.0.0.1";
|
|
162
|
+
const port = config?.port ?? 0;
|
|
163
|
+
const mode = config?.mode ?? "loopback_mock";
|
|
164
|
+
if (mode === "proxy_url" && !config?.public_url) {
|
|
165
|
+
throw new Error("trusted_match_context_router_runner.provider_server.public_url is required in proxy_url mode.");
|
|
166
|
+
}
|
|
167
|
+
if (config?.public_url) assertHttpUrl(config.public_url, "provider_server.public_url");
|
|
168
|
+
const responses = new Map(
|
|
169
|
+
vector.provider_responses.map((entry) => [entry.registration_provider_id, entry.response])
|
|
170
|
+
);
|
|
171
|
+
const server = (0, import_node_http.createServer)((req, res) => {
|
|
172
|
+
void serveProviderFixture(req, res, responses).catch((error) => {
|
|
173
|
+
if (res.headersSent) {
|
|
174
|
+
res.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
175
|
+
} else {
|
|
176
|
+
respondJson(res, 500, { error: "fixture_server_error" });
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
await listen(server, host, port);
|
|
181
|
+
const address = server.address();
|
|
182
|
+
if (!address || typeof address === "string") {
|
|
183
|
+
await closeServer(server);
|
|
184
|
+
throw new Error("Provider fixture server did not expose a TCP address.");
|
|
185
|
+
}
|
|
186
|
+
const localBase = `http://${formatHost(host)}:${address.port}`;
|
|
187
|
+
const advertisedBase = (mode === "proxy_url" ? config.public_url : localBase).replace(/\/$/, "");
|
|
188
|
+
const providers = vector.registrations.map(({ provider_id }) => ({
|
|
189
|
+
provider_id,
|
|
190
|
+
context_url: `${advertisedBase}/providers/${encodeURIComponent(provider_id)}/context`
|
|
191
|
+
}));
|
|
192
|
+
return { providers, close: () => closeServer(server) };
|
|
193
|
+
}
|
|
194
|
+
async function serveProviderFixture(req, res, responses) {
|
|
195
|
+
const pathname = new URL(req.url ?? "/", "http://fixture.invalid").pathname;
|
|
196
|
+
const match = pathname.match(/^\/providers\/([^/]+)\/context$/);
|
|
197
|
+
if (req.method !== "POST" || !match) {
|
|
198
|
+
respondJson(res, req.method === "POST" ? 404 : 405, { error: "not_found" });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
await consumeBody(req, MAX_PROVIDER_REQUEST_BYTES);
|
|
203
|
+
} catch {
|
|
204
|
+
respondJson(res, 413, { error: "request_too_large" });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const providerId = decodeURIComponent(match[1]);
|
|
208
|
+
const response = responses.get(providerId);
|
|
209
|
+
if (!response) {
|
|
210
|
+
respondJson(res, 404, { error: "provider_not_found" });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
respondJson(res, 200, response);
|
|
214
|
+
}
|
|
215
|
+
async function postRouterContext(options, request, parentSignal) {
|
|
216
|
+
const routerUrl = `${options.router_url.replace(/\/$/, "")}/context`;
|
|
217
|
+
const parsed = new URL(routerUrl);
|
|
218
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
219
|
+
throw new Error("trusted_match_context_router_runner.router_url must use http or https.");
|
|
220
|
+
}
|
|
221
|
+
const controller = new AbortController();
|
|
222
|
+
const abort = () => controller.abort(parentSignal?.reason);
|
|
223
|
+
if (parentSignal?.aborted) abort();
|
|
224
|
+
parentSignal?.addEventListener("abort", abort, { once: true });
|
|
225
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
226
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
227
|
+
throw new Error("trusted_match_context_router_runner.timeoutMs must be a positive finite number.");
|
|
228
|
+
}
|
|
229
|
+
const timer = setTimeout(
|
|
230
|
+
() => controller.abort(new Error(`Context router replay timed out after ${timeoutMs}ms`)),
|
|
231
|
+
timeoutMs
|
|
232
|
+
);
|
|
233
|
+
try {
|
|
234
|
+
const response = await (options.fetchImpl ?? fetch)(routerUrl, {
|
|
235
|
+
method: "POST",
|
|
236
|
+
headers: { "content-type": "application/json", ...options.headers ?? {} },
|
|
237
|
+
body: JSON.stringify(request),
|
|
238
|
+
signal: controller.signal
|
|
239
|
+
});
|
|
240
|
+
const body = await readResponseBody(response, MAX_ROUTER_RESPONSE_BYTES);
|
|
241
|
+
return {
|
|
242
|
+
url: routerUrl,
|
|
243
|
+
status: response.status,
|
|
244
|
+
headers: responseHeaders(response.headers),
|
|
245
|
+
body,
|
|
246
|
+
...!response.ok && { error: `Context router returned HTTP ${response.status}.` }
|
|
247
|
+
};
|
|
248
|
+
} finally {
|
|
249
|
+
clearTimeout(timer);
|
|
250
|
+
parentSignal?.removeEventListener("abort", abort);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function assertHttpUrl(value, field) {
|
|
254
|
+
const parsed = new URL(value);
|
|
255
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
256
|
+
throw new Error(`trusted_match_context_router_runner.${field} must use http or https.`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async function readResponseBody(response, maxBytes) {
|
|
260
|
+
if (!response.body) return null;
|
|
261
|
+
const reader = response.body.getReader();
|
|
262
|
+
const chunks = [];
|
|
263
|
+
let size = 0;
|
|
264
|
+
while (true) {
|
|
265
|
+
const { value, done } = await reader.read();
|
|
266
|
+
if (done) break;
|
|
267
|
+
if (!value) continue;
|
|
268
|
+
size += value.byteLength;
|
|
269
|
+
if (size > maxBytes) {
|
|
270
|
+
await reader.cancel();
|
|
271
|
+
throw new Error(`Context router response exceeded ${maxBytes} bytes.`);
|
|
272
|
+
}
|
|
273
|
+
chunks.push(value);
|
|
274
|
+
}
|
|
275
|
+
const bytes = new Uint8Array(size);
|
|
276
|
+
let offset = 0;
|
|
277
|
+
for (const chunk of chunks) {
|
|
278
|
+
bytes.set(chunk, offset);
|
|
279
|
+
offset += chunk.byteLength;
|
|
280
|
+
}
|
|
281
|
+
const text = new TextDecoder().decode(bytes);
|
|
282
|
+
if (!text) return null;
|
|
283
|
+
try {
|
|
284
|
+
return JSON.parse(text);
|
|
285
|
+
} catch {
|
|
286
|
+
return text;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function listen(server, host, port) {
|
|
290
|
+
return new Promise((resolve, reject) => {
|
|
291
|
+
const onError = (error) => reject(error);
|
|
292
|
+
server.once("error", onError);
|
|
293
|
+
server.listen(port, host, () => {
|
|
294
|
+
server.off("error", onError);
|
|
295
|
+
resolve();
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
function closeServer(server) {
|
|
300
|
+
return new Promise((resolve, reject) => {
|
|
301
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
function consumeBody(req, maxBytes) {
|
|
305
|
+
return new Promise((resolve, reject) => {
|
|
306
|
+
let size = 0;
|
|
307
|
+
req.on("data", (chunk) => {
|
|
308
|
+
size += Buffer.byteLength(chunk);
|
|
309
|
+
if (size > maxBytes) reject(new Error("request too large"));
|
|
310
|
+
});
|
|
311
|
+
req.on("end", resolve);
|
|
312
|
+
req.on("error", reject);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
function respondJson(res, status, body) {
|
|
316
|
+
const encoded = JSON.stringify(body);
|
|
317
|
+
res.writeHead(status, { "content-type": "application/json", "content-length": Buffer.byteLength(encoded) });
|
|
318
|
+
res.end(encoded);
|
|
319
|
+
}
|
|
320
|
+
function formatHost(host) {
|
|
321
|
+
return host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
322
|
+
}
|
|
323
|
+
function failedProbe(url, error) {
|
|
324
|
+
return { url, status: 0, headers: {}, body: null, error };
|
|
325
|
+
}
|
|
326
|
+
function responseHeaders(headers) {
|
|
327
|
+
const result = {};
|
|
328
|
+
headers.forEach((value, key) => {
|
|
329
|
+
result[key] = value;
|
|
330
|
+
});
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
333
|
+
function isRecord(value) {
|
|
334
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
335
|
+
}
|
|
336
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
337
|
+
0 && (module.exports = {
|
|
338
|
+
replayTrustedMatchContextVector
|
|
339
|
+
});
|
|
340
|
+
//# sourceMappingURL=trusted-match-context-replay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/testing/storyboard/trusted-match-context-replay.ts"],"sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { basename, isAbsolute, join } from 'node:path';\nimport { getComplianceCacheDir } from './compliance';\nimport type {\n HttpProbeResult,\n StoryboardStep,\n TrustedMatchContextProviderEndpoint,\n TrustedMatchContextRouterRunnerOptions,\n} from './types';\n\nconst DEFAULT_VECTOR_REF = 'test-vectors/trusted-match-context-merge/vectors.json';\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst MAX_ROUTER_RESPONSE_BYTES = 1024 * 1024;\nconst MAX_PROVIDER_REQUEST_BYTES = 64 * 1024;\n\ninterface TrustedMatchContextVector {\n profile: string;\n registrations: Array<{ provider_id: string }>;\n provider_responses: Array<{\n registration_provider_id: string;\n response: Record<string, unknown>;\n }>;\n request?: Record<string, unknown>;\n}\n\nexport interface TrustedMatchContextReplayResult {\n httpResult: HttpProbeResult;\n request: Record<string, unknown>;\n vectorSource?: string;\n}\n\nexport async function replayTrustedMatchContextVector(\n step: StoryboardStep,\n options: TrustedMatchContextRouterRunnerOptions,\n params: {\n requestOverride?: Record<string, unknown>;\n adcpVersion?: string;\n signal?: AbortSignal;\n } = {}\n): Promise<TrustedMatchContextReplayResult> {\n const vectorResult = loadVector(step.vector_ref, options.vectorsRoot, params.adcpVersion);\n const emptyRequest = params.requestOverride ?? step.sample_request ?? {};\n if ('error' in vectorResult) {\n return {\n request: emptyRequest,\n httpResult: failedProbe(options.router_url, vectorResult.error),\n };\n }\n\n const request = params.requestOverride ?? vectorResult.vector.request ?? step.sample_request;\n if (!request || typeof request !== 'object' || Array.isArray(request)) {\n return {\n request: {},\n vectorSource: vectorResult.path,\n httpResult: failedProbe(\n options.router_url,\n '`replay_trusted_match_context_vector` requires vector.request or step.sample_request.'\n ),\n };\n }\n\n let fixtureServer: ProviderFixtureServer | undefined;\n let cleanupRegistration: void | (() => void | Promise<void>) = undefined;\n let result: TrustedMatchContextReplayResult;\n try {\n fixtureServer = await createProviderFixtureServer(vectorResult.vector, options.provider_server);\n cleanupRegistration = await options.registerProviders({\n profile: vectorResult.vector.profile,\n providers: fixtureServer.providers,\n request: structuredClone(request),\n });\n const httpResult = await postRouterContext(options, request, params.signal);\n result = { httpResult, request, vectorSource: vectorResult.path };\n } catch (error) {\n result = {\n request,\n vectorSource: vectorResult.path,\n httpResult: failedProbe(options.router_url, error instanceof Error ? error.message : String(error)),\n };\n } finally {\n const cleanupErrors: string[] = [];\n try {\n if (cleanupRegistration !== undefined) {\n if (typeof cleanupRegistration !== 'function') {\n throw new Error('registerProviders must return void or a cleanup function.');\n }\n await cleanupRegistration();\n }\n } catch (error) {\n cleanupErrors.push(`registration cleanup failed: ${error instanceof Error ? error.message : String(error)}`);\n }\n try {\n await fixtureServer?.close();\n } catch (error) {\n cleanupErrors.push(`provider fixture cleanup failed: ${error instanceof Error ? error.message : String(error)}`);\n }\n if (cleanupErrors.length > 0) {\n const priorError = result!.httpResult.error;\n result!.httpResult.error = [...(priorError ? [priorError] : []), ...cleanupErrors].join('; ');\n }\n }\n return result!;\n}\n\nfunction loadVector(\n vectorRef: string | undefined,\n vectorsRoot: string | undefined,\n adcpVersion: string | undefined\n): { vector: TrustedMatchContextVector; path: string } | { error: string } {\n const rawRef = (vectorRef ?? DEFAULT_VECTOR_REF).split('#', 1)[0]!;\n if (!rawRef || isAbsolute(rawRef) || rawRef.split(/[\\\\/]/).includes('..')) {\n return { error: `Invalid Trusted Match Context vector_ref: ${vectorRef ?? rawRef}` };\n }\n\n const withoutStatic = rawRef.replace(/^static\\//, '').replace(/^compliance\\/source\\//, '');\n const candidates: string[] = [];\n if (vectorsRoot) {\n candidates.push(join(vectorsRoot, rawRef), join(vectorsRoot, withoutStatic), join(vectorsRoot, basename(rawRef)));\n }\n const complianceDir = getComplianceCacheDir({ ...(adcpVersion && { version: adcpVersion }) });\n candidates.push(\n join(complianceDir, withoutStatic),\n join(complianceDir, rawRef),\n join(process.cwd(), rawRef),\n join(process.cwd(), withoutStatic)\n );\n\n for (const candidate of [...new Set(candidates)]) {\n if (!existsSync(candidate)) continue;\n try {\n const parsed = JSON.parse(readFileSync(candidate, 'utf8')) as unknown;\n const validationError = validateVector(parsed);\n if (validationError) return { error: `${candidate}: ${validationError}` };\n return { vector: parsed as TrustedMatchContextVector, path: candidate };\n } catch (error) {\n return { error: `Failed to read Trusted Match Context vector ${candidate}: ${String(error)}` };\n }\n }\n return { error: `Trusted Match Context vector file not found for ${rawRef}` };\n}\n\nfunction validateVector(value: unknown): string | undefined {\n if (!isRecord(value)) return 'vector must be an object';\n if (typeof value.profile !== 'string' || value.profile.length === 0) return 'profile must be a non-empty string';\n if (!Array.isArray(value.registrations) || value.registrations.length === 0) {\n return 'registrations must be a non-empty array';\n }\n if (!Array.isArray(value.provider_responses) || value.provider_responses.length === 0) {\n return 'provider_responses must be a non-empty array';\n }\n\n const ids = new Set<string>();\n for (const registration of value.registrations) {\n if (!isRecord(registration) || typeof registration.provider_id !== 'string' || !registration.provider_id) {\n return 'every registration requires a non-empty provider_id';\n }\n if (ids.has(registration.provider_id)) return `duplicate provider_id: ${registration.provider_id}`;\n ids.add(registration.provider_id);\n }\n const responseIds = new Set<string>();\n for (const entry of value.provider_responses) {\n if (!isRecord(entry) || typeof entry.registration_provider_id !== 'string' || !isRecord(entry.response)) {\n return 'every provider response requires registration_provider_id and an object response';\n }\n if (!ids.has(entry.registration_provider_id)) {\n return `provider response has no matching registration: ${entry.registration_provider_id}`;\n }\n if (responseIds.has(entry.registration_provider_id)) {\n return `duplicate provider response: ${entry.registration_provider_id}`;\n }\n responseIds.add(entry.registration_provider_id);\n }\n for (const providerId of ids) {\n if (!responseIds.has(providerId)) return `registration has no provider response: ${providerId}`;\n }\n if ('request' in value && !isRecord(value.request)) return 'request must be an object when present';\n return undefined;\n}\n\ninterface ProviderFixtureServer {\n providers: TrustedMatchContextProviderEndpoint[];\n close(): Promise<void>;\n}\n\nasync function createProviderFixtureServer(\n vector: TrustedMatchContextVector,\n config: TrustedMatchContextRouterRunnerOptions['provider_server']\n): Promise<ProviderFixtureServer> {\n const host = config?.host ?? '127.0.0.1';\n const port = config?.port ?? 0;\n const mode = config?.mode ?? 'loopback_mock';\n if (mode === 'proxy_url' && !config?.public_url) {\n throw new Error('trusted_match_context_router_runner.provider_server.public_url is required in proxy_url mode.');\n }\n if (config?.public_url) assertHttpUrl(config.public_url, 'provider_server.public_url');\n\n const responses = new Map(\n vector.provider_responses.map(entry => [entry.registration_provider_id, entry.response] as const)\n );\n const server = createServer((req, res) => {\n void serveProviderFixture(req, res, responses).catch(error => {\n if (res.headersSent) {\n res.destroy(error instanceof Error ? error : new Error(String(error)));\n } else {\n respondJson(res, 500, { error: 'fixture_server_error' });\n }\n });\n });\n await listen(server, host, port);\n const address = server.address();\n if (!address || typeof address === 'string') {\n await closeServer(server);\n throw new Error('Provider fixture server did not expose a TCP address.');\n }\n const localBase = `http://${formatHost(host)}:${address.port}`;\n const advertisedBase = (mode === 'proxy_url' ? config!.public_url! : localBase).replace(/\\/$/, '');\n const providers = vector.registrations.map(({ provider_id }) => ({\n provider_id,\n context_url: `${advertisedBase}/providers/${encodeURIComponent(provider_id)}/context`,\n }));\n return { providers, close: () => closeServer(server) };\n}\n\nasync function serveProviderFixture(\n req: IncomingMessage,\n res: ServerResponse,\n responses: Map<string, Record<string, unknown>>\n): Promise<void> {\n const pathname = new URL(req.url ?? '/', 'http://fixture.invalid').pathname;\n const match = pathname.match(/^\\/providers\\/([^/]+)\\/context$/);\n if (req.method !== 'POST' || !match) {\n respondJson(res, req.method === 'POST' ? 404 : 405, { error: 'not_found' });\n return;\n }\n try {\n await consumeBody(req, MAX_PROVIDER_REQUEST_BYTES);\n } catch {\n respondJson(res, 413, { error: 'request_too_large' });\n return;\n }\n const providerId = decodeURIComponent(match[1]!);\n const response = responses.get(providerId);\n if (!response) {\n respondJson(res, 404, { error: 'provider_not_found' });\n return;\n }\n respondJson(res, 200, response);\n}\n\nasync function postRouterContext(\n options: TrustedMatchContextRouterRunnerOptions,\n request: Record<string, unknown>,\n parentSignal?: AbortSignal\n): Promise<HttpProbeResult> {\n const routerUrl = `${options.router_url.replace(/\\/$/, '')}/context`;\n const parsed = new URL(routerUrl);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error('trusted_match_context_router_runner.router_url must use http or https.');\n }\n const controller = new AbortController();\n const abort = () => controller.abort(parentSignal?.reason);\n if (parentSignal?.aborted) abort();\n parentSignal?.addEventListener('abort', abort, { once: true });\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n throw new Error('trusted_match_context_router_runner.timeoutMs must be a positive finite number.');\n }\n const timer = setTimeout(\n () => controller.abort(new Error(`Context router replay timed out after ${timeoutMs}ms`)),\n timeoutMs\n );\n try {\n const response = await (options.fetchImpl ?? fetch)(routerUrl, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...(options.headers ?? {}) },\n body: JSON.stringify(request),\n signal: controller.signal,\n });\n const body = await readResponseBody(response, MAX_ROUTER_RESPONSE_BYTES);\n return {\n url: routerUrl,\n status: response.status,\n headers: responseHeaders(response.headers),\n body,\n ...(!response.ok && { error: `Context router returned HTTP ${response.status}.` }),\n };\n } finally {\n clearTimeout(timer);\n parentSignal?.removeEventListener('abort', abort);\n }\n}\n\nfunction assertHttpUrl(value: string, field: string): void {\n const parsed = new URL(value);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error(`trusted_match_context_router_runner.${field} must use http or https.`);\n }\n}\n\nasync function readResponseBody(response: Response, maxBytes: number): Promise<unknown> {\n if (!response.body) return null;\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n if (!value) continue;\n size += value.byteLength;\n if (size > maxBytes) {\n await reader.cancel();\n throw new Error(`Context router response exceeded ${maxBytes} bytes.`);\n }\n chunks.push(value);\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n const text = new TextDecoder().decode(bytes);\n if (!text) return null;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return text;\n }\n}\n\nfunction listen(server: Server, host: string, port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const onError = (error: Error) => reject(error);\n server.once('error', onError);\n server.listen(port, host, () => {\n server.off('error', onError);\n resolve();\n });\n });\n}\n\nfunction closeServer(server: Server): Promise<void> {\n return new Promise((resolve, reject) => {\n server.close(error => (error ? reject(error) : resolve()));\n });\n}\n\nfunction consumeBody(req: IncomingMessage, maxBytes: number): Promise<void> {\n return new Promise((resolve, reject) => {\n let size = 0;\n req.on('data', chunk => {\n size += Buffer.byteLength(chunk);\n if (size > maxBytes) reject(new Error('request too large'));\n });\n req.on('end', resolve);\n req.on('error', reject);\n });\n}\n\nfunction respondJson(res: ServerResponse, status: number, body: unknown): void {\n const encoded = JSON.stringify(body);\n res.writeHead(status, { 'content-type': 'application/json', 'content-length': Buffer.byteLength(encoded) });\n res.end(encoded);\n}\n\nfunction formatHost(host: string): string {\n return host.includes(':') && !host.startsWith('[') ? `[${host}]` : host;\n}\n\nfunction failedProbe(url: string, error: string): HttpProbeResult {\n return { url, status: 0, headers: {}, body: null, error };\n}\n\nfunction responseHeaders(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n"],"mappings":"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","names":[]}
|