@adcp/sdk 13.0.2 → 13.0.4

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 (49) hide show
  1. package/bin/adcp.js +37 -2
  2. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  3. package/dist/lib/server/decisioning/capabilities.d.mts +5 -5
  4. package/dist/lib/server/decisioning/capabilities.d.ts +5 -5
  5. package/dist/lib/server/decisioning/capabilities.js.map +1 -1
  6. package/dist/lib/server/decisioning/capabilities.mjs.map +1 -1
  7. package/dist/lib/testing/client.d.ts.map +1 -1
  8. package/dist/lib/testing/client.js +6 -2
  9. package/dist/lib/testing/client.js.map +1 -1
  10. package/dist/lib/testing/client.mjs +6 -2
  11. package/dist/lib/testing/client.mjs.map +1 -1
  12. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  13. package/dist/lib/testing/compliance/comply.js +27 -18
  14. package/dist/lib/testing/compliance/comply.js.map +1 -1
  15. package/dist/lib/testing/compliance/comply.mjs +25 -17
  16. package/dist/lib/testing/compliance/comply.mjs.map +1 -1
  17. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  18. package/dist/lib/testing/storyboard/runner.js +18 -4
  19. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  20. package/dist/lib/testing/storyboard/runner.mjs +18 -4
  21. package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
  22. package/dist/lib/testing/storyboard/types.d.mts +83 -29
  23. package/dist/lib/testing/storyboard/types.d.ts +83 -29
  24. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  25. package/dist/lib/testing/storyboard/types.js.map +1 -1
  26. package/dist/lib/testing/storyboard/types.mjs.map +1 -1
  27. package/dist/lib/testing/storyboard/validations.d.mts +3 -1
  28. package/dist/lib/testing/storyboard/validations.d.ts +3 -1
  29. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
  30. package/dist/lib/testing/storyboard/validations.js +83 -23
  31. package/dist/lib/testing/storyboard/validations.js.map +1 -1
  32. package/dist/lib/testing/storyboard/validations.mjs +83 -24
  33. package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
  34. package/dist/lib/testing/types.d.mts +11 -0
  35. package/dist/lib/testing/types.d.ts +11 -0
  36. package/dist/lib/testing/types.d.ts.map +1 -1
  37. package/dist/lib/testing/types.js.map +1 -1
  38. package/dist/lib/validation/schema-loader.d.ts.map +1 -1
  39. package/dist/lib/validation/schema-loader.js +9 -0
  40. package/dist/lib/validation/schema-loader.js.map +1 -1
  41. package/dist/lib/validation/schema-loader.mjs +8 -0
  42. package/dist/lib/validation/schema-loader.mjs.map +1 -1
  43. package/dist/lib/version.d.mts +3 -3
  44. package/dist/lib/version.d.ts +3 -3
  45. package/dist/lib/version.js +3 -3
  46. package/dist/lib/version.js.map +1 -1
  47. package/dist/lib/version.mjs +3 -3
  48. package/dist/lib/version.mjs.map +1 -1
  49. package/package.json +3 -3
@@ -40,6 +40,17 @@ export interface TestOptions {
40
40
  * `adcpVersion` (or the storyboard/compliance version when omitted).
41
41
  */
42
42
  schemaRoot?: string;
43
+ /**
44
+ * Whether strict AJV response-schema failures contribute to storyboard
45
+ * grading. Defaults to `true`, matching the hosted compliance grader.
46
+ *
47
+ * Set to `false` only for packaged-schema diagnostic migrations that need
48
+ * the historical lenient-Zod grade while inspecting
49
+ * `strict_validation_summary` and the per-validation `strict` verdicts.
50
+ * Strict validation still runs in that mode; it is informational rather
51
+ * than grading. An explicit external `schemaRoot` remains authoritative.
52
+ */
53
+ strictResponseSchemaValidation?: boolean;
43
54
  /** Custom User-Agent string sent with all outbound requests */
44
55
  userAgent?: string;
45
56
  brand?: {
@@ -40,6 +40,17 @@ export interface TestOptions {
40
40
  * `adcpVersion` (or the storyboard/compliance version when omitted).
41
41
  */
42
42
  schemaRoot?: string;
43
+ /**
44
+ * Whether strict AJV response-schema failures contribute to storyboard
45
+ * grading. Defaults to `true`, matching the hosted compliance grader.
46
+ *
47
+ * Set to `false` only for packaged-schema diagnostic migrations that need
48
+ * the historical lenient-Zod grade while inspecting
49
+ * `strict_validation_summary` and the per-validation `strict` verdicts.
50
+ * Strict validation still runs in that mode; it is informational rather
51
+ * than grading. An explicit external `schemaRoot` remains authoritative.
52
+ */
53
+ strictResponseSchemaValidation?: boolean;
43
54
  /** Custom User-Agent string sent with all outbound requests */
44
55
  userAgent?: string;
45
56
  brand?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/testing/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/testing/types.ts"],"sourcesContent":["/**\n * Types for AdCP Agent E2E Testing\n */\n\nimport type { FormatReferenceStructuredObject as FormatID } from '../types/core.generated';\nimport type { ControllerDetection } from './test-controller';\nimport type { WebhookReceiver } from './storyboard/webhook-receiver';\nimport type { AdcpVersion } from '../version';\nimport type { TransportOptions, VersionEnvelopeMode } from '../protocols';\n\n// Test scenarios that can be run\nexport type TestScenario =\n | 'health_check' // Just check if agent responds\n | 'discovery' // get_products, list_creative_formats, list_authorized_properties\n | 'create_media_buy' // Discovery + create a test media buy\n | 'full_sales_flow' // Full lifecycle: discovery -> create -> update -> delivery\n | 'reporting_flow' // Dedicated: create media buy -> get_media_buy_delivery validation\n | 'creative_sync' // Test sync_creatives flow\n | 'creative_inline' // Test inline creatives in create_media_buy\n | 'creative_reference' // Build -> sync -> reference a creative via creative_ids\n | 'pricing_models' // Test different pricing models the agent supports\n | 'creative_flow' // Creative agent: list_formats -> build -> preview\n | 'creative_lifecycle' // Creative agent: formats -> sync multiple -> list with/without snapshot -> build/preview\n | 'signals_flow' // Signals agent: get_signals -> activate\n // Edge case testing scenarios\n | 'error_handling' // Test agent returns proper error responses\n | 'validation' // Test schema validation (invalid inputs should be rejected)\n | 'pricing_edge_cases' // Test auction vs fixed pricing, min spend, bid_price requirements\n | 'temporal_validation' // Test date/time ordering and format validation\n // Behavioral analysis scenarios\n | 'behavior_analysis' // Analyze agent behavior: auth requirements, brief relevance, filtering\n // Response consistency scenarios\n | 'response_consistency' // Check for schema errors, pagination bugs, data mismatches\n // v3 Governance protocol scenarios\n | 'governance_property_lists' // Property list CRUD operations\n | 'governance_content_standards' // Content standards lifecycle\n | 'property_list_filters' // Property list filter round-trip: GARM, MFA, custom_tags, feature_requirements\n // v3 Campaign governance scenarios\n | 'campaign_governance' // Full lifecycle: sync_plans -> check -> execute -> report outcome\n | 'campaign_governance_denied' // Denied flow: over-budget, unauthorized market\n | 'campaign_governance_conditions' // Conditions flow: apply conditions -> re-check\n | 'campaign_governance_delivery' // Delivery monitoring with drift detection\n | 'seller_governance_context' // Seller persistence of governance_context\n // v3 SI (Sponsored Intelligence) protocol scenarios\n | 'si_session_lifecycle' // Full SI session: initiate -> messages -> terminate\n | 'si_availability' // Check SI offering availability\n | 'si_handoff' // ACP handoff flow: initiate -> purchase intent -> terminate with handoff_transaction\n // v3 Capability discovery\n | 'capability_discovery' // Verify get_adcp_capabilities response\n // Schema compliance\n | 'schema_compliance' // Validate v3 channel enum, pricing field names, format assets structure\n // Audience management\n | 'sync_audiences' // Test CRM audience sync flow\n // State machine compliance\n | 'media_buy_lifecycle' // Pause -> resume -> cancel state transitions\n | 'terminal_state_enforcement' // Verify agents reject updates to terminal-state media buys\n | 'package_lifecycle' // Package-level pause/resume independent of media buy status\n // Error compliance (transport error mapping spec)\n | 'error_codes' // Validate standard AdCP error codes in responses\n | 'error_structure' // Validate error JSON structure against error.json schema\n | 'error_transport' // Validate transport binding (structuredContent, text fallback)\n // Deterministic state machine scenarios (require comply_test_controller)\n | 'deterministic_creative' // Force creative status transitions via test controller\n | 'deterministic_media_buy' // Force media buy status transitions via test controller\n | 'deterministic_account' // Force account status transitions + operation gates\n | 'deterministic_session' // Force SI session timeout/termination\n | 'deterministic_delivery' // Simulate delivery data and verify reporting\n | 'deterministic_budget' // Simulate budget spend and verify financials\n | 'controller_validation' // Validate the test controller itself (error codes, edge cases)\n // Brand rights protocol scenarios\n | 'brand_identity' // Brand identity discovery (public and authorized access tiers)\n | 'brand_rights_flow' // Brand rights: get_rights -> acquire_rights lifecycle\n | 'creative_approval'; // Creative approval workflow for brand compliance\n\nexport interface TestOptions {\n // Protocol to use for testing (default: 'mcp')\n protocol?: 'mcp' | 'a2a';\n /** Optional cancellation signal for discovery and storyboard helper calls. */\n signal?: AbortSignal;\n /**\n * Runtime-only transport configuration for discovery and every storyboard\n * or compliance tool call. In particular, `fetchFn` lets hosted runners\n * enforce a request-scoped network policy without replacing global fetch.\n */\n transport?: TransportOptions;\n /**\n * AdCP protocol version the test client should speak. Storyboard runners\n * set this from the compliance cache version instead of relying on the\n * installed package default.\n */\n adcpVersion?: AdcpVersion | (string & {});\n /**\n * Optional wire-only AdCP version envelope override. Validation and schema\n * selection continue to use `adcpVersion`; request envelopes use this value.\n * Intended for hosted stable-line badges backed by prerelease caches.\n */\n wireAdcpVersion?: AdcpVersion | (string & {});\n /**\n * Version-envelope emission mode. Defaults to `auto`; 3.0 storyboards emit\n * the legacy major marker only, while 3.1 storyboards also emit the exact\n * `adcp_version` marker. Compliance discovery may negotiate `major-only`\n * for strict pre-3.1 agents.\n */\n versionEnvelope?: VersionEnvelopeMode;\n /**\n * External schema bundle root used for request/response validation during\n * storyboard and compliance runs. The root is registered against\n * `adcpVersion` (or the storyboard/compliance version when omitted).\n */\n schemaRoot?: string;\n /** Custom User-Agent string sent with all outbound requests */\n userAgent?: string;\n // Brand reference for product discovery (preferred over brand_manifest)\n brand?: { domain: string; brand_id?: string };\n // Custom brief for product discovery\n brief?: string;\n // Budget for test media buy (default: 1000)\n budget?: number;\n // Specific format IDs to test\n format_ids?: string[];\n // Test session ID for isolation\n test_session_id?: string;\n // Channels to focus on (if not specified, tests all agent supports)\n channels?: string[];\n // Specific pricing models to test\n pricing_models?: string[];\n /**\n * Authentication for agents that require it.\n *\n * - `bearer`: raw token sent as `Authorization: Bearer <token>`.\n * - `basic`: cleartext `username` and `password`, encoded internally.\n * - `oauth`: saved OAuth tokens (access_token + refresh_token). MCP only.\n * The library auto-refreshes on 401. Obtain tokens interactively via\n * `adcp --save-auth <alias> --oauth`, then pass the saved blob here for\n * non-interactive reuse.\n * - `oauth_client_credentials`: RFC 6749 §4.4 machine-to-machine flow.\n * The library exchanges the secret for a fresh access token before each\n * call (cached while valid). Supply `tokens` to seed the cache; omit to\n * exchange on first call.\n */\n auth?:\n | { type: 'bearer'; token: string }\n | { type: 'basic'; username: string; password: string }\n | {\n type: 'oauth';\n tokens: import('../types/adcp').AgentOAuthTokens;\n client?: import('../types/adcp').AgentOAuthClient;\n }\n | {\n type: 'oauth_client_credentials';\n credentials: import('../types/adcp').AgentOAuthClientCredentials;\n tokens?: import('../types/adcp').AgentOAuthTokens;\n };\n /**\n * Extra HTTP headers applied to every outbound request to the agent.\n * Forwarded into `AgentConfig.headers`, so MCP and A2A transports both\n * see them. `Authorization` and `x-adcp-auth` are reserved — auth wins.\n *\n * Typical use: tenant-routing headers (`x-adcp-tenant`, `Apx-Incoming-Host`)\n * for multi-tenant agents fronted by a reverse proxy. The CLI exposes these\n * via `-H KEY=VALUE` (repeatable) and persists them in `~/.adcp/config.json`.\n */\n headers?: Record<string, string>;\n // Brand manifest for creative testing\n brand_manifest?: {\n name: string;\n url?: string;\n tagline?: string;\n logos?: Array<{\n url: string;\n orientation?: 'square' | 'horizontal' | 'vertical' | 'stacked';\n background?: 'dark-bg' | 'light-bg' | 'transparent-bg';\n variant?: 'primary' | 'secondary' | 'icon' | 'wordmark' | 'full-lockup';\n tags?: string[];\n usage?: string;\n width?: number;\n height?: number;\n }>;\n colors?: Record<string, string>;\n tone?: {\n voice?: string;\n attributes?: string[];\n dos?: string[];\n donts?: string[];\n };\n assets?: Array<{\n asset_id: string;\n asset_type: string;\n url: string;\n width?: number;\n height?: number;\n tags?: string[];\n }>;\n };\n // For creative testing: test multiple formats programmatically\n test_all_formats?: boolean;\n // For creative testing: max formats to test when test_all_formats is true\n max_formats_to_test?: number;\n // For signals testing: specific signal types to test\n signal_types?: string[];\n // For governance testing: name for test property list\n property_list_name?: string;\n // For governance testing: specific content standards to test\n content_standards_id?: string;\n // For SI testing: specific offering ID to test\n si_offering_id?: string;\n // For SI testing: initial conversation context\n si_context?: string;\n /**\n * Shared explicit account id for test scenarios that need an account-scoped\n * request. Domain-specific account ids below take precedence when provided.\n */\n account_id?: string;\n /**\n * For media-buy testing: account ID to use with get_products,\n * create_media_buy, sync_creatives, and related media-buy flows.\n */\n media_buy_account_id?: string;\n // For audience testing: account ID to use with sync_audiences\n audience_account_id?: string;\n // When true, use sandbox mode. For implicit accounts, uses the natural key with\n // sandbox: true. For explicit accounts, discovers sandbox accounts via list_accounts.\n sandbox?: boolean;\n /**\n * When true, the runner injects `ext.adcp.disable_sandbox: true` on every\n * outgoing request, signaling the agent under test to bypass any internal\n * sandbox routing (env-var fallbacks, brand-domain heuristics, fixture\n * substitutes) and exercise its real adapter path. Distinct from `sandbox`\n * (which sets `account.sandbox: false` — a value, not a routing hint).\n *\n * Honored by adopters who explicitly read `ext.adcp.disable_sandbox`.\n * Agents that don't recognize the field ignore it (per spec, `ext` is\n * accepted-without-error). The pair (sandbox=false + disable_sandbox=true)\n * is the strongest \"production path only\" signal the runner can send;\n * `--no-sandbox` on `adcp storyboard run` sets both. Issue #841.\n */\n disable_sandbox?: boolean;\n /**\n * Fictional-entity test-kit data loaded from `test-kits/<name>.yaml`.\n * Storyboard phases may skip based on fields here (e.g. `skip_if: \"!test_kit.auth.api_key\"`).\n */\n test_kit?: {\n auth?: {\n /** API key the runner presents on API-key probes. */\n api_key?: string;\n /** HTTP Basic credential the runner presents on Basic-auth probes. */\n basic?: {\n /** Username portion of the Basic credential. */\n username?: string;\n /** Password portion of the Basic credential. */\n password?: string;\n /** Unencoded `username:password` pair. */\n credentials?: string;\n };\n /**\n * Auth-required, read-only tool the runner uses for unauth + invalid-key probes.\n * Required whenever `auth` is declared — no default is substituted. Must be one of\n * the values in `PROBE_TASK_ALLOWLIST`. Kits that miss this or pick a task outside\n * the allowlist fail at `comply()` / `runStoryboard()` entry with\n * `TestKitValidationError`.\n */\n probe_task: string;\n };\n [key: string]: unknown;\n };\n /** @internal Pre-created client from comply() — avoids per-scenario MCP reconnection */\n _client?: unknown;\n /** @internal Pre-discovered profile from comply() — skips per-scenario discovery */\n _profile?: AgentProfile;\n /**\n * @internal Server-declared AdCP version learned during capability discovery.\n * Storyboard response validation uses this for version-skew compatibility\n * without forcing the transport client to pin a schema bundle that may not\n * ship with the installed SDK.\n */\n _serverAdcpVersion?: string;\n /** @internal Test controller capabilities from comply() — set when comply_test_controller detected */\n _controllerCapabilities?: ControllerDetection;\n /** @internal Pre-created webhook receiver, used for unit-test injection. When\n * present, the runner skips creating its own listener and does NOT close\n * the receiver after the run (caller-owned). Production callers pass\n * `webhook_receiver` instead. */\n _webhookReceiver?: WebhookReceiver;\n}\n\nexport interface TestStepResult {\n step: string;\n task?: string;\n passed: boolean;\n duration_ms: number;\n details?: string;\n error?: string;\n response_preview?: string;\n // Structured data for collectObservations() — decoupled from response_preview display\n observation_data?: Record<string, unknown>;\n // For tracking what was created (for cleanup or follow-up)\n created_id?: string;\n // Deprecation or other warnings\n warnings?: string[];\n /** True when the step was skipped (including re-graded branch-set peers). */\n skipped?: boolean;\n /** Canonical skip reason when `skipped` is true; maps to `RunnerSkipReason`. */\n skip_reason?: string;\n /**\n * Selection reason when a skipped-looking step was intentionally outside\n * the caller's requested run. Summary artifacts use this to keep\n * not-selected steps out of actionable skip-cause rollups.\n */\n selection_reason?: string;\n /**\n * Names the unmet runtime requirement when `skip_reason` is\n * `'requirement_unmet'` (per adcp-client#1626). Carries the same value\n * the storyboard authored in `Storyboard.requires`. Lets skip-cause\n * aggregators sub-group not-applicable scenarios per-requirement\n * without parsing the warning text. Absent for every other skip reason.\n */\n requirement?: string;\n}\n\nexport interface AgentProfile {\n name: string;\n tools: string[];\n channels?: string[];\n pricing_models?: string[];\n format_ids?: string[];\n delivery_types?: string[];\n // For creative agents\n supported_formats?: Array<{\n format_id: FormatID;\n name?: string;\n required_assets?: string[];\n optional_assets?: string[];\n }>;\n // For signals agents\n supported_signals?: Array<{\n signal_id: string;\n name?: string;\n type?: string;\n }>;\n // v3 capabilities\n adcp_version?: 'v2' | 'v3';\n /**\n * AdCP major versions the agent declared in `get_adcp_capabilities.adcp.major_versions`.\n * Drives version-gated storyboard filtering so a v3.0 agent isn't failed against a\n * storyboard introduced in a later minor version.\n */\n adcp_major_versions?: number[];\n /**\n * Exact/release-precision versions from\n * `get_adcp_capabilities.adcp.supported_versions`.\n */\n adcp_supported_versions?: string[];\n /**\n * Seller's full AdCP build version from\n * `get_adcp_capabilities.adcp.build_version`.\n */\n adcp_build_version?: string;\n supported_protocols?: string[];\n /** Specialism claims from get_adcp_capabilities.specialisms */\n specialisms?: string[];\n supports_governance?: boolean;\n supports_si?: boolean;\n /**\n * Populated when the agent advertises `get_adcp_capabilities` but the call failed\n * or returned no data. Signals the compliance runner that the universal-only\n * result is due to a broken caps probe, not an agent that lacks v3 support.\n */\n capabilities_probe_error?: string;\n /**\n * Schema violations found during the preflight `get_adcp_capabilities`\n * call. Kept separately from `capabilities_probe_error`: an invalid\n * response is still available for best-effort storyboard selection, while\n * the runner surfaces each violation as a structured notice.\n */\n capabilities_schema_issues?: Array<{\n /** RFC 6901 pointer into the capabilities response. */\n pointer: string;\n /** Validator-authored explanation of the violation. */\n message: string;\n }>;\n /**\n * Raw `get_adcp_capabilities` response body. Used by the storyboard runner to\n * evaluate `requires_capability` predicates (e.g. `adcp.idempotency.supported`)\n * that reference fields not extracted into the normalised profile shape above.\n */\n raw_capabilities?: unknown;\n /**\n * SDK version string the agent self-reported in `get_adcp_capabilities`, e.g.\n * `\"@adcp/client@5.14.0\"`. Populated opportunistically — absent for hand-rolled\n * agents that don't emit the field. Used by the storyboard runner to suffix\n * shape-drift hints when the reported version predates the recommended helper.\n */\n library_version?: string;\n}\n\nexport interface TestResult {\n agent_url: string;\n scenario: TestScenario;\n overall_passed: boolean;\n steps?: TestStepResult[];\n summary: string;\n total_duration_ms: number;\n tested_at: string;\n // Agent profile discovered during testing\n agent_profile?: AgentProfile;\n}\n\nexport interface SuiteResult {\n agent_url: string;\n agent_profile: AgentProfile;\n /** Scenarios that were run */\n scenarios_run: TestScenario[];\n /** Scenarios skipped because the agent does not advertise the required tools */\n scenarios_skipped: TestScenario[];\n results: TestResult[];\n /**\n * True only when at least one scenario ran and none failed.\n * False for both \"all failed\" and \"no applicable scenarios found\".\n */\n overall_passed: boolean;\n passed_count: number;\n failed_count: number;\n /** Wall-clock time including capability discovery and all scenario runs */\n total_duration_ms: number;\n tested_at: string;\n}\n\n// Generic task result from executeTask\nexport interface TaskResult {\n success: boolean;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- response shape varies by tool; typed per-access in scenarios\n data?: any;\n error?: string;\n /** Structured AdCP error forwarded from the transport layer. Mirrors `TaskResultFailure.adcpError`. */\n adcp_error?: import('../core/ConversationTypes').AdcpErrorInfo;\n /**\n * Internal: which MCP extraction path produced `data`. Set by the response\n * unwrapper and the raw MCP probe so the storyboard runner can surface it\n * in its output contract. Consumers outside the runner should treat this\n * as implementation detail — it's NOT part of the public `AdCPResponse`.\n */\n _extraction_path?: 'structured_content' | 'text_fallback' | 'error' | 'none';\n}\n\n// Logger interface for library use\nexport interface Logger {\n info: (context: object, message: string) => void;\n error: (context: object, message: string) => void;\n warn: (context: object, message: string) => void;\n debug: (context: object, message: string) => void;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/testing/types.ts"],"sourcesContent":["/**\n * Types for AdCP Agent E2E Testing\n */\n\nimport type { FormatReferenceStructuredObject as FormatID } from '../types/core.generated';\nimport type { ControllerDetection } from './test-controller';\nimport type { WebhookReceiver } from './storyboard/webhook-receiver';\nimport type { AdcpVersion } from '../version';\nimport type { TransportOptions, VersionEnvelopeMode } from '../protocols';\n\n// Test scenarios that can be run\nexport type TestScenario =\n | 'health_check' // Just check if agent responds\n | 'discovery' // get_products, list_creative_formats, list_authorized_properties\n | 'create_media_buy' // Discovery + create a test media buy\n | 'full_sales_flow' // Full lifecycle: discovery -> create -> update -> delivery\n | 'reporting_flow' // Dedicated: create media buy -> get_media_buy_delivery validation\n | 'creative_sync' // Test sync_creatives flow\n | 'creative_inline' // Test inline creatives in create_media_buy\n | 'creative_reference' // Build -> sync -> reference a creative via creative_ids\n | 'pricing_models' // Test different pricing models the agent supports\n | 'creative_flow' // Creative agent: list_formats -> build -> preview\n | 'creative_lifecycle' // Creative agent: formats -> sync multiple -> list with/without snapshot -> build/preview\n | 'signals_flow' // Signals agent: get_signals -> activate\n // Edge case testing scenarios\n | 'error_handling' // Test agent returns proper error responses\n | 'validation' // Test schema validation (invalid inputs should be rejected)\n | 'pricing_edge_cases' // Test auction vs fixed pricing, min spend, bid_price requirements\n | 'temporal_validation' // Test date/time ordering and format validation\n // Behavioral analysis scenarios\n | 'behavior_analysis' // Analyze agent behavior: auth requirements, brief relevance, filtering\n // Response consistency scenarios\n | 'response_consistency' // Check for schema errors, pagination bugs, data mismatches\n // v3 Governance protocol scenarios\n | 'governance_property_lists' // Property list CRUD operations\n | 'governance_content_standards' // Content standards lifecycle\n | 'property_list_filters' // Property list filter round-trip: GARM, MFA, custom_tags, feature_requirements\n // v3 Campaign governance scenarios\n | 'campaign_governance' // Full lifecycle: sync_plans -> check -> execute -> report outcome\n | 'campaign_governance_denied' // Denied flow: over-budget, unauthorized market\n | 'campaign_governance_conditions' // Conditions flow: apply conditions -> re-check\n | 'campaign_governance_delivery' // Delivery monitoring with drift detection\n | 'seller_governance_context' // Seller persistence of governance_context\n // v3 SI (Sponsored Intelligence) protocol scenarios\n | 'si_session_lifecycle' // Full SI session: initiate -> messages -> terminate\n | 'si_availability' // Check SI offering availability\n | 'si_handoff' // ACP handoff flow: initiate -> purchase intent -> terminate with handoff_transaction\n // v3 Capability discovery\n | 'capability_discovery' // Verify get_adcp_capabilities response\n // Schema compliance\n | 'schema_compliance' // Validate v3 channel enum, pricing field names, format assets structure\n // Audience management\n | 'sync_audiences' // Test CRM audience sync flow\n // State machine compliance\n | 'media_buy_lifecycle' // Pause -> resume -> cancel state transitions\n | 'terminal_state_enforcement' // Verify agents reject updates to terminal-state media buys\n | 'package_lifecycle' // Package-level pause/resume independent of media buy status\n // Error compliance (transport error mapping spec)\n | 'error_codes' // Validate standard AdCP error codes in responses\n | 'error_structure' // Validate error JSON structure against error.json schema\n | 'error_transport' // Validate transport binding (structuredContent, text fallback)\n // Deterministic state machine scenarios (require comply_test_controller)\n | 'deterministic_creative' // Force creative status transitions via test controller\n | 'deterministic_media_buy' // Force media buy status transitions via test controller\n | 'deterministic_account' // Force account status transitions + operation gates\n | 'deterministic_session' // Force SI session timeout/termination\n | 'deterministic_delivery' // Simulate delivery data and verify reporting\n | 'deterministic_budget' // Simulate budget spend and verify financials\n | 'controller_validation' // Validate the test controller itself (error codes, edge cases)\n // Brand rights protocol scenarios\n | 'brand_identity' // Brand identity discovery (public and authorized access tiers)\n | 'brand_rights_flow' // Brand rights: get_rights -> acquire_rights lifecycle\n | 'creative_approval'; // Creative approval workflow for brand compliance\n\nexport interface TestOptions {\n // Protocol to use for testing (default: 'mcp')\n protocol?: 'mcp' | 'a2a';\n /** Optional cancellation signal for discovery and storyboard helper calls. */\n signal?: AbortSignal;\n /**\n * Runtime-only transport configuration for discovery and every storyboard\n * or compliance tool call. In particular, `fetchFn` lets hosted runners\n * enforce a request-scoped network policy without replacing global fetch.\n */\n transport?: TransportOptions;\n /**\n * AdCP protocol version the test client should speak. Storyboard runners\n * set this from the compliance cache version instead of relying on the\n * installed package default.\n */\n adcpVersion?: AdcpVersion | (string & {});\n /**\n * Optional wire-only AdCP version envelope override. Validation and schema\n * selection continue to use `adcpVersion`; request envelopes use this value.\n * Intended for hosted stable-line badges backed by prerelease caches.\n */\n wireAdcpVersion?: AdcpVersion | (string & {});\n /**\n * Version-envelope emission mode. Defaults to `auto`; 3.0 storyboards emit\n * the legacy major marker only, while 3.1 storyboards also emit the exact\n * `adcp_version` marker. Compliance discovery may negotiate `major-only`\n * for strict pre-3.1 agents.\n */\n versionEnvelope?: VersionEnvelopeMode;\n /**\n * External schema bundle root used for request/response validation during\n * storyboard and compliance runs. The root is registered against\n * `adcpVersion` (or the storyboard/compliance version when omitted).\n */\n schemaRoot?: string;\n /**\n * Whether strict AJV response-schema failures contribute to storyboard\n * grading. Defaults to `true`, matching the hosted compliance grader.\n *\n * Set to `false` only for packaged-schema diagnostic migrations that need\n * the historical lenient-Zod grade while inspecting\n * `strict_validation_summary` and the per-validation `strict` verdicts.\n * Strict validation still runs in that mode; it is informational rather\n * than grading. An explicit external `schemaRoot` remains authoritative.\n */\n strictResponseSchemaValidation?: boolean;\n /** Custom User-Agent string sent with all outbound requests */\n userAgent?: string;\n // Brand reference for product discovery (preferred over brand_manifest)\n brand?: { domain: string; brand_id?: string };\n // Custom brief for product discovery\n brief?: string;\n // Budget for test media buy (default: 1000)\n budget?: number;\n // Specific format IDs to test\n format_ids?: string[];\n // Test session ID for isolation\n test_session_id?: string;\n // Channels to focus on (if not specified, tests all agent supports)\n channels?: string[];\n // Specific pricing models to test\n pricing_models?: string[];\n /**\n * Authentication for agents that require it.\n *\n * - `bearer`: raw token sent as `Authorization: Bearer <token>`.\n * - `basic`: cleartext `username` and `password`, encoded internally.\n * - `oauth`: saved OAuth tokens (access_token + refresh_token). MCP only.\n * The library auto-refreshes on 401. Obtain tokens interactively via\n * `adcp --save-auth <alias> --oauth`, then pass the saved blob here for\n * non-interactive reuse.\n * - `oauth_client_credentials`: RFC 6749 §4.4 machine-to-machine flow.\n * The library exchanges the secret for a fresh access token before each\n * call (cached while valid). Supply `tokens` to seed the cache; omit to\n * exchange on first call.\n */\n auth?:\n | { type: 'bearer'; token: string }\n | { type: 'basic'; username: string; password: string }\n | {\n type: 'oauth';\n tokens: import('../types/adcp').AgentOAuthTokens;\n client?: import('../types/adcp').AgentOAuthClient;\n }\n | {\n type: 'oauth_client_credentials';\n credentials: import('../types/adcp').AgentOAuthClientCredentials;\n tokens?: import('../types/adcp').AgentOAuthTokens;\n };\n /**\n * Extra HTTP headers applied to every outbound request to the agent.\n * Forwarded into `AgentConfig.headers`, so MCP and A2A transports both\n * see them. `Authorization` and `x-adcp-auth` are reserved — auth wins.\n *\n * Typical use: tenant-routing headers (`x-adcp-tenant`, `Apx-Incoming-Host`)\n * for multi-tenant agents fronted by a reverse proxy. The CLI exposes these\n * via `-H KEY=VALUE` (repeatable) and persists them in `~/.adcp/config.json`.\n */\n headers?: Record<string, string>;\n // Brand manifest for creative testing\n brand_manifest?: {\n name: string;\n url?: string;\n tagline?: string;\n logos?: Array<{\n url: string;\n orientation?: 'square' | 'horizontal' | 'vertical' | 'stacked';\n background?: 'dark-bg' | 'light-bg' | 'transparent-bg';\n variant?: 'primary' | 'secondary' | 'icon' | 'wordmark' | 'full-lockup';\n tags?: string[];\n usage?: string;\n width?: number;\n height?: number;\n }>;\n colors?: Record<string, string>;\n tone?: {\n voice?: string;\n attributes?: string[];\n dos?: string[];\n donts?: string[];\n };\n assets?: Array<{\n asset_id: string;\n asset_type: string;\n url: string;\n width?: number;\n height?: number;\n tags?: string[];\n }>;\n };\n // For creative testing: test multiple formats programmatically\n test_all_formats?: boolean;\n // For creative testing: max formats to test when test_all_formats is true\n max_formats_to_test?: number;\n // For signals testing: specific signal types to test\n signal_types?: string[];\n // For governance testing: name for test property list\n property_list_name?: string;\n // For governance testing: specific content standards to test\n content_standards_id?: string;\n // For SI testing: specific offering ID to test\n si_offering_id?: string;\n // For SI testing: initial conversation context\n si_context?: string;\n /**\n * Shared explicit account id for test scenarios that need an account-scoped\n * request. Domain-specific account ids below take precedence when provided.\n */\n account_id?: string;\n /**\n * For media-buy testing: account ID to use with get_products,\n * create_media_buy, sync_creatives, and related media-buy flows.\n */\n media_buy_account_id?: string;\n // For audience testing: account ID to use with sync_audiences\n audience_account_id?: string;\n // When true, use sandbox mode. For implicit accounts, uses the natural key with\n // sandbox: true. For explicit accounts, discovers sandbox accounts via list_accounts.\n sandbox?: boolean;\n /**\n * When true, the runner injects `ext.adcp.disable_sandbox: true` on every\n * outgoing request, signaling the agent under test to bypass any internal\n * sandbox routing (env-var fallbacks, brand-domain heuristics, fixture\n * substitutes) and exercise its real adapter path. Distinct from `sandbox`\n * (which sets `account.sandbox: false` — a value, not a routing hint).\n *\n * Honored by adopters who explicitly read `ext.adcp.disable_sandbox`.\n * Agents that don't recognize the field ignore it (per spec, `ext` is\n * accepted-without-error). The pair (sandbox=false + disable_sandbox=true)\n * is the strongest \"production path only\" signal the runner can send;\n * `--no-sandbox` on `adcp storyboard run` sets both. Issue #841.\n */\n disable_sandbox?: boolean;\n /**\n * Fictional-entity test-kit data loaded from `test-kits/<name>.yaml`.\n * Storyboard phases may skip based on fields here (e.g. `skip_if: \"!test_kit.auth.api_key\"`).\n */\n test_kit?: {\n auth?: {\n /** API key the runner presents on API-key probes. */\n api_key?: string;\n /** HTTP Basic credential the runner presents on Basic-auth probes. */\n basic?: {\n /** Username portion of the Basic credential. */\n username?: string;\n /** Password portion of the Basic credential. */\n password?: string;\n /** Unencoded `username:password` pair. */\n credentials?: string;\n };\n /**\n * Auth-required, read-only tool the runner uses for unauth + invalid-key probes.\n * Required whenever `auth` is declared — no default is substituted. Must be one of\n * the values in `PROBE_TASK_ALLOWLIST`. Kits that miss this or pick a task outside\n * the allowlist fail at `comply()` / `runStoryboard()` entry with\n * `TestKitValidationError`.\n */\n probe_task: string;\n };\n [key: string]: unknown;\n };\n /** @internal Pre-created client from comply() — avoids per-scenario MCP reconnection */\n _client?: unknown;\n /** @internal Pre-discovered profile from comply() — skips per-scenario discovery */\n _profile?: AgentProfile;\n /**\n * @internal Server-declared AdCP version learned during capability discovery.\n * Storyboard response validation uses this for version-skew compatibility\n * without forcing the transport client to pin a schema bundle that may not\n * ship with the installed SDK.\n */\n _serverAdcpVersion?: string;\n /** @internal Test controller capabilities from comply() — set when comply_test_controller detected */\n _controllerCapabilities?: ControllerDetection;\n /** @internal Pre-created webhook receiver, used for unit-test injection. When\n * present, the runner skips creating its own listener and does NOT close\n * the receiver after the run (caller-owned). Production callers pass\n * `webhook_receiver` instead. */\n _webhookReceiver?: WebhookReceiver;\n}\n\nexport interface TestStepResult {\n step: string;\n task?: string;\n passed: boolean;\n duration_ms: number;\n details?: string;\n error?: string;\n response_preview?: string;\n // Structured data for collectObservations() — decoupled from response_preview display\n observation_data?: Record<string, unknown>;\n // For tracking what was created (for cleanup or follow-up)\n created_id?: string;\n // Deprecation or other warnings\n warnings?: string[];\n /** True when the step was skipped (including re-graded branch-set peers). */\n skipped?: boolean;\n /** Canonical skip reason when `skipped` is true; maps to `RunnerSkipReason`. */\n skip_reason?: string;\n /**\n * Selection reason when a skipped-looking step was intentionally outside\n * the caller's requested run. Summary artifacts use this to keep\n * not-selected steps out of actionable skip-cause rollups.\n */\n selection_reason?: string;\n /**\n * Names the unmet runtime requirement when `skip_reason` is\n * `'requirement_unmet'` (per adcp-client#1626). Carries the same value\n * the storyboard authored in `Storyboard.requires`. Lets skip-cause\n * aggregators sub-group not-applicable scenarios per-requirement\n * without parsing the warning text. Absent for every other skip reason.\n */\n requirement?: string;\n}\n\nexport interface AgentProfile {\n name: string;\n tools: string[];\n channels?: string[];\n pricing_models?: string[];\n format_ids?: string[];\n delivery_types?: string[];\n // For creative agents\n supported_formats?: Array<{\n format_id: FormatID;\n name?: string;\n required_assets?: string[];\n optional_assets?: string[];\n }>;\n // For signals agents\n supported_signals?: Array<{\n signal_id: string;\n name?: string;\n type?: string;\n }>;\n // v3 capabilities\n adcp_version?: 'v2' | 'v3';\n /**\n * AdCP major versions the agent declared in `get_adcp_capabilities.adcp.major_versions`.\n * Drives version-gated storyboard filtering so a v3.0 agent isn't failed against a\n * storyboard introduced in a later minor version.\n */\n adcp_major_versions?: number[];\n /**\n * Exact/release-precision versions from\n * `get_adcp_capabilities.adcp.supported_versions`.\n */\n adcp_supported_versions?: string[];\n /**\n * Seller's full AdCP build version from\n * `get_adcp_capabilities.adcp.build_version`.\n */\n adcp_build_version?: string;\n supported_protocols?: string[];\n /** Specialism claims from get_adcp_capabilities.specialisms */\n specialisms?: string[];\n supports_governance?: boolean;\n supports_si?: boolean;\n /**\n * Populated when the agent advertises `get_adcp_capabilities` but the call failed\n * or returned no data. Signals the compliance runner that the universal-only\n * result is due to a broken caps probe, not an agent that lacks v3 support.\n */\n capabilities_probe_error?: string;\n /**\n * Schema violations found during the preflight `get_adcp_capabilities`\n * call. Kept separately from `capabilities_probe_error`: an invalid\n * response is still available for best-effort storyboard selection, while\n * the runner surfaces each violation as a structured notice.\n */\n capabilities_schema_issues?: Array<{\n /** RFC 6901 pointer into the capabilities response. */\n pointer: string;\n /** Validator-authored explanation of the violation. */\n message: string;\n }>;\n /**\n * Raw `get_adcp_capabilities` response body. Used by the storyboard runner to\n * evaluate `requires_capability` predicates (e.g. `adcp.idempotency.supported`)\n * that reference fields not extracted into the normalised profile shape above.\n */\n raw_capabilities?: unknown;\n /**\n * SDK version string the agent self-reported in `get_adcp_capabilities`, e.g.\n * `\"@adcp/client@5.14.0\"`. Populated opportunistically — absent for hand-rolled\n * agents that don't emit the field. Used by the storyboard runner to suffix\n * shape-drift hints when the reported version predates the recommended helper.\n */\n library_version?: string;\n}\n\nexport interface TestResult {\n agent_url: string;\n scenario: TestScenario;\n overall_passed: boolean;\n steps?: TestStepResult[];\n summary: string;\n total_duration_ms: number;\n tested_at: string;\n // Agent profile discovered during testing\n agent_profile?: AgentProfile;\n}\n\nexport interface SuiteResult {\n agent_url: string;\n agent_profile: AgentProfile;\n /** Scenarios that were run */\n scenarios_run: TestScenario[];\n /** Scenarios skipped because the agent does not advertise the required tools */\n scenarios_skipped: TestScenario[];\n results: TestResult[];\n /**\n * True only when at least one scenario ran and none failed.\n * False for both \"all failed\" and \"no applicable scenarios found\".\n */\n overall_passed: boolean;\n passed_count: number;\n failed_count: number;\n /** Wall-clock time including capability discovery and all scenario runs */\n total_duration_ms: number;\n tested_at: string;\n}\n\n// Generic task result from executeTask\nexport interface TaskResult {\n success: boolean;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- response shape varies by tool; typed per-access in scenarios\n data?: any;\n error?: string;\n /** Structured AdCP error forwarded from the transport layer. Mirrors `TaskResultFailure.adcpError`. */\n adcp_error?: import('../core/ConversationTypes').AdcpErrorInfo;\n /**\n * Internal: which MCP extraction path produced `data`. Set by the response\n * unwrapper and the raw MCP probe so the storyboard runner can surface it\n * in its output contract. Consumers outside the runner should treat this\n * as implementation detail — it's NOT part of the public `AdCPResponse`.\n */\n _extraction_path?: 'structured_content' | 'text_fallback' | 'error' | 'none';\n}\n\n// Logger interface for library use\nexport interface Logger {\n info: (context: object, message: string) => void;\n error: (context: object, message: string) => void;\n warn: (context: object, message: string) => void;\n debug: (context: object, message: string) => void;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"schema-loader.d.ts","sourceRoot":"","sources":["../../../src/lib/validation/schema-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAQjD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,gBAAgB,CAAC;AAClF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,eAAe,CAAC;AAOpD,QAAA,MAAM,sBAAsB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAMrD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgCxD;AAmDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAgB/E;AAED,wBAAgB,sBAAsB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAsBzE;AAkPD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAY9E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAiBlE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAanG;AA6ND;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CAoC9B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CAwC9B;AAuCD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,MAAqB,GAAG,MAAM,EAAE,CAG1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,MAAqB,GAAG,SAAS,MAAM,EAAE,CAMxF;AAED,8DAA8D;AAC9D,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOxD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAM7D;AAkDD,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAqB,GAC7B,SAAS,gBAAgB,EAAE,CAuI7B"}
1
+ {"version":3,"file":"schema-loader.d.ts","sourceRoot":"","sources":["../../../src/lib/validation/schema-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAQjD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,gBAAgB,CAAC;AAClF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,eAAe,CAAC;AAOpD,QAAA,MAAM,sBAAsB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAMrD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgCxD;AAmDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAgB/E;AAED,wBAAgB,sBAAsB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAsBzE;AAkPD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAY9E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAiBlE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAanG;AA8OD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CAoC9B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAqB,GAC7B,gBAAgB,GAAG,SAAS,CAwC9B;AAuCD,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,MAAqB,GAAG,MAAM,EAAE,CAG1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,MAAqB,GAAG,SAAS,MAAM,EAAE,CAMxF;AAED,8DAA8D;AAC9D,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOxD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAM7D;AAkDD,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAqB,GAC7B,SAAS,gBAAgB,EAAE,CAuI7B"}
@@ -36,6 +36,7 @@ __export(schema_loader_exports, {
36
36
  getSchemaValidatorByRef: () => getSchemaValidatorByRef,
37
37
  getValidator: () => getValidator,
38
38
  hasSchemaBundle: () => hasSchemaBundle,
39
+ isExternalSchemaRootActive: () => isExternalSchemaRootActive,
39
40
  listValidatorKeys: () => listValidatorKeys,
40
41
  registerExternalSchemaRoot: () => registerExternalSchemaRoot,
41
42
  resolveBundleKey: () => resolveBundleKey,
@@ -292,6 +293,13 @@ function withExternalSchemaRoot(version, root, fn) {
292
293
  }
293
294
  return scopedExternalSchemaRoots.run(next, fn);
294
295
  }
296
+ function isExternalSchemaRootActive(version) {
297
+ const key = resolveBundleKey(version);
298
+ const scopedRoot = scopedExternalSchemaRoots.getStore()?.get(key);
299
+ if (scopedRoot && (0, import_fs.existsSync)(scopedRoot)) return true;
300
+ const registeredRoot = externalSchemaRoots.get(key);
301
+ return registeredRoot !== void 0 && (0, import_fs.existsSync)(registeredRoot);
302
+ }
295
303
  function walkJsonFiles(dir) {
296
304
  if (!(0, import_fs.existsSync)(dir)) return [];
297
305
  const out = [];
@@ -696,6 +704,7 @@ function cloneJsonValue(value) {
696
704
  getSchemaValidatorByRef,
697
705
  getValidator,
698
706
  hasSchemaBundle,
707
+ isExternalSchemaRootActive,
699
708
  listValidatorKeys,
700
709
  registerExternalSchemaRoot,
701
710
  resolveBundleKey,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/validation/schema-loader.ts"],"sourcesContent":["/**\n * JSON Schema loader for AdCP tool request/response validation.\n *\n * Loads the bundled per-tool schemas shipped with the SDK plus the\n * `core/` schemas that async response variants `$ref`, then compiles\n * AJV validators lazily by `(toolName, direction)`.\n *\n * Stage 3: state is per-AdCP-version. The same SDK instance can hold\n * compiled validators for `3.0.0`, `3.0.1`, `3.1.0-beta.1`, etc. side by\n * side; callers pass the version they're validating against. Default is\n * the SDK-pinned `ADCP_VERSION` so callers that don't care about\n * cross-version selection (most internal call sites) keep working\n * unchanged.\n */\n\nimport Ajv, { type ValidateFunction } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { readdirSync, readFileSync, existsSync } from 'fs';\nimport path from 'path';\nimport { ADCP_VERSION } from '../version';\nimport { ConfigurationError } from '../errors';\n\nexport type ResponseVariant = 'sync' | 'submitted' | 'working' | 'input-required';\nexport type Direction = 'request' | ResponseVariant;\n\ninterface LoadedSchema {\n $id?: string;\n [k: string]: unknown;\n}\n\nconst SCHEMA_FILENAME_SUFFIX: Record<Direction, string> = {\n request: 'request',\n sync: 'response',\n submitted: 'async-response-submitted',\n working: 'async-response-working',\n 'input-required': 'async-response-input-required',\n};\n\n/**\n * Map a consumer-provided version pin to the loader's bundle key.\n *\n * - Stable semver `'3.0.0'` / `'3.0.1'` → `'3.0'` (latest patch in minor)\n * - Bare minor `'3.0'` → `'3.0'` (already the bundle key)\n * - Release-precision prerelease `'3.1-beta'` / `'3.1-beta.0'` →\n * returned verbatim. {@link resolveSchemaRoot} fuzzy-resolves to the\n * highest cached prerelease directory whose own release-precision form\n * matches (e.g. `'3.1-beta'` matches `schemas/cache/3.1.0-beta.0/`).\n * Accepted because sellers advertise `supported_versions` in this\n * shape (`[\"3.1-beta\"]`), and a buyer reading that off the wire must\n * be able to pin to it.\n * - Full prerelease semver `'3.1.0-beta.1'` → `'3.1.0-beta.1'`\n * (exact-version, intentional pin)\n * - Legacy alias `'v3'` / `'v2.5'` / `'v2.6'` → returned verbatim (cache\n * historically keyed these directories by the alias name)\n *\n * Per the AdCP spec convention patches don't change wire shape, so collapsing\n * stable patches into the minor is functionally equivalent for any validator\n * consumer. Prereleases are kept exact because pinning a beta is intentional\n * and bit-fidelity matters for cross-version interop tests.\n *\n * Throws `ConfigurationError` for any input that doesn't match one of the\n * recognized shapes. Strings reach `path.join` via `resolveSchemaRoot`, and\n * pass-through of arbitrary garbage (`'../etc'`, `'3foo'`) lets a non-version\n * directory probe leak through `hasSchemaBundle`'s boolean. The throw is\n * caught by `hasSchemaBundle`'s try/catch (still returns false) and surfaces\n * with a useful field name from `resolveAdcpVersion`.\n */\nexport function resolveBundleKey(version: string): string {\n // Bare 'MAJOR.MINOR' (no patch).\n const minorOnly = version.match(/^(\\d+)\\.(\\d+)$/);\n if (minorOnly) return `${minorOnly[1]}.${minorOnly[2]}`;\n // Release-precision prerelease 'MAJOR.MINOR-PRE' (no patch). Same SemVer §9\n // prerelease constraint as the full-semver branch — `'3.1-/../etc'`-style\n // strings can't slip through. Returns verbatim; resolveSchemaRoot does the\n // fuzzy directory match.\n const releasePrecisionPre = version.match(/^(\\d+)\\.(\\d+)-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*$/);\n if (releasePrecisionPre) return version;\n // Full 'MAJOR.MINOR.PATCH' with optional prerelease. Prerelease group\n // restricted to SemVer §9 identifiers (alphanumerics + hyphen,\n // dot-separated) so `'3.0.0-/../etc'`-style strings can't slip through\n // and reach `path.join` as a directory component. The full version is\n // returned verbatim for prereleases, so this is the last line of defense\n // before that string becomes a path segment.\n const semver = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$/);\n if (semver) {\n const [, major, minor, , prerelease] = semver;\n if (prerelease !== undefined) return version;\n return `${major}.${minor}`;\n }\n // Legacy alias: 'v' followed by a major and optional minor. Restricted to\n // this exact shape so non-version garbage can't reach the filesystem.\n const legacyAlias = version.match(/^v\\d+(\\.\\d+)?$/);\n if (legacyAlias) return version;\n throw new ConfigurationError(\n `AdCP version ${JSON.stringify(version)} is not a recognized version format. ` +\n `Expected semver (e.g. '3.0.1', '3.1.0-beta.1'), bare minor ('3.0'), ` +\n `release-precision ('3.1-beta'), or legacy alias ('v3', 'v2.5').`,\n 'adcpVersion'\n );\n}\n\n/**\n * Collapse a bundle key to the release-precision string the AdCP wire schema\n * accepts for the `adcp_version` envelope field (spec PR\n * `adcontextprotocol/adcp#3493`). The wire pattern is\n * `^\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$` — release-precision (MAJOR.MINOR with\n * optional prerelease), never full MAJOR.MINOR.PATCH semver.\n *\n * - Stable bundle key `'3.0'` / `'3.1'` → returned verbatim.\n * - Prerelease bundle key `'3.1.0-beta.0'` → `'3.1-beta.0'` (PATCH segment\n * dropped; the prerelease tag is the wire-meaningful release identifier,\n * PATCH is implementation-internal).\n * - Full stable semver `'3.0.11'` → `'3.0'` (patches don't change wire\n * shape; surface them via `build_version` on capabilities instead).\n * - Legacy alias `'v3'` / `'v2.5'` — returned verbatim. The wire spec\n * predates the envelope field, so legacy-aliased clients won't emit\n * `adcp_version` anyway (gated by `bundleSupportsAdcpVersionField`).\n *\n * The normalization rule is declared in `core/version-envelope.json`:\n *\n * > SDKs that read full-semver values from bundle metadata (e.g.\n * > ComplianceIndex.published_version = \"3.1.0-beta.1\") MUST normalize to\n * > release-precision (\"3.1-beta.1\") before emitting on the wire —\n * > meta-field values are NOT valid wire values.\n *\n * **Idempotent.** Re-applying to an already-wire-shaped value is a no-op:\n * `toReleasePrecisionWire('3.1-beta.0') === '3.1-beta.0'`. Safe to call\n * defensively on values a caller read off the wire and is passing back.\n *\n * **Prerelease regex is stricter than the wire pattern by design.** The wire\n * pattern allows `[a-zA-Z0-9.-]+` (any mix of dots and hyphens), but this\n * function only accepts SemVer §9-shaped prerelease tags\n * (`[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*`) — disallowing leading dots, double\n * dots, or trailing dots. Mirrors the path-traversal hardening on\n * {@link resolveBundleKey} (`'3.0.0-/../etc'`-style strings can't reach the\n * filesystem there, and shouldn't be silently mirrored to the wire here).\n * A future reader who wants to \"fix\" this to match the wire regex\n * character-for-character should NOT — the strictness is intentional.\n *\n * Defense: rejecting unrecognized shapes here surfaces SDK-internal misuse\n * (someone calling this with raw garbage) loudly instead of silently\n * emitting a non-spec wire string.\n */\n/**\n * The exact pattern `core/version-envelope.json` applies to `adcp_version`\n * on the wire. Kept verbatim so {@link validateAdcpVersionWire} doesn't\n * drift from the spec — bump only when the spec itself bumps.\n */\nconst ADCP_VERSION_WIRE_PATTERN = /^\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$/;\n\n/**\n * Validate a string against the AdCP 3.1 `adcp_version` wire pattern.\n * Throws `ConfigurationError` with a hint that points at\n * {@link toReleasePrecisionWire} when the value would be sent on the wire\n * but doesn't satisfy `core/version-envelope.json`'s pattern.\n *\n * Use this when you're constructing a request envelope by hand (storyboard\n * fixtures, conformance harnesses, custom transports) and want a clear\n * error rather than a downstream AJV pattern-mismatch from the seller —\n * by the time the seller rejects the request, the buyer's stack frame is\n * long gone and `core/version-envelope.json/properties/adcp_version/pattern`\n * is the only clue.\n *\n * The SDK's own `buildVersionEnvelope` calls this as a postcondition after\n * normalizing the bundle key — should never throw in well-formed SDK code,\n * but if a future refactor breaks the normalization the assertion fires\n * with a message that names the helper to call.\n *\n * Returns the value with the type narrowed to `string` via assertion.\n */\nexport function validateAdcpVersionWire(value: unknown): asserts value is string {\n if (typeof value !== 'string') {\n throw new ConfigurationError(\n `adcp_version must be a string. Got ${typeof value}. ` +\n `Use toReleasePrecisionWire() to convert a bundle key or full-semver pin to a wire-shaped string.`,\n 'adcp_version'\n );\n }\n if (!ADCP_VERSION_WIRE_PATTERN.test(value)) {\n throw new ConfigurationError(\n `adcp_version ${JSON.stringify(value)} doesn't match the AdCP 3.1 wire pattern ${ADCP_VERSION_WIRE_PATTERN}. ` +\n `Full-semver bundle keys (e.g. \"3.1.0-beta.0\") are NOT valid wire values — ` +\n `call toReleasePrecisionWire() to normalize (e.g. \"3.1.0-beta.0\" → \"3.1-beta.0\").`,\n 'adcp_version'\n );\n }\n}\n\nexport function toReleasePrecisionWire(bundleKeyOrVersion: string): string {\n // Bare release-precision (MAJOR.MINOR or MAJOR.MINOR-PRE) — already wire-shaped.\n const releasePrecision = bundleKeyOrVersion.match(/^(\\d+)\\.(\\d+)(-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/);\n if (releasePrecision) {\n const [, major, minor, prerelease = ''] = releasePrecision;\n return `${major}.${minor}${prerelease}`;\n }\n // Full semver — collapse PATCH segment. Prerelease (if any) is preserved.\n const fullSemver = bundleKeyOrVersion.match(/^(\\d+)\\.(\\d+)\\.\\d+(-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/);\n if (fullSemver) {\n const [, major, minor, prerelease = ''] = fullSemver;\n return `${major}.${minor}${prerelease}`;\n }\n // Legacy alias passthrough. Callers that reach here with a legacy alias\n // shouldn't be emitting `adcp_version` (no version-envelope support), but\n // returning the input verbatim is least-surprise.\n if (/^v\\d+(\\.\\d+)?$/.test(bundleKeyOrVersion)) return bundleKeyOrVersion;\n throw new ConfigurationError(\n `Cannot normalize ${JSON.stringify(bundleKeyOrVersion)} to release-precision wire format. ` +\n `Expected a bundle key or AdCP version string.`,\n 'adcpVersion'\n );\n}\n\n/**\n * Resolve the directory that holds the bundled + core schemas for a given\n * AdCP version. Source layout (dev):\n * schemas/cache/<exact-version>/{bundled,core}\n * Built layout (dist):\n * dist/lib/schemas-data/<bundle-key>/{bundled,core}\n *\n * Stable releases use minor-name keys (`3.0/`); prereleases use full-version\n * keys (`3.1.0-beta.1/`). See {@link resolveBundleKey}.\n *\n * Falls back to the source-tree cache when dist isn't built (dev workflow\n * before `npm run build:lib`). For stable pins, the cache fallback scans\n * for the highest-patch sibling in the requested minor — `'3.0.0'` resolves\n * to `schemas/cache/3.0.1/` when only `3.0.1` is cached, matching dist's\n * collapse behavior.\n *\n * Throws when no bundle exists. Callers pinning a specific prerelease\n * surface the error; the construction-time fence in `resolveAdcpVersion`\n * catches most cross-major mistakes before this point.\n */\nfunction resolveSchemaRoot(version: string): string {\n const key = resolveBundleKey(version);\n const scopedRoot = scopedExternalSchemaRoots.getStore()?.get(key);\n if (scopedRoot && existsSync(scopedRoot)) return scopedRoot;\n\n const externalRoot = externalSchemaRoots.get(key);\n if (externalRoot && existsSync(externalRoot)) return externalRoot;\n\n const distCandidate = path.join(__dirname, '..', 'schemas-data', key);\n if (existsSync(distCandidate)) return distCandidate;\n\n // Published builds carry exact prerelease bundle directories\n // (`3.1.0-rc.1/`), while callers may pin the release-precision family\n // alias (`3.1-rc`). Resolve that alias before falling back to source cache.\n const releasePrecisionMatch = /^\\d+\\.\\d+-/.test(key);\n if (releasePrecisionMatch) {\n const distPrereleaseCandidate = findPrereleaseBundle(path.join(__dirname, '..', 'schemas-data'), key);\n if (distPrereleaseCandidate) return distPrereleaseCandidate;\n }\n\n // Source-tree fallback: cache stays exact-version-named, so map the key\n // back to the highest-patch cache directory in the same minor for stable\n // pins. Prereleases need an exact match.\n const cacheRoot = path.join(__dirname, '..', '..', '..', 'schemas', 'cache');\n const exactCandidate = path.join(cacheRoot, version);\n if (existsSync(exactCandidate)) return exactCandidate;\n\n // For minor-only or stable-patch pins, find the highest stable patch in\n // the cache that matches the resolved minor. Skip `*.previous` snapshots\n // — `sync-schemas` writes those as transient backups during replaceTree;\n // a partially-written snapshot whose patch number happens to be highest\n // would otherwise win the sort.\n const minorMatch = key.match(/^(\\d+)\\.(\\d+)$/);\n if (minorMatch && existsSync(cacheRoot)) {\n const [, major, minor] = minorMatch;\n const prefix = `${major}.${minor}.`;\n const cached = readdirSync(cacheRoot, { withFileTypes: true })\n .filter(\n e =>\n e.isDirectory() &&\n e.name.startsWith(prefix) &&\n !e.name.endsWith('.previous') &&\n /^\\d+\\.\\d+\\.\\d+$/.test(e.name)\n )\n .map(e => ({\n name: e.name,\n patch: parseInt(e.name.slice(prefix.length), 10),\n }))\n .filter(c => Number.isFinite(c.patch))\n .sort((a, b) => b.patch - a.patch);\n if (cached.length > 0) return path.join(cacheRoot, cached[0]!.name);\n }\n\n // For release-precision prerelease pins (`'3.1-beta'`, `'3.1-beta.0'`),\n // find the highest cached prerelease directory whose own release-precision\n // form starts with the requested key. A pin of `'3.1-beta'` matches any\n // directory whose `toReleasePrecisionWire` form is `'3.1-beta'` or\n // `'3.1-beta.*'`. A pin of `'3.1-beta.0'` matches `'3.1-beta.0'` or\n // `'3.1-beta.0.*'`. Sort newest-first by directory name with numeric\n // collation so rc.10 wins over rc.9.\n if (releasePrecisionMatch) {\n const cachePrereleaseCandidate = findPrereleaseBundle(cacheRoot, key);\n if (cachePrereleaseCandidate) return cachePrereleaseCandidate;\n }\n\n throw new Error(\n `AdCP schema data for version \"${version}\" not found. ` +\n `Looked for bundle key \"${key}\" in ${distCandidate}, exact path ${exactCandidate}, ` +\n `and the latest-patch fallback in ${cacheRoot}. ` +\n `Run \\`npm run sync-schemas\\` and \\`npm run build:lib\\` to populate the bundle.`\n );\n}\n\nfunction findPrereleaseBundle(root: string, key: string): string | undefined {\n if (!existsSync(root)) return undefined;\n const cached = readdirSync(root, { withFileTypes: true })\n .filter(e => e.isDirectory() && !e.name.endsWith('.previous'))\n .map(e => {\n try {\n return { name: e.name, rp: toReleasePrecisionWire(e.name) };\n } catch {\n return null;\n }\n })\n .filter((c): c is { name: string; rp: string } => c !== null)\n .filter(c => c.rp === key || c.rp.startsWith(`${key}.`))\n .sort((a, b) => compareBundleNamesDesc(a.name, b.name));\n if (cached.length === 0) return undefined;\n return path.join(root, cached[0]!.name);\n}\n\nfunction compareBundleNamesDesc(a: string, b: string): number {\n return b.localeCompare(a, undefined, { numeric: true, sensitivity: 'base' });\n}\n\ninterface LoaderState {\n ajv: Ajv;\n fileIndex: Map<string, string>;\n validators: Map<string, ValidateFunction>;\n rawSchemas: Map<string, Record<string, unknown>>;\n entityPaths: Map<string, SchemaEntityPath[]>;\n schemaIdFiles?: Map<string, string>;\n root: string;\n coreLoaded: boolean;\n version: string;\n}\n\nconst states: Map<string, LoaderState> = new Map();\nconst externalSchemaRoots: Map<string, string> = new Map();\nconst scopedExternalSchemaRoots = new AsyncLocalStorage<Map<string, string>>();\n\nfunction stateCacheKey(bundleKey: string, root: string): string {\n return `${bundleKey}\\0${root}`;\n}\n\nfunction clearStatesForBundle(bundleKey: string): void {\n for (const [stateKey, state] of states) {\n if (state.version === bundleKey) states.delete(stateKey);\n }\n}\n\nfunction hasSchemaRootShape(root: string): boolean {\n if (!existsSync(root)) return false;\n const bundledRoot = path.join(root, 'bundled');\n const files = existsSync(bundledRoot) ? walkJsonFiles(bundledRoot) : walkJsonFiles(root);\n return files.some(file => {\n try {\n const schema = loadJson(file);\n return typeof schema.$id === 'string' || typeof schema.$schema === 'string';\n } catch {\n return false;\n }\n });\n}\n\nfunction schemaIdVersionHint(schemaId: string): string | undefined {\n return schemaId.match(/\\/schemas\\/([^/]+)\\//)?.[1];\n}\n\nfunction collectSchemaRootVersionAliases(root: string): Set<string> {\n const aliases = new Set<string>();\n for (const file of walkJsonFiles(root)) {\n let schema: LoadedSchema;\n try {\n schema = loadJson(file);\n } catch {\n continue;\n }\n if (typeof schema.$id !== 'string') continue;\n const hint = schemaIdVersionHint(schema.$id);\n if (!hint) continue;\n for (const alias of schemaRootVersionAliases(hint)) aliases.add(alias);\n }\n return aliases;\n}\n\nfunction schemaRootVersionAliases(version: string): Set<string> {\n const aliases = new Set<string>([version]);\n try {\n aliases.add(resolveBundleKey(version));\n } catch {\n // Keep the raw value only; callers that care will throw separately.\n }\n try {\n const releasePrecision = toReleasePrecisionWire(version);\n aliases.add(releasePrecision);\n const family = prereleaseFamilyAlias(releasePrecision);\n if (family) aliases.add(family);\n } catch {\n // Keep any aliases already collected.\n }\n return aliases;\n}\n\nfunction prereleaseFamilyAlias(releasePrecisionVersion: string): string | undefined {\n return releasePrecisionVersion.match(/^(\\d+\\.\\d+-[0-9A-Za-z-]+)\\.\\d+$/)?.[1];\n}\n\nfunction collectSchemaRootVersionAliasGroups(root: string): Array<{ hint: string; aliases: Set<string> }> {\n const groups: Array<{ hint: string; aliases: Set<string> }> = [];\n for (const file of walkJsonFiles(root)) {\n let schema: LoadedSchema;\n try {\n schema = loadJson(file);\n } catch {\n continue;\n }\n if (typeof schema.$id !== 'string') continue;\n const hint = schemaIdVersionHint(schema.$id);\n if (!hint) continue;\n groups.push({ hint, aliases: schemaRootVersionAliases(hint) });\n }\n return groups;\n}\n\nfunction assertSchemaRootMatchesVersion(version: string, root: string): Set<string> {\n const expectedAliases = schemaRootVersionAliases(version);\n const rootGroups = collectSchemaRootVersionAliasGroups(root);\n const rootAliases = collectSchemaRootVersionAliases(root);\n if (\n rootGroups.length > 0 &&\n rootGroups.every(group => [...group.aliases].some(alias => expectedAliases.has(alias)))\n ) {\n return new Set([...expectedAliases, ...rootAliases]);\n }\n const found =\n rootGroups.length === 0\n ? 'no AdCP schema ids'\n : rootGroups\n .map(group => `${group.hint} (${Array.from(group.aliases).sort().join(', ')})`)\n .sort()\n .join(', ');\n throw new Error(\n `External AdCP schema root for version \"${version}\" at ${root} does not match the requested version and ` +\n `must contain only schema ids matching ${Array.from(expectedAliases).sort().join(', ')}; found ${found}.`\n );\n}\n\nconst externalSchemaRootAliases: Map<string, Set<string>> = new Map();\n\n/**\n * Register a schema bundle supplied outside the installed SDK package.\n *\n * Compliance runners use this when `--compliance-dir` points at another\n * package/check-out whose storyboards and schema bundle should be used\n * together. The root must be the schema-data directory itself, e.g.\n * `.../dist/lib/schemas-data/3.0`.\n */\nexport function registerExternalSchemaRoot(version: string, root: string): void {\n const key = resolveBundleKey(version);\n if (!hasSchemaRootShape(root)) {\n throw new Error(`External AdCP schema root for version \"${version}\" not found or empty at ${root}`);\n }\n const aliases = assertSchemaRootMatchesVersion(version, root);\n externalSchemaRootAliases.set(key, aliases);\n for (const alias of aliases) {\n const previous = externalSchemaRoots.get(alias);\n externalSchemaRoots.set(alias, root);\n if (previous !== root) clearStatesForBundle(alias);\n }\n}\n\n/** Test/helper hook for unregistering an external schema bundle. */\nexport function unregisterExternalSchemaRoot(version: string): void {\n const key = resolveBundleKey(version);\n const aliases = new Set(schemaRootVersionAliases(version));\n for (const [registeredKey, registeredAliases] of externalSchemaRootAliases) {\n if (\n registeredKey === key ||\n registeredAliases.has(key) ||\n [...aliases].some(alias => registeredAliases.has(alias))\n ) {\n for (const alias of registeredAliases) aliases.add(alias);\n externalSchemaRootAliases.delete(registeredKey);\n }\n }\n for (const alias of aliases) {\n externalSchemaRoots.delete(alias);\n clearStatesForBundle(alias);\n }\n}\n\n/**\n * Run a callback with an external schema root scoped to the current async\n * execution chain. Unlike `registerExternalSchemaRoot`, this does not poison\n * process-global validation state for later hosted/compliance runs.\n */\nexport function withExternalSchemaRoot<T>(version: string, root: string | undefined, fn: () => T): T {\n if (root === undefined) return fn();\n if (!hasSchemaRootShape(root)) {\n throw new Error(`External AdCP schema root for version \"${version}\" not found or empty at ${root}`);\n }\n const aliases = assertSchemaRootMatchesVersion(version, root);\n const parent = scopedExternalSchemaRoots.getStore();\n const next = new Map(parent);\n for (const alias of aliases) {\n next.set(alias, root);\n clearStatesForBundle(alias);\n }\n return scopedExternalSchemaRoots.run(next, fn);\n}\n\nfunction walkJsonFiles(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) out.push(...walkJsonFiles(full));\n else if (entry.isFile() && entry.name.endsWith('.json')) out.push(full);\n }\n return out;\n}\n\nfunction loadJson(file: string): LoadedSchema {\n return JSON.parse(readFileSync(file, 'utf-8')) as LoadedSchema;\n}\n\n/**\n * Clear `additionalProperties: false` at the response root so envelope\n * fields (`replayed`, `context`, `ext`, and future envelope additions)\n * can ride alongside the tool-specific body — per security.mdx the\n * envelope is always extensible. Upstream bundled schemas pin\n * `additionalProperties: false` at the root on a handful of mutating\n * tools (the property-list family), which rejects envelope fields like\n * `replayed` that aren't declared in the tool-specific body.\n *\n * Scope is deliberately narrow: only the top-level object, plus each\n * direct branch of a root-level `oneOf` / `anyOf` / `allOf`. Nested\n * bodies stay strict so response-side drift detection still catches\n * typos inside `Product`, `Package`, `MediaBuy` etc. Applied only to\n * response variants; request schemas stay strict so outgoing drift\n * fails at the edge.\n */\nfunction relaxResponseRoot(schema: LoadedSchema): LoadedSchema {\n const clone = { ...schema };\n if (clone.additionalProperties === false) {\n clone.additionalProperties = true;\n }\n for (const key of ['oneOf', 'anyOf', 'allOf'] as const) {\n const branches = clone[key];\n if (Array.isArray(branches)) {\n clone[key] = branches.map(branch => {\n if (!branch || typeof branch !== 'object') return branch;\n const branchClone = { ...(branch as Record<string, unknown>) };\n if (branchClone.additionalProperties === false) {\n branchClone.additionalProperties = true;\n }\n return branchClone;\n });\n }\n }\n return clone;\n}\n\nfunction getAjvRegisteredIds(ajv: Ajv): Set<string> {\n const internals = ajv as unknown as {\n schemas?: Record<string, unknown>;\n refs?: Record<string, unknown>;\n };\n return new Set([...Object.keys(internals.schemas ?? {}), ...Object.keys(internals.refs ?? {})]);\n}\n\n/**\n * Build the (toolName, direction) → file path index by scanning the schema\n * tree once. Runs eagerly at first validator lookup.\n */\nfunction buildFileIndex(root: string): Map<string, string> {\n const index = new Map<string, string>();\n const record = (toolName: string, direction: Direction, file: string): void => {\n index.set(`${toolName}::${direction}`, file);\n };\n\n // Sync request/response live in the pre-resolved bundled/ tree.\n const bundledRoot = path.join(root, 'bundled');\n for (const file of walkJsonFiles(bundledRoot)) {\n const base = path.basename(file, '.json');\n if (base.endsWith('-request')) {\n const tool = base.slice(0, -'-request'.length).replace(/-/g, '_');\n record(tool, 'request', file);\n } else if (base.endsWith('-response')) {\n const tool = base.slice(0, -'-response'.length).replace(/-/g, '_');\n record(tool, 'sync', file);\n }\n }\n\n // Async variants AND domain schemas that ship flat (not pre-bundled) both\n // live in the per-domain directories. Walk each for sync request/response\n // files and async variant files. Skip `bundled/` (already indexed above)\n // and `core/` (pure $ref targets, no tools).\n //\n // Flat-tree domains include `governance/`, `brand/`, `account/`,\n // `content-standards/`, `property/`, `collection/` — their schemas are\n // NOT pre-resolved into `bundled/`, so a bundled-only walk would miss\n // every `check_governance` / `acquire_rights` / `creative_approval` /\n // `sync_governance` / `*_property_list` request-response pair. That gap\n // (flagged by the ad-tech-protocol reviewer on PR #831) would leave\n // protocol-wide-requirement-bearing tasks (idempotency_key pattern,\n // `format: uri` on `caller`) invisible to the strict-validation signal.\n // Register flat-tree sync pairs only when `bundled/` didn't already\n // index them, so pre-resolved schemas (with $refs already inlined) win\n // for any domain that ships both.\n for (const entry of readdirSync(root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (entry.name === 'bundled' || entry.name === 'core') continue;\n const domainDir = path.join(root, entry.name);\n for (const file of walkJsonFiles(domainDir)) {\n const base = path.basename(file, '.json');\n if (base.endsWith('-async-response-submitted')) {\n const tool = base.slice(0, -'-async-response-submitted'.length).replace(/-/g, '_');\n record(tool, 'submitted', file);\n } else if (base.endsWith('-async-response-working')) {\n const tool = base.slice(0, -'-async-response-working'.length).replace(/-/g, '_');\n record(tool, 'working', file);\n } else if (base.endsWith('-async-response-input-required')) {\n const tool = base.slice(0, -'-async-response-input-required'.length).replace(/-/g, '_');\n record(tool, 'input-required', file);\n } else if (base.endsWith('-request')) {\n const tool = base.slice(0, -'-request'.length).replace(/-/g, '_');\n if (!index.has(`${tool}::request`)) record(tool, 'request', file);\n } else if (base.endsWith('-response')) {\n const tool = base.slice(0, -'-response'.length).replace(/-/g, '_');\n if (!index.has(`${tool}::sync`)) record(tool, 'sync', file);\n }\n }\n }\n\n return index;\n}\n\nfunction ensureInit(version: string): LoaderState {\n // States are keyed by bundle key, not by raw version string, so\n // `getValidator('foo', 'request', '3.0.0')` and the same call with\n // `'3.0.1'` share state — both resolve to bundle key `'3.0'` and the\n // same compiled AJV instance.\n const key = resolveBundleKey(version);\n const root = resolveSchemaRoot(version);\n const cacheKey = stateCacheKey(key, root);\n const cached = states.get(cacheKey);\n if (cached) return cached;\n const ajv = new Ajv({\n strict: false,\n allErrors: true,\n allowUnionTypes: true,\n });\n addFormats(ajv);\n\n const state: LoaderState = {\n ajv,\n fileIndex: buildFileIndex(root),\n validators: new Map(),\n rawSchemas: new Map(),\n entityPaths: new Map(),\n root,\n coreLoaded: false,\n version: key,\n };\n states.set(cacheKey, state);\n return state;\n}\n\n/**\n * Lazily pre-register every non-tool JSON schema shipped with the SDK so\n * cross-domain `$ref`s compile. Async response variants and flat-tree\n * domain schemas `$ref` out to three classes of building-block schemas:\n *\n * - `core/` + `enums/` — shared primitives referenced by every domain.\n * - `pricing-options/`, `error-details/`, `extensions/` — stand-alone\n * fragment trees.\n * - Sibling fragments inside each domain directory — e.g.\n * `governance/audience-constraints.json` referenced by\n * `governance/sync-plans-request.json`, or `signals/*` fragments\n * referenced by `signals/activate-signal-*.json`.\n *\n * Walk every directory except `bundled/` (pre-resolved schemas with refs\n * already inlined). Response files that `buildFileIndex` registered as tools\n * are registered with `relaxResponseRoot` applied, matching `getValidator`.\n * The fileIndex check is stricter than a filename-suffix match:\n * building-block fragments like `core/pagination-response.json` end in\n * `-response.json` but aren't tools, so suffix-matching would wrongly treat\n * them as relaxable response roots.\n */\nfunction ensureCoreLoaded(s: LoaderState): void {\n if (s.coreLoaded) return;\n // Tool response files are pre-registered with the same response-root\n // relaxation `getValidator` would apply. This matters for the async response\n // union: `core/async-response-data.json` can `$ref` both async variants and\n // sync responses, so callers must not have to prewarm response validators\n // before compiling a request that references the union.\n //\n // Why this matters: bundles whose source tree doesn't include a `bundled/`\n // pre-resolved subtree (e.g. v2.5, where the spec ships flat schemas with\n // unresolved `$ref`s) classify fragments like `media-buy/package-request.json`\n // as tool `package::request` via the filename-suffix heuristic in\n // `buildFileIndex`. Skipping all tool files would leave that fragment\n // unregistered, so a later compile of `create_media_buy` fails on\n // `MissingRefError: can't resolve /schemas/media-buy/package-request.json`.\n //\n const responseToolFiles = new Map<string, Direction>();\n for (const [key, file] of s.fileIndex) {\n if (key.endsWith('::request')) continue;\n const direction = key.slice(key.indexOf('::') + 2) as Direction;\n responseToolFiles.set(file, direction);\n }\n const registeredIds = getAjvRegisteredIds(s.ajv);\n for (const entry of readdirSync(s.root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (entry.name === 'bundled') continue;\n const abs = path.join(s.root, entry.name);\n for (const file of walkJsonFiles(abs)) {\n const responseDirection = responseToolFiles.get(file);\n const schema = loadJson(file);\n const schemaToRegister = responseDirection === undefined ? schema : relaxResponseRoot(schema);\n if (typeof schemaToRegister.$id === 'string' && !registeredIds.has(schemaToRegister.$id)) {\n s.ajv.addSchema(schemaToRegister);\n registeredIds.add(schemaToRegister.$id);\n }\n }\n }\n s.coreLoaded = true;\n}\n\n/**\n * Look up the compiled AJV validator for a given tool + direction in the\n * specified AdCP version's schema bundle. Returns `undefined` when no\n * schema exists for the pair — callers can skip validation cleanly (e.g.,\n * custom tools outside the AdCP spec).\n *\n * `version` defaults to the SDK-pinned `ADCP_VERSION`. Pass the per-instance\n * `getAdcpVersion()` value when the validator should track the client/server's\n * configured pin (Stage 3+).\n */\nexport function getValidator(\n toolName: string,\n direction: Direction,\n version: string = ADCP_VERSION\n): ValidateFunction | undefined {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::${direction}`;\n const cached = s.validators.get(cacheKey);\n if (cached) return cached;\n\n const file = s.fileIndex.get(cacheKey);\n if (!file) return undefined;\n\n // Schemas that $ref into core/ and enums/ need those trees registered\n // before compile. Async response variants always do; flat-tree domain\n // schemas (anything outside `bundled/`) do too — their $refs weren't\n // pre-resolved at spec-publish time.\n const fromBundled = file.includes(`${path.sep}bundled${path.sep}`);\n if (direction === 'request' || !fromBundled) ensureCoreLoaded(s);\n\n const rawSchema = loadJson(file);\n // Bundled files inline every referenced subschema with the original\n // canonical `$id` (e.g. `core/version-envelope.json` appears nested\n // inside every bundled tool response). Bundled files carry NO\n // internal `$ref`s — the spec publishes them fully resolved, see\n // the `note: \"This is a bundled schema with all $ref resolved inline\"`\n // tag on every bundled file. Once `ensureCoreLoaded` has registered\n // any of those core schemas standalone (which it does for the flat-\n // tree governance / brand / property domains), Ajv's compile of a\n // bundled file trips the ambiguous-ref check on every nested $id.\n //\n // The fix: strip nested `$id` fields before compile on bundled\n // schemas. The root `$id` is kept (it's the validator's lookup key);\n // every other `$id` in the tree was just metadata anyway.\n const prepared = fromBundled ? stripNestedIds(rawSchema) : rawSchema;\n const schema = direction === 'request' ? prepared : relaxResponseRoot(prepared);\n const existing = typeof schema.$id === 'string' ? s.ajv.getSchema(schema.$id) : undefined;\n const compiled = existing ?? s.ajv.compile(schema);\n s.validators.set(cacheKey, compiled);\n return compiled;\n}\n\n/**\n * Compile an arbitrary schema from the cached bundle by path, e.g.\n * `core/mcp-webhook-payload.json`. Used by storyboard webhook assertions\n * whose payload schema is not tied to a tool request/response pair.\n */\nexport function getSchemaValidatorByRef(\n schemaRef: string,\n version: string = ADCP_VERSION\n): ValidateFunction | undefined {\n const s = ensureInit(version);\n const normalized = normalizeSchemaRef(schemaRef);\n if (!normalized) return undefined;\n\n const cacheKey = `schema-ref::${normalized}`;\n const cached = s.validators.get(cacheKey);\n if (cached) return cached;\n\n const file = path.join(s.root, normalized);\n if (!existsSync(file)) return undefined;\n\n // Use an isolated AJV instance for arbitrary schema refs. Tool response\n // validators deliberately relax some roots for SDK back-compat; webhook\n // payload schemas need strict raw JSON Schema behavior without polluting the\n // shared tool-validator registry with unrelaxed response schemas.\n const ajv = new Ajv({\n strict: false,\n allErrors: true,\n allowUnionTypes: true,\n });\n addFormats(ajv);\n const dependencySchemas: LoadedSchema[] = [];\n const registeredIds = new Set<string>();\n for (const schemaFile of walkJsonFiles(s.root)) {\n if (schemaFile.includes(`${path.sep}bundled${path.sep}`)) continue;\n if (schemaFile === file) continue;\n const schema = loadJson(schemaFile);\n if (typeof schema.$id === 'string' && !registeredIds.has(schema.$id)) {\n registeredIds.add(schema.$id);\n dependencySchemas.push(schema);\n }\n }\n if (dependencySchemas.length > 0) {\n ajv.addSchema(dependencySchemas);\n }\n const rawSchema = loadJson(file);\n const compiled = ajv.compile(rawSchema);\n s.validators.set(cacheKey, compiled);\n return compiled;\n}\n\nfunction normalizeSchemaRef(schemaRef: string): string | undefined {\n const trimmed = schemaRef.replace(/^\\/+/, '');\n if (trimmed.length === 0) return undefined;\n const normalized = path.normalize(trimmed);\n if (normalized.startsWith('..') || path.isAbsolute(normalized)) return undefined;\n return normalized;\n}\n\n/**\n * Strip `$id` from every subschema of a bundled response file, preserving\n * the root `$id`. Bundled files are fully inlined (no internal `$ref`s),\n * so the nested `$id`s are vestigial metadata — Ajv only cares about the\n * root `$id` for validator lookup. Without this strip, Ajv's\n * `checkAmbiguousRef` throws when an inlined nested `$id` matches one\n * already registered standalone via `ensureCoreLoaded`.\n *\n * Returns a deep-copied tree; the input is not mutated.\n */\nfunction stripNestedIds(schema: LoadedSchema): LoadedSchema {\n const root = JSON.parse(JSON.stringify(schema)) as LoadedSchema;\n const rootId = typeof root.$id === 'string' ? root.$id : undefined;\n const walk = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) walk(item);\n return;\n }\n if (!node || typeof node !== 'object') return;\n const obj = node as Record<string, unknown>;\n if (typeof obj.$id === 'string' && obj.$id !== rootId) {\n delete obj.$id;\n }\n for (const value of Object.values(obj)) walk(value);\n };\n walk(root);\n return root;\n}\n\n/** List of (toolName, direction) pairs that have schemas. Used by tests. */\nexport function listValidatorKeys(version: string = ADCP_VERSION): string[] {\n const s = ensureInit(version);\n return [...s.fileIndex.keys()].sort();\n}\n\n/**\n * `$id`s of every schema currently registered with the AdCP validator's AJV\n * instance for `version`. Used by the schema-validator to extract the\n * rejecting sub-schema's `$id` from an Ajv error's `schemaPath`: when a\n * `$ref` is followed, Ajv prefixes the schemaPath with the target schema's\n * `$id`, so the longest registered `$id` that prefixes a schemaPath is the\n * sub-schema responsible for the failure.\n *\n * The set grows as `getValidator` calls trigger `ensureCoreLoaded` and\n * compile new tool roots — callers should read it AFTER the validate call\n * they're projecting errors from.\n */\nexport function getRegisteredSchemaIds(version: string = ADCP_VERSION): readonly string[] {\n const s = ensureInit(version);\n // Ajv 8 keeps registered schemas at `ajv.schemas` (URI → SchemaEnv). Returning\n // the keys is enough for prefix matching; we don't expose the SchemaEnv values.\n const registry = (s.ajv as unknown as { schemas?: Record<string, unknown> }).schemas;\n return registry ? Object.keys(registry) : [];\n}\n\n/** Suffix used in the suffix table — exported for testing. */\nexport { SCHEMA_FILENAME_SUFFIX };\n\n/**\n * Returns true when the schema bundle for `version` is reachable from the\n * dist build or the source-tree fallback. Cheap synchronous check; safe\n * to call at construction time of clients/servers to fail fast on a pin\n * we don't have schemas for.\n */\nexport function hasSchemaBundle(version: string): boolean {\n try {\n resolveSchemaRoot(version);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Test hook: reset cached state. With no argument, clears every version's\n * loader state; with a version, clears only the bundle that version\n * resolves to (so passing `'3.0.0'` and `'3.0.1'` both clear the `'3.0'`\n * bundle).\n */\nexport function _resetValidationLoader(version?: string): void {\n if (version === undefined) {\n states.clear();\n } else {\n clearStatesForBundle(resolveBundleKey(version));\n }\n}\n\n/**\n * Returns true when `field` is **explicitly declared** as a top-level property\n * in the request schema for `toolName`, or when no schema is available\n * (fail-open). Used by the storyboard runner to decide whether to inject\n * envelope fields that aren't universally present across tools (e.g. `brand`,\n * `account`, `ext`).\n *\n * Reads the raw JSON schema file without compiling — avoids coupling to AJV\n * internals. Only inspects the top-level `properties` map; nested sub-schemas\n * are not traversed. Results are memoized in `LoaderState.rawSchemas` so\n * multi-step storyboard runs don't re-read the same file on each step.\n *\n * **Semantic note**: AdCP 3.1.0-beta.3 set `additionalProperties: true` on\n * mutating request schemas (vendor-extension friendly). Before that flip, the\n * helper used `additionalProperties: false` as the gate — \"if the schema is\n * strict, only `properties` keys are allowed.\" Now requests are universally\n * permissive at the schema level, so that gate would say `true` for any field\n * on any request — defeating the storyboard runner's intent (\"only inject\n * envelope fields the tool's schema declares it expects to see\"). The helper\n * now checks `field in properties` directly: the question we actually care\n * about is **\"does the schema declare this field at top level?\"**, not\n * \"does the schema permit this field at top level?\" (it permits everything).\n *\n * Fails open (returns `true`) when:\n * - No schema file is indexed for the tool (custom tool, schema not synced)\n * - The schema root is not reachable (schemas not built/synced yet)\n * - Any I/O / parse error during the read\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function schemaAllowsTopLevelField(toolName: string, field: string, version: string = ADCP_VERSION): boolean {\n try {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::request`;\n const file = s.fileIndex.get(cacheKey);\n if (!file) return true;\n let schema = s.rawSchemas.get(cacheKey);\n if (!schema) {\n schema = loadJson(file) as Record<string, unknown>;\n s.rawSchemas.set(cacheKey, schema);\n }\n const props = schema.properties as Record<string, unknown> | undefined;\n return props !== undefined && field in props;\n } catch {\n return true;\n }\n}\n\nexport interface SchemaEntityPath {\n /** Property path from the tool request root. `*` addresses every array item. */\n path: string[];\n /** AdCP `x-entity` annotation found on the identity-bearing leaf. */\n xEntity: string;\n}\n\n/**\n * Return every request field carrying an `x-entity` annotation. Unlike the\n * server hydration map this walks nested arrays/objects, because storyboard\n * fixture handles commonly live at `packages[*].product_id` and\n * `packages[*].pricing_option_id`.\n *\n * Missing schemas fail closed with an empty list: handle substitution must\n * never guess from a field name alone.\n */\nexport function getRequestSchemaEntityPaths(\n toolName: string,\n version: string = ADCP_VERSION\n): readonly SchemaEntityPath[] {\n try {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::request`;\n const cached = s.entityPaths.get(cacheKey);\n if (cached) return cached;\n const file = s.fileIndex.get(cacheKey);\n if (!file) return [];\n\n const root = loadJson(file) as Record<string, unknown>;\n const found = new Map<string, SchemaEntityPath>();\n const stack = new Set<string>();\n\n const resolvePointer = (document: unknown, fragment: string): unknown => {\n if (!fragment || fragment === '#') return document;\n if (!fragment.startsWith('#/')) return undefined;\n let current = document;\n for (const encoded of fragment.slice(2).split('/')) {\n if (!current || typeof current !== 'object') return undefined;\n const key = encoded.replace(/~1/g, '/').replace(/~0/g, '~');\n current = (current as Record<string, unknown>)[key];\n }\n return current;\n };\n\n const resolveRef = (\n ref: string,\n currentFile: string,\n currentDocument: Record<string, unknown>\n ): { node: unknown; file: string; document: Record<string, unknown>; key: string } | undefined => {\n const hash = ref.indexOf('#');\n const refPath = hash >= 0 ? ref.slice(0, hash) : ref;\n const fragment = hash >= 0 ? ref.slice(hash) : '';\n if (!refPath) {\n return {\n node: resolvePointer(currentDocument, fragment),\n file: currentFile,\n document: currentDocument,\n key: `${currentFile}${fragment}`,\n };\n }\n\n const schemaRelative = refPath.match(/\\/schemas\\/[^/]+\\/(.+)$/)?.[1];\n const candidates = [\n schemaRelative ? path.join(s.root, schemaRelative) : undefined,\n path.resolve(path.dirname(currentFile), refPath),\n ].filter((candidate): candidate is string => candidate !== undefined);\n let targetFile = candidates.find(candidate => existsSync(candidate));\n // Standard AdCP refs encode their schema-root-relative file path, so\n // they resolve without parsing every JSON file in the bundle. Build the\n // expensive $id index only for an unusual ref that cannot be resolved\n // by path.\n if (!targetFile) {\n if (!s.schemaIdFiles) {\n const idToFile = new Map<string, string>();\n for (const schemaFile of walkJsonFiles(s.root)) {\n try {\n const schema = loadJson(schemaFile);\n if (typeof schema.$id === 'string') idToFile.set(schema.$id, schemaFile);\n } catch {\n // A malformed unrelated schema is not a usable ref target.\n }\n }\n s.schemaIdFiles = idToFile;\n }\n targetFile = s.schemaIdFiles.get(refPath);\n }\n if (!targetFile) return undefined;\n const document = loadJson(targetFile) as Record<string, unknown>;\n return {\n node: resolvePointer(document, fragment),\n file: targetFile,\n document,\n key: `${targetFile}${fragment}`,\n };\n };\n\n const walk = (\n node: unknown,\n propertyPath: string[],\n currentFile: string,\n currentDocument: Record<string, unknown>,\n depth: number\n ): void => {\n if (!node || typeof node !== 'object' || depth > 48) return;\n const obj = node as Record<string, unknown>;\n if (typeof obj['x-entity'] === 'string' && propertyPath.length > 0) {\n const entityPath = { path: [...propertyPath], xEntity: obj['x-entity'] as string };\n found.set(`${entityPath.path.join('.')}\\0${entityPath.xEntity}`, entityPath);\n }\n\n if (typeof obj.$ref === 'string') {\n const target = resolveRef(obj.$ref, currentFile, currentDocument);\n if (target && target.node !== undefined) {\n const guard = `${target.key}\\0${propertyPath.join('.')}`;\n if (!stack.has(guard)) {\n stack.add(guard);\n walk(target.node, propertyPath, target.file, target.document, depth + 1);\n stack.delete(guard);\n }\n }\n }\n\n const properties = obj.properties;\n if (properties && typeof properties === 'object' && !Array.isArray(properties)) {\n for (const [key, child] of Object.entries(properties as Record<string, unknown>)) {\n walk(child, [...propertyPath, key], currentFile, currentDocument, depth + 1);\n }\n }\n if (obj.items !== undefined) {\n walk(obj.items, [...propertyPath, '*'], currentFile, currentDocument, depth + 1);\n }\n for (const keyword of ['allOf', 'anyOf', 'oneOf'] as const) {\n const branches = obj[keyword];\n if (Array.isArray(branches)) {\n for (const branch of branches) walk(branch, propertyPath, currentFile, currentDocument, depth + 1);\n }\n }\n for (const keyword of ['if', 'then', 'else', 'not'] as const) {\n if (obj[keyword] !== undefined) {\n walk(obj[keyword], propertyPath, currentFile, currentDocument, depth + 1);\n }\n }\n };\n\n walk(root, [], file, root, 0);\n const result = [...found.values()].sort((a, b) => {\n const byPath = a.path.join('.').localeCompare(b.path.join('.'));\n return byPath || a.xEntity.localeCompare(b.xEntity);\n });\n s.entityPaths.set(cacheKey, result);\n return result;\n } catch {\n return [];\n }\n}\n\n/**\n * Resolve a JSON Schema `default` value by walking a dot-separated property\n * path through a schema's nested `properties` maps.\n *\n * This intentionally does not instantiate AJV's `useDefaults` mutation mode.\n * Callers decide when a schema default is semantically meaningful for their\n * runtime object; this helper only reports what the bundled schema declares.\n *\n * Fails closed (`undefined`) when the schema is unavailable, the path is not a\n * concrete properties path, or the target schema node has no `default`.\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function getSchemaDefaultByPath(schemaRef: string, dottedPath: string, version: string = ADCP_VERSION): unknown {\n try {\n const s = ensureInit(version);\n const normalized = normalizeSchemaRef(schemaRef);\n if (!normalized) return undefined;\n\n const cacheKey = `schema-ref::${normalized}`;\n const file = path.join(s.root, normalized);\n if (!existsSync(file)) return undefined;\n\n let schema = s.rawSchemas.get(cacheKey);\n if (!schema) {\n schema = loadJson(file) as Record<string, unknown>;\n s.rawSchemas.set(cacheKey, schema);\n }\n\n const node = resolveSchemaPropertyPath(schema, dottedPath);\n if (!node || !Object.prototype.hasOwnProperty.call(node, 'default')) return undefined;\n return cloneJsonValue((node as { default: unknown }).default);\n } catch {\n return undefined;\n }\n}\n\nfunction resolveSchemaPropertyPath(\n schema: Record<string, unknown>,\n dottedPath: string\n): Record<string, unknown> | undefined {\n let current: unknown = schema;\n for (const key of dottedPath.split('.')) {\n if (!current || typeof current !== 'object') return undefined;\n const props = (current as Record<string, unknown>).properties;\n if (!props || typeof props !== 'object') return undefined;\n if (!Object.prototype.hasOwnProperty.call(props, key)) return undefined;\n current = (props as Record<string, unknown>)[key];\n }\n return current && typeof current === 'object' ? (current as Record<string, unknown>) : undefined;\n}\n\nfunction cloneJsonValue(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value;\n return JSON.parse(JSON.stringify(value)) as unknown;\n}\n"],"mappings":"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","names":["path","Ajv","addFormats"]}
1
+ {"version":3,"sources":["../../../src/lib/validation/schema-loader.ts"],"sourcesContent":["/**\n * JSON Schema loader for AdCP tool request/response validation.\n *\n * Loads the bundled per-tool schemas shipped with the SDK plus the\n * `core/` schemas that async response variants `$ref`, then compiles\n * AJV validators lazily by `(toolName, direction)`.\n *\n * Stage 3: state is per-AdCP-version. The same SDK instance can hold\n * compiled validators for `3.0.0`, `3.0.1`, `3.1.0-beta.1`, etc. side by\n * side; callers pass the version they're validating against. Default is\n * the SDK-pinned `ADCP_VERSION` so callers that don't care about\n * cross-version selection (most internal call sites) keep working\n * unchanged.\n */\n\nimport Ajv, { type ValidateFunction } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { readdirSync, readFileSync, existsSync } from 'fs';\nimport path from 'path';\nimport { ADCP_VERSION } from '../version';\nimport { ConfigurationError } from '../errors';\n\nexport type ResponseVariant = 'sync' | 'submitted' | 'working' | 'input-required';\nexport type Direction = 'request' | ResponseVariant;\n\ninterface LoadedSchema {\n $id?: string;\n [k: string]: unknown;\n}\n\nconst SCHEMA_FILENAME_SUFFIX: Record<Direction, string> = {\n request: 'request',\n sync: 'response',\n submitted: 'async-response-submitted',\n working: 'async-response-working',\n 'input-required': 'async-response-input-required',\n};\n\n/**\n * Map a consumer-provided version pin to the loader's bundle key.\n *\n * - Stable semver `'3.0.0'` / `'3.0.1'` → `'3.0'` (latest patch in minor)\n * - Bare minor `'3.0'` → `'3.0'` (already the bundle key)\n * - Release-precision prerelease `'3.1-beta'` / `'3.1-beta.0'` →\n * returned verbatim. {@link resolveSchemaRoot} fuzzy-resolves to the\n * highest cached prerelease directory whose own release-precision form\n * matches (e.g. `'3.1-beta'` matches `schemas/cache/3.1.0-beta.0/`).\n * Accepted because sellers advertise `supported_versions` in this\n * shape (`[\"3.1-beta\"]`), and a buyer reading that off the wire must\n * be able to pin to it.\n * - Full prerelease semver `'3.1.0-beta.1'` → `'3.1.0-beta.1'`\n * (exact-version, intentional pin)\n * - Legacy alias `'v3'` / `'v2.5'` / `'v2.6'` → returned verbatim (cache\n * historically keyed these directories by the alias name)\n *\n * Per the AdCP spec convention patches don't change wire shape, so collapsing\n * stable patches into the minor is functionally equivalent for any validator\n * consumer. Prereleases are kept exact because pinning a beta is intentional\n * and bit-fidelity matters for cross-version interop tests.\n *\n * Throws `ConfigurationError` for any input that doesn't match one of the\n * recognized shapes. Strings reach `path.join` via `resolveSchemaRoot`, and\n * pass-through of arbitrary garbage (`'../etc'`, `'3foo'`) lets a non-version\n * directory probe leak through `hasSchemaBundle`'s boolean. The throw is\n * caught by `hasSchemaBundle`'s try/catch (still returns false) and surfaces\n * with a useful field name from `resolveAdcpVersion`.\n */\nexport function resolveBundleKey(version: string): string {\n // Bare 'MAJOR.MINOR' (no patch).\n const minorOnly = version.match(/^(\\d+)\\.(\\d+)$/);\n if (minorOnly) return `${minorOnly[1]}.${minorOnly[2]}`;\n // Release-precision prerelease 'MAJOR.MINOR-PRE' (no patch). Same SemVer §9\n // prerelease constraint as the full-semver branch — `'3.1-/../etc'`-style\n // strings can't slip through. Returns verbatim; resolveSchemaRoot does the\n // fuzzy directory match.\n const releasePrecisionPre = version.match(/^(\\d+)\\.(\\d+)-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*$/);\n if (releasePrecisionPre) return version;\n // Full 'MAJOR.MINOR.PATCH' with optional prerelease. Prerelease group\n // restricted to SemVer §9 identifiers (alphanumerics + hyphen,\n // dot-separated) so `'3.0.0-/../etc'`-style strings can't slip through\n // and reach `path.join` as a directory component. The full version is\n // returned verbatim for prereleases, so this is the last line of defense\n // before that string becomes a path segment.\n const semver = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$/);\n if (semver) {\n const [, major, minor, , prerelease] = semver;\n if (prerelease !== undefined) return version;\n return `${major}.${minor}`;\n }\n // Legacy alias: 'v' followed by a major and optional minor. Restricted to\n // this exact shape so non-version garbage can't reach the filesystem.\n const legacyAlias = version.match(/^v\\d+(\\.\\d+)?$/);\n if (legacyAlias) return version;\n throw new ConfigurationError(\n `AdCP version ${JSON.stringify(version)} is not a recognized version format. ` +\n `Expected semver (e.g. '3.0.1', '3.1.0-beta.1'), bare minor ('3.0'), ` +\n `release-precision ('3.1-beta'), or legacy alias ('v3', 'v2.5').`,\n 'adcpVersion'\n );\n}\n\n/**\n * Collapse a bundle key to the release-precision string the AdCP wire schema\n * accepts for the `adcp_version` envelope field (spec PR\n * `adcontextprotocol/adcp#3493`). The wire pattern is\n * `^\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$` — release-precision (MAJOR.MINOR with\n * optional prerelease), never full MAJOR.MINOR.PATCH semver.\n *\n * - Stable bundle key `'3.0'` / `'3.1'` → returned verbatim.\n * - Prerelease bundle key `'3.1.0-beta.0'` → `'3.1-beta.0'` (PATCH segment\n * dropped; the prerelease tag is the wire-meaningful release identifier,\n * PATCH is implementation-internal).\n * - Full stable semver `'3.0.11'` → `'3.0'` (patches don't change wire\n * shape; surface them via `build_version` on capabilities instead).\n * - Legacy alias `'v3'` / `'v2.5'` — returned verbatim. The wire spec\n * predates the envelope field, so legacy-aliased clients won't emit\n * `adcp_version` anyway (gated by `bundleSupportsAdcpVersionField`).\n *\n * The normalization rule is declared in `core/version-envelope.json`:\n *\n * > SDKs that read full-semver values from bundle metadata (e.g.\n * > ComplianceIndex.published_version = \"3.1.0-beta.1\") MUST normalize to\n * > release-precision (\"3.1-beta.1\") before emitting on the wire —\n * > meta-field values are NOT valid wire values.\n *\n * **Idempotent.** Re-applying to an already-wire-shaped value is a no-op:\n * `toReleasePrecisionWire('3.1-beta.0') === '3.1-beta.0'`. Safe to call\n * defensively on values a caller read off the wire and is passing back.\n *\n * **Prerelease regex is stricter than the wire pattern by design.** The wire\n * pattern allows `[a-zA-Z0-9.-]+` (any mix of dots and hyphens), but this\n * function only accepts SemVer §9-shaped prerelease tags\n * (`[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*`) — disallowing leading dots, double\n * dots, or trailing dots. Mirrors the path-traversal hardening on\n * {@link resolveBundleKey} (`'3.0.0-/../etc'`-style strings can't reach the\n * filesystem there, and shouldn't be silently mirrored to the wire here).\n * A future reader who wants to \"fix\" this to match the wire regex\n * character-for-character should NOT — the strictness is intentional.\n *\n * Defense: rejecting unrecognized shapes here surfaces SDK-internal misuse\n * (someone calling this with raw garbage) loudly instead of silently\n * emitting a non-spec wire string.\n */\n/**\n * The exact pattern `core/version-envelope.json` applies to `adcp_version`\n * on the wire. Kept verbatim so {@link validateAdcpVersionWire} doesn't\n * drift from the spec — bump only when the spec itself bumps.\n */\nconst ADCP_VERSION_WIRE_PATTERN = /^\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$/;\n\n/**\n * Validate a string against the AdCP 3.1 `adcp_version` wire pattern.\n * Throws `ConfigurationError` with a hint that points at\n * {@link toReleasePrecisionWire} when the value would be sent on the wire\n * but doesn't satisfy `core/version-envelope.json`'s pattern.\n *\n * Use this when you're constructing a request envelope by hand (storyboard\n * fixtures, conformance harnesses, custom transports) and want a clear\n * error rather than a downstream AJV pattern-mismatch from the seller —\n * by the time the seller rejects the request, the buyer's stack frame is\n * long gone and `core/version-envelope.json/properties/adcp_version/pattern`\n * is the only clue.\n *\n * The SDK's own `buildVersionEnvelope` calls this as a postcondition after\n * normalizing the bundle key — should never throw in well-formed SDK code,\n * but if a future refactor breaks the normalization the assertion fires\n * with a message that names the helper to call.\n *\n * Returns the value with the type narrowed to `string` via assertion.\n */\nexport function validateAdcpVersionWire(value: unknown): asserts value is string {\n if (typeof value !== 'string') {\n throw new ConfigurationError(\n `adcp_version must be a string. Got ${typeof value}. ` +\n `Use toReleasePrecisionWire() to convert a bundle key or full-semver pin to a wire-shaped string.`,\n 'adcp_version'\n );\n }\n if (!ADCP_VERSION_WIRE_PATTERN.test(value)) {\n throw new ConfigurationError(\n `adcp_version ${JSON.stringify(value)} doesn't match the AdCP 3.1 wire pattern ${ADCP_VERSION_WIRE_PATTERN}. ` +\n `Full-semver bundle keys (e.g. \"3.1.0-beta.0\") are NOT valid wire values — ` +\n `call toReleasePrecisionWire() to normalize (e.g. \"3.1.0-beta.0\" → \"3.1-beta.0\").`,\n 'adcp_version'\n );\n }\n}\n\nexport function toReleasePrecisionWire(bundleKeyOrVersion: string): string {\n // Bare release-precision (MAJOR.MINOR or MAJOR.MINOR-PRE) — already wire-shaped.\n const releasePrecision = bundleKeyOrVersion.match(/^(\\d+)\\.(\\d+)(-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/);\n if (releasePrecision) {\n const [, major, minor, prerelease = ''] = releasePrecision;\n return `${major}.${minor}${prerelease}`;\n }\n // Full semver — collapse PATCH segment. Prerelease (if any) is preserved.\n const fullSemver = bundleKeyOrVersion.match(/^(\\d+)\\.(\\d+)\\.\\d+(-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/);\n if (fullSemver) {\n const [, major, minor, prerelease = ''] = fullSemver;\n return `${major}.${minor}${prerelease}`;\n }\n // Legacy alias passthrough. Callers that reach here with a legacy alias\n // shouldn't be emitting `adcp_version` (no version-envelope support), but\n // returning the input verbatim is least-surprise.\n if (/^v\\d+(\\.\\d+)?$/.test(bundleKeyOrVersion)) return bundleKeyOrVersion;\n throw new ConfigurationError(\n `Cannot normalize ${JSON.stringify(bundleKeyOrVersion)} to release-precision wire format. ` +\n `Expected a bundle key or AdCP version string.`,\n 'adcpVersion'\n );\n}\n\n/**\n * Resolve the directory that holds the bundled + core schemas for a given\n * AdCP version. Source layout (dev):\n * schemas/cache/<exact-version>/{bundled,core}\n * Built layout (dist):\n * dist/lib/schemas-data/<bundle-key>/{bundled,core}\n *\n * Stable releases use minor-name keys (`3.0/`); prereleases use full-version\n * keys (`3.1.0-beta.1/`). See {@link resolveBundleKey}.\n *\n * Falls back to the source-tree cache when dist isn't built (dev workflow\n * before `npm run build:lib`). For stable pins, the cache fallback scans\n * for the highest-patch sibling in the requested minor — `'3.0.0'` resolves\n * to `schemas/cache/3.0.1/` when only `3.0.1` is cached, matching dist's\n * collapse behavior.\n *\n * Throws when no bundle exists. Callers pinning a specific prerelease\n * surface the error; the construction-time fence in `resolveAdcpVersion`\n * catches most cross-major mistakes before this point.\n */\nfunction resolveSchemaRoot(version: string): string {\n const key = resolveBundleKey(version);\n const scopedRoot = scopedExternalSchemaRoots.getStore()?.get(key);\n if (scopedRoot && existsSync(scopedRoot)) return scopedRoot;\n\n const externalRoot = externalSchemaRoots.get(key);\n if (externalRoot && existsSync(externalRoot)) return externalRoot;\n\n const distCandidate = path.join(__dirname, '..', 'schemas-data', key);\n if (existsSync(distCandidate)) return distCandidate;\n\n // Published builds carry exact prerelease bundle directories\n // (`3.1.0-rc.1/`), while callers may pin the release-precision family\n // alias (`3.1-rc`). Resolve that alias before falling back to source cache.\n const releasePrecisionMatch = /^\\d+\\.\\d+-/.test(key);\n if (releasePrecisionMatch) {\n const distPrereleaseCandidate = findPrereleaseBundle(path.join(__dirname, '..', 'schemas-data'), key);\n if (distPrereleaseCandidate) return distPrereleaseCandidate;\n }\n\n // Source-tree fallback: cache stays exact-version-named, so map the key\n // back to the highest-patch cache directory in the same minor for stable\n // pins. Prereleases need an exact match.\n const cacheRoot = path.join(__dirname, '..', '..', '..', 'schemas', 'cache');\n const exactCandidate = path.join(cacheRoot, version);\n if (existsSync(exactCandidate)) return exactCandidate;\n\n // For minor-only or stable-patch pins, find the highest stable patch in\n // the cache that matches the resolved minor. Skip `*.previous` snapshots\n // — `sync-schemas` writes those as transient backups during replaceTree;\n // a partially-written snapshot whose patch number happens to be highest\n // would otherwise win the sort.\n const minorMatch = key.match(/^(\\d+)\\.(\\d+)$/);\n if (minorMatch && existsSync(cacheRoot)) {\n const [, major, minor] = minorMatch;\n const prefix = `${major}.${minor}.`;\n const cached = readdirSync(cacheRoot, { withFileTypes: true })\n .filter(\n e =>\n e.isDirectory() &&\n e.name.startsWith(prefix) &&\n !e.name.endsWith('.previous') &&\n /^\\d+\\.\\d+\\.\\d+$/.test(e.name)\n )\n .map(e => ({\n name: e.name,\n patch: parseInt(e.name.slice(prefix.length), 10),\n }))\n .filter(c => Number.isFinite(c.patch))\n .sort((a, b) => b.patch - a.patch);\n if (cached.length > 0) return path.join(cacheRoot, cached[0]!.name);\n }\n\n // For release-precision prerelease pins (`'3.1-beta'`, `'3.1-beta.0'`),\n // find the highest cached prerelease directory whose own release-precision\n // form starts with the requested key. A pin of `'3.1-beta'` matches any\n // directory whose `toReleasePrecisionWire` form is `'3.1-beta'` or\n // `'3.1-beta.*'`. A pin of `'3.1-beta.0'` matches `'3.1-beta.0'` or\n // `'3.1-beta.0.*'`. Sort newest-first by directory name with numeric\n // collation so rc.10 wins over rc.9.\n if (releasePrecisionMatch) {\n const cachePrereleaseCandidate = findPrereleaseBundle(cacheRoot, key);\n if (cachePrereleaseCandidate) return cachePrereleaseCandidate;\n }\n\n throw new Error(\n `AdCP schema data for version \"${version}\" not found. ` +\n `Looked for bundle key \"${key}\" in ${distCandidate}, exact path ${exactCandidate}, ` +\n `and the latest-patch fallback in ${cacheRoot}. ` +\n `Run \\`npm run sync-schemas\\` and \\`npm run build:lib\\` to populate the bundle.`\n );\n}\n\nfunction findPrereleaseBundle(root: string, key: string): string | undefined {\n if (!existsSync(root)) return undefined;\n const cached = readdirSync(root, { withFileTypes: true })\n .filter(e => e.isDirectory() && !e.name.endsWith('.previous'))\n .map(e => {\n try {\n return { name: e.name, rp: toReleasePrecisionWire(e.name) };\n } catch {\n return null;\n }\n })\n .filter((c): c is { name: string; rp: string } => c !== null)\n .filter(c => c.rp === key || c.rp.startsWith(`${key}.`))\n .sort((a, b) => compareBundleNamesDesc(a.name, b.name));\n if (cached.length === 0) return undefined;\n return path.join(root, cached[0]!.name);\n}\n\nfunction compareBundleNamesDesc(a: string, b: string): number {\n return b.localeCompare(a, undefined, { numeric: true, sensitivity: 'base' });\n}\n\ninterface LoaderState {\n ajv: Ajv;\n fileIndex: Map<string, string>;\n validators: Map<string, ValidateFunction>;\n rawSchemas: Map<string, Record<string, unknown>>;\n entityPaths: Map<string, SchemaEntityPath[]>;\n schemaIdFiles?: Map<string, string>;\n root: string;\n coreLoaded: boolean;\n version: string;\n}\n\nconst states: Map<string, LoaderState> = new Map();\nconst externalSchemaRoots: Map<string, string> = new Map();\nconst scopedExternalSchemaRoots = new AsyncLocalStorage<Map<string, string>>();\n\nfunction stateCacheKey(bundleKey: string, root: string): string {\n return `${bundleKey}\\0${root}`;\n}\n\nfunction clearStatesForBundle(bundleKey: string): void {\n for (const [stateKey, state] of states) {\n if (state.version === bundleKey) states.delete(stateKey);\n }\n}\n\nfunction hasSchemaRootShape(root: string): boolean {\n if (!existsSync(root)) return false;\n const bundledRoot = path.join(root, 'bundled');\n const files = existsSync(bundledRoot) ? walkJsonFiles(bundledRoot) : walkJsonFiles(root);\n return files.some(file => {\n try {\n const schema = loadJson(file);\n return typeof schema.$id === 'string' || typeof schema.$schema === 'string';\n } catch {\n return false;\n }\n });\n}\n\nfunction schemaIdVersionHint(schemaId: string): string | undefined {\n return schemaId.match(/\\/schemas\\/([^/]+)\\//)?.[1];\n}\n\nfunction collectSchemaRootVersionAliases(root: string): Set<string> {\n const aliases = new Set<string>();\n for (const file of walkJsonFiles(root)) {\n let schema: LoadedSchema;\n try {\n schema = loadJson(file);\n } catch {\n continue;\n }\n if (typeof schema.$id !== 'string') continue;\n const hint = schemaIdVersionHint(schema.$id);\n if (!hint) continue;\n for (const alias of schemaRootVersionAliases(hint)) aliases.add(alias);\n }\n return aliases;\n}\n\nfunction schemaRootVersionAliases(version: string): Set<string> {\n const aliases = new Set<string>([version]);\n try {\n aliases.add(resolveBundleKey(version));\n } catch {\n // Keep the raw value only; callers that care will throw separately.\n }\n try {\n const releasePrecision = toReleasePrecisionWire(version);\n aliases.add(releasePrecision);\n const family = prereleaseFamilyAlias(releasePrecision);\n if (family) aliases.add(family);\n } catch {\n // Keep any aliases already collected.\n }\n return aliases;\n}\n\nfunction prereleaseFamilyAlias(releasePrecisionVersion: string): string | undefined {\n return releasePrecisionVersion.match(/^(\\d+\\.\\d+-[0-9A-Za-z-]+)\\.\\d+$/)?.[1];\n}\n\nfunction collectSchemaRootVersionAliasGroups(root: string): Array<{ hint: string; aliases: Set<string> }> {\n const groups: Array<{ hint: string; aliases: Set<string> }> = [];\n for (const file of walkJsonFiles(root)) {\n let schema: LoadedSchema;\n try {\n schema = loadJson(file);\n } catch {\n continue;\n }\n if (typeof schema.$id !== 'string') continue;\n const hint = schemaIdVersionHint(schema.$id);\n if (!hint) continue;\n groups.push({ hint, aliases: schemaRootVersionAliases(hint) });\n }\n return groups;\n}\n\nfunction assertSchemaRootMatchesVersion(version: string, root: string): Set<string> {\n const expectedAliases = schemaRootVersionAliases(version);\n const rootGroups = collectSchemaRootVersionAliasGroups(root);\n const rootAliases = collectSchemaRootVersionAliases(root);\n if (\n rootGroups.length > 0 &&\n rootGroups.every(group => [...group.aliases].some(alias => expectedAliases.has(alias)))\n ) {\n return new Set([...expectedAliases, ...rootAliases]);\n }\n const found =\n rootGroups.length === 0\n ? 'no AdCP schema ids'\n : rootGroups\n .map(group => `${group.hint} (${Array.from(group.aliases).sort().join(', ')})`)\n .sort()\n .join(', ');\n throw new Error(\n `External AdCP schema root for version \"${version}\" at ${root} does not match the requested version and ` +\n `must contain only schema ids matching ${Array.from(expectedAliases).sort().join(', ')}; found ${found}.`\n );\n}\n\nconst externalSchemaRootAliases: Map<string, Set<string>> = new Map();\n\n/**\n * Register a schema bundle supplied outside the installed SDK package.\n *\n * Compliance runners use this when `--compliance-dir` points at another\n * package/check-out whose storyboards and schema bundle should be used\n * together. The root must be the schema-data directory itself, e.g.\n * `.../dist/lib/schemas-data/3.0`.\n */\nexport function registerExternalSchemaRoot(version: string, root: string): void {\n const key = resolveBundleKey(version);\n if (!hasSchemaRootShape(root)) {\n throw new Error(`External AdCP schema root for version \"${version}\" not found or empty at ${root}`);\n }\n const aliases = assertSchemaRootMatchesVersion(version, root);\n externalSchemaRootAliases.set(key, aliases);\n for (const alias of aliases) {\n const previous = externalSchemaRoots.get(alias);\n externalSchemaRoots.set(alias, root);\n if (previous !== root) clearStatesForBundle(alias);\n }\n}\n\n/** Test/helper hook for unregistering an external schema bundle. */\nexport function unregisterExternalSchemaRoot(version: string): void {\n const key = resolveBundleKey(version);\n const aliases = new Set(schemaRootVersionAliases(version));\n for (const [registeredKey, registeredAliases] of externalSchemaRootAliases) {\n if (\n registeredKey === key ||\n registeredAliases.has(key) ||\n [...aliases].some(alias => registeredAliases.has(alias))\n ) {\n for (const alias of registeredAliases) aliases.add(alias);\n externalSchemaRootAliases.delete(registeredKey);\n }\n }\n for (const alias of aliases) {\n externalSchemaRoots.delete(alias);\n clearStatesForBundle(alias);\n }\n}\n\n/**\n * Run a callback with an external schema root scoped to the current async\n * execution chain. Unlike `registerExternalSchemaRoot`, this does not poison\n * process-global validation state for later hosted/compliance runs.\n */\nexport function withExternalSchemaRoot<T>(version: string, root: string | undefined, fn: () => T): T {\n if (root === undefined) return fn();\n if (!hasSchemaRootShape(root)) {\n throw new Error(`External AdCP schema root for version \"${version}\" not found or empty at ${root}`);\n }\n const aliases = assertSchemaRootMatchesVersion(version, root);\n const parent = scopedExternalSchemaRoots.getStore();\n const next = new Map(parent);\n for (const alias of aliases) {\n next.set(alias, root);\n clearStatesForBundle(alias);\n }\n return scopedExternalSchemaRoots.run(next, fn);\n}\n\n/**\n * Return whether validation for `version` currently resolves through a\n * caller-supplied schema bundle rather than the SDK's packaged snapshot.\n *\n * Storyboard validation uses this to make an explicit external JSON Schema\n * bundle authoritative.\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function isExternalSchemaRootActive(version: string): boolean {\n const key = resolveBundleKey(version);\n const scopedRoot = scopedExternalSchemaRoots.getStore()?.get(key);\n if (scopedRoot && existsSync(scopedRoot)) return true;\n const registeredRoot = externalSchemaRoots.get(key);\n return registeredRoot !== undefined && existsSync(registeredRoot);\n}\n\nfunction walkJsonFiles(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) out.push(...walkJsonFiles(full));\n else if (entry.isFile() && entry.name.endsWith('.json')) out.push(full);\n }\n return out;\n}\n\nfunction loadJson(file: string): LoadedSchema {\n return JSON.parse(readFileSync(file, 'utf-8')) as LoadedSchema;\n}\n\n/**\n * Clear `additionalProperties: false` at the response root so envelope\n * fields (`replayed`, `context`, `ext`, and future envelope additions)\n * can ride alongside the tool-specific body — per security.mdx the\n * envelope is always extensible. Upstream bundled schemas pin\n * `additionalProperties: false` at the root on a handful of mutating\n * tools (the property-list family), which rejects envelope fields like\n * `replayed` that aren't declared in the tool-specific body.\n *\n * Scope is deliberately narrow: only the top-level object, plus each\n * direct branch of a root-level `oneOf` / `anyOf` / `allOf`. Nested\n * bodies stay strict so response-side drift detection still catches\n * typos inside `Product`, `Package`, `MediaBuy` etc. Applied only to\n * response variants; request schemas stay strict so outgoing drift\n * fails at the edge.\n */\nfunction relaxResponseRoot(schema: LoadedSchema): LoadedSchema {\n const clone = { ...schema };\n if (clone.additionalProperties === false) {\n clone.additionalProperties = true;\n }\n for (const key of ['oneOf', 'anyOf', 'allOf'] as const) {\n const branches = clone[key];\n if (Array.isArray(branches)) {\n clone[key] = branches.map(branch => {\n if (!branch || typeof branch !== 'object') return branch;\n const branchClone = { ...(branch as Record<string, unknown>) };\n if (branchClone.additionalProperties === false) {\n branchClone.additionalProperties = true;\n }\n return branchClone;\n });\n }\n }\n return clone;\n}\n\nfunction getAjvRegisteredIds(ajv: Ajv): Set<string> {\n const internals = ajv as unknown as {\n schemas?: Record<string, unknown>;\n refs?: Record<string, unknown>;\n };\n return new Set([...Object.keys(internals.schemas ?? {}), ...Object.keys(internals.refs ?? {})]);\n}\n\n/**\n * Build the (toolName, direction) → file path index by scanning the schema\n * tree once. Runs eagerly at first validator lookup.\n */\nfunction buildFileIndex(root: string): Map<string, string> {\n const index = new Map<string, string>();\n const record = (toolName: string, direction: Direction, file: string): void => {\n index.set(`${toolName}::${direction}`, file);\n };\n\n // Sync request/response live in the pre-resolved bundled/ tree.\n const bundledRoot = path.join(root, 'bundled');\n for (const file of walkJsonFiles(bundledRoot)) {\n const base = path.basename(file, '.json');\n if (base.endsWith('-request')) {\n const tool = base.slice(0, -'-request'.length).replace(/-/g, '_');\n record(tool, 'request', file);\n } else if (base.endsWith('-response')) {\n const tool = base.slice(0, -'-response'.length).replace(/-/g, '_');\n record(tool, 'sync', file);\n }\n }\n\n // Async variants AND domain schemas that ship flat (not pre-bundled) both\n // live in the per-domain directories. Walk each for sync request/response\n // files and async variant files. Skip `bundled/` (already indexed above)\n // and `core/` (pure $ref targets, no tools).\n //\n // Flat-tree domains include `governance/`, `brand/`, `account/`,\n // `content-standards/`, `property/`, `collection/` — their schemas are\n // NOT pre-resolved into `bundled/`, so a bundled-only walk would miss\n // every `check_governance` / `acquire_rights` / `creative_approval` /\n // `sync_governance` / `*_property_list` request-response pair. That gap\n // (flagged by the ad-tech-protocol reviewer on PR #831) would leave\n // protocol-wide-requirement-bearing tasks (idempotency_key pattern,\n // `format: uri` on `caller`) invisible to the strict-validation signal.\n // Register flat-tree sync pairs only when `bundled/` didn't already\n // index them, so pre-resolved schemas (with $refs already inlined) win\n // for any domain that ships both.\n for (const entry of readdirSync(root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (entry.name === 'bundled' || entry.name === 'core') continue;\n const domainDir = path.join(root, entry.name);\n for (const file of walkJsonFiles(domainDir)) {\n const base = path.basename(file, '.json');\n if (base.endsWith('-async-response-submitted')) {\n const tool = base.slice(0, -'-async-response-submitted'.length).replace(/-/g, '_');\n record(tool, 'submitted', file);\n } else if (base.endsWith('-async-response-working')) {\n const tool = base.slice(0, -'-async-response-working'.length).replace(/-/g, '_');\n record(tool, 'working', file);\n } else if (base.endsWith('-async-response-input-required')) {\n const tool = base.slice(0, -'-async-response-input-required'.length).replace(/-/g, '_');\n record(tool, 'input-required', file);\n } else if (base.endsWith('-request')) {\n const tool = base.slice(0, -'-request'.length).replace(/-/g, '_');\n if (!index.has(`${tool}::request`)) record(tool, 'request', file);\n } else if (base.endsWith('-response')) {\n const tool = base.slice(0, -'-response'.length).replace(/-/g, '_');\n if (!index.has(`${tool}::sync`)) record(tool, 'sync', file);\n }\n }\n }\n\n return index;\n}\n\nfunction ensureInit(version: string): LoaderState {\n // States are keyed by bundle key, not by raw version string, so\n // `getValidator('foo', 'request', '3.0.0')` and the same call with\n // `'3.0.1'` share state — both resolve to bundle key `'3.0'` and the\n // same compiled AJV instance.\n const key = resolveBundleKey(version);\n const root = resolveSchemaRoot(version);\n const cacheKey = stateCacheKey(key, root);\n const cached = states.get(cacheKey);\n if (cached) return cached;\n const ajv = new Ajv({\n strict: false,\n allErrors: true,\n allowUnionTypes: true,\n });\n addFormats(ajv);\n\n const state: LoaderState = {\n ajv,\n fileIndex: buildFileIndex(root),\n validators: new Map(),\n rawSchemas: new Map(),\n entityPaths: new Map(),\n root,\n coreLoaded: false,\n version: key,\n };\n states.set(cacheKey, state);\n return state;\n}\n\n/**\n * Lazily pre-register every non-tool JSON schema shipped with the SDK so\n * cross-domain `$ref`s compile. Async response variants and flat-tree\n * domain schemas `$ref` out to three classes of building-block schemas:\n *\n * - `core/` + `enums/` — shared primitives referenced by every domain.\n * - `pricing-options/`, `error-details/`, `extensions/` — stand-alone\n * fragment trees.\n * - Sibling fragments inside each domain directory — e.g.\n * `governance/audience-constraints.json` referenced by\n * `governance/sync-plans-request.json`, or `signals/*` fragments\n * referenced by `signals/activate-signal-*.json`.\n *\n * Walk every directory except `bundled/` (pre-resolved schemas with refs\n * already inlined). Response files that `buildFileIndex` registered as tools\n * are registered with `relaxResponseRoot` applied, matching `getValidator`.\n * The fileIndex check is stricter than a filename-suffix match:\n * building-block fragments like `core/pagination-response.json` end in\n * `-response.json` but aren't tools, so suffix-matching would wrongly treat\n * them as relaxable response roots.\n */\nfunction ensureCoreLoaded(s: LoaderState): void {\n if (s.coreLoaded) return;\n // Tool response files are pre-registered with the same response-root\n // relaxation `getValidator` would apply. This matters for the async response\n // union: `core/async-response-data.json` can `$ref` both async variants and\n // sync responses, so callers must not have to prewarm response validators\n // before compiling a request that references the union.\n //\n // Why this matters: bundles whose source tree doesn't include a `bundled/`\n // pre-resolved subtree (e.g. v2.5, where the spec ships flat schemas with\n // unresolved `$ref`s) classify fragments like `media-buy/package-request.json`\n // as tool `package::request` via the filename-suffix heuristic in\n // `buildFileIndex`. Skipping all tool files would leave that fragment\n // unregistered, so a later compile of `create_media_buy` fails on\n // `MissingRefError: can't resolve /schemas/media-buy/package-request.json`.\n //\n const responseToolFiles = new Map<string, Direction>();\n for (const [key, file] of s.fileIndex) {\n if (key.endsWith('::request')) continue;\n const direction = key.slice(key.indexOf('::') + 2) as Direction;\n responseToolFiles.set(file, direction);\n }\n const registeredIds = getAjvRegisteredIds(s.ajv);\n for (const entry of readdirSync(s.root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (entry.name === 'bundled') continue;\n const abs = path.join(s.root, entry.name);\n for (const file of walkJsonFiles(abs)) {\n const responseDirection = responseToolFiles.get(file);\n const schema = loadJson(file);\n const schemaToRegister = responseDirection === undefined ? schema : relaxResponseRoot(schema);\n if (typeof schemaToRegister.$id === 'string' && !registeredIds.has(schemaToRegister.$id)) {\n s.ajv.addSchema(schemaToRegister);\n registeredIds.add(schemaToRegister.$id);\n }\n }\n }\n s.coreLoaded = true;\n}\n\n/**\n * Look up the compiled AJV validator for a given tool + direction in the\n * specified AdCP version's schema bundle. Returns `undefined` when no\n * schema exists for the pair — callers can skip validation cleanly (e.g.,\n * custom tools outside the AdCP spec).\n *\n * `version` defaults to the SDK-pinned `ADCP_VERSION`. Pass the per-instance\n * `getAdcpVersion()` value when the validator should track the client/server's\n * configured pin (Stage 3+).\n */\nexport function getValidator(\n toolName: string,\n direction: Direction,\n version: string = ADCP_VERSION\n): ValidateFunction | undefined {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::${direction}`;\n const cached = s.validators.get(cacheKey);\n if (cached) return cached;\n\n const file = s.fileIndex.get(cacheKey);\n if (!file) return undefined;\n\n // Schemas that $ref into core/ and enums/ need those trees registered\n // before compile. Async response variants always do; flat-tree domain\n // schemas (anything outside `bundled/`) do too — their $refs weren't\n // pre-resolved at spec-publish time.\n const fromBundled = file.includes(`${path.sep}bundled${path.sep}`);\n if (direction === 'request' || !fromBundled) ensureCoreLoaded(s);\n\n const rawSchema = loadJson(file);\n // Bundled files inline every referenced subschema with the original\n // canonical `$id` (e.g. `core/version-envelope.json` appears nested\n // inside every bundled tool response). Bundled files carry NO\n // internal `$ref`s — the spec publishes them fully resolved, see\n // the `note: \"This is a bundled schema with all $ref resolved inline\"`\n // tag on every bundled file. Once `ensureCoreLoaded` has registered\n // any of those core schemas standalone (which it does for the flat-\n // tree governance / brand / property domains), Ajv's compile of a\n // bundled file trips the ambiguous-ref check on every nested $id.\n //\n // The fix: strip nested `$id` fields before compile on bundled\n // schemas. The root `$id` is kept (it's the validator's lookup key);\n // every other `$id` in the tree was just metadata anyway.\n const prepared = fromBundled ? stripNestedIds(rawSchema) : rawSchema;\n const schema = direction === 'request' ? prepared : relaxResponseRoot(prepared);\n const existing = typeof schema.$id === 'string' ? s.ajv.getSchema(schema.$id) : undefined;\n const compiled = existing ?? s.ajv.compile(schema);\n s.validators.set(cacheKey, compiled);\n return compiled;\n}\n\n/**\n * Compile an arbitrary schema from the cached bundle by path, e.g.\n * `core/mcp-webhook-payload.json`. Used by storyboard webhook assertions\n * whose payload schema is not tied to a tool request/response pair.\n */\nexport function getSchemaValidatorByRef(\n schemaRef: string,\n version: string = ADCP_VERSION\n): ValidateFunction | undefined {\n const s = ensureInit(version);\n const normalized = normalizeSchemaRef(schemaRef);\n if (!normalized) return undefined;\n\n const cacheKey = `schema-ref::${normalized}`;\n const cached = s.validators.get(cacheKey);\n if (cached) return cached;\n\n const file = path.join(s.root, normalized);\n if (!existsSync(file)) return undefined;\n\n // Use an isolated AJV instance for arbitrary schema refs. Tool response\n // validators deliberately relax some roots for SDK back-compat; webhook\n // payload schemas need strict raw JSON Schema behavior without polluting the\n // shared tool-validator registry with unrelaxed response schemas.\n const ajv = new Ajv({\n strict: false,\n allErrors: true,\n allowUnionTypes: true,\n });\n addFormats(ajv);\n const dependencySchemas: LoadedSchema[] = [];\n const registeredIds = new Set<string>();\n for (const schemaFile of walkJsonFiles(s.root)) {\n if (schemaFile.includes(`${path.sep}bundled${path.sep}`)) continue;\n if (schemaFile === file) continue;\n const schema = loadJson(schemaFile);\n if (typeof schema.$id === 'string' && !registeredIds.has(schema.$id)) {\n registeredIds.add(schema.$id);\n dependencySchemas.push(schema);\n }\n }\n if (dependencySchemas.length > 0) {\n ajv.addSchema(dependencySchemas);\n }\n const rawSchema = loadJson(file);\n const compiled = ajv.compile(rawSchema);\n s.validators.set(cacheKey, compiled);\n return compiled;\n}\n\nfunction normalizeSchemaRef(schemaRef: string): string | undefined {\n const trimmed = schemaRef.replace(/^\\/+/, '');\n if (trimmed.length === 0) return undefined;\n const normalized = path.normalize(trimmed);\n if (normalized.startsWith('..') || path.isAbsolute(normalized)) return undefined;\n return normalized;\n}\n\n/**\n * Strip `$id` from every subschema of a bundled response file, preserving\n * the root `$id`. Bundled files are fully inlined (no internal `$ref`s),\n * so the nested `$id`s are vestigial metadata — Ajv only cares about the\n * root `$id` for validator lookup. Without this strip, Ajv's\n * `checkAmbiguousRef` throws when an inlined nested `$id` matches one\n * already registered standalone via `ensureCoreLoaded`.\n *\n * Returns a deep-copied tree; the input is not mutated.\n */\nfunction stripNestedIds(schema: LoadedSchema): LoadedSchema {\n const root = JSON.parse(JSON.stringify(schema)) as LoadedSchema;\n const rootId = typeof root.$id === 'string' ? root.$id : undefined;\n const walk = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const item of node) walk(item);\n return;\n }\n if (!node || typeof node !== 'object') return;\n const obj = node as Record<string, unknown>;\n if (typeof obj.$id === 'string' && obj.$id !== rootId) {\n delete obj.$id;\n }\n for (const value of Object.values(obj)) walk(value);\n };\n walk(root);\n return root;\n}\n\n/** List of (toolName, direction) pairs that have schemas. Used by tests. */\nexport function listValidatorKeys(version: string = ADCP_VERSION): string[] {\n const s = ensureInit(version);\n return [...s.fileIndex.keys()].sort();\n}\n\n/**\n * `$id`s of every schema currently registered with the AdCP validator's AJV\n * instance for `version`. Used by the schema-validator to extract the\n * rejecting sub-schema's `$id` from an Ajv error's `schemaPath`: when a\n * `$ref` is followed, Ajv prefixes the schemaPath with the target schema's\n * `$id`, so the longest registered `$id` that prefixes a schemaPath is the\n * sub-schema responsible for the failure.\n *\n * The set grows as `getValidator` calls trigger `ensureCoreLoaded` and\n * compile new tool roots — callers should read it AFTER the validate call\n * they're projecting errors from.\n */\nexport function getRegisteredSchemaIds(version: string = ADCP_VERSION): readonly string[] {\n const s = ensureInit(version);\n // Ajv 8 keeps registered schemas at `ajv.schemas` (URI → SchemaEnv). Returning\n // the keys is enough for prefix matching; we don't expose the SchemaEnv values.\n const registry = (s.ajv as unknown as { schemas?: Record<string, unknown> }).schemas;\n return registry ? Object.keys(registry) : [];\n}\n\n/** Suffix used in the suffix table — exported for testing. */\nexport { SCHEMA_FILENAME_SUFFIX };\n\n/**\n * Returns true when the schema bundle for `version` is reachable from the\n * dist build or the source-tree fallback. Cheap synchronous check; safe\n * to call at construction time of clients/servers to fail fast on a pin\n * we don't have schemas for.\n */\nexport function hasSchemaBundle(version: string): boolean {\n try {\n resolveSchemaRoot(version);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Test hook: reset cached state. With no argument, clears every version's\n * loader state; with a version, clears only the bundle that version\n * resolves to (so passing `'3.0.0'` and `'3.0.1'` both clear the `'3.0'`\n * bundle).\n */\nexport function _resetValidationLoader(version?: string): void {\n if (version === undefined) {\n states.clear();\n } else {\n clearStatesForBundle(resolveBundleKey(version));\n }\n}\n\n/**\n * Returns true when `field` is **explicitly declared** as a top-level property\n * in the request schema for `toolName`, or when no schema is available\n * (fail-open). Used by the storyboard runner to decide whether to inject\n * envelope fields that aren't universally present across tools (e.g. `brand`,\n * `account`, `ext`).\n *\n * Reads the raw JSON schema file without compiling — avoids coupling to AJV\n * internals. Only inspects the top-level `properties` map; nested sub-schemas\n * are not traversed. Results are memoized in `LoaderState.rawSchemas` so\n * multi-step storyboard runs don't re-read the same file on each step.\n *\n * **Semantic note**: AdCP 3.1.0-beta.3 set `additionalProperties: true` on\n * mutating request schemas (vendor-extension friendly). Before that flip, the\n * helper used `additionalProperties: false` as the gate — \"if the schema is\n * strict, only `properties` keys are allowed.\" Now requests are universally\n * permissive at the schema level, so that gate would say `true` for any field\n * on any request — defeating the storyboard runner's intent (\"only inject\n * envelope fields the tool's schema declares it expects to see\"). The helper\n * now checks `field in properties` directly: the question we actually care\n * about is **\"does the schema declare this field at top level?\"**, not\n * \"does the schema permit this field at top level?\" (it permits everything).\n *\n * Fails open (returns `true`) when:\n * - No schema file is indexed for the tool (custom tool, schema not synced)\n * - The schema root is not reachable (schemas not built/synced yet)\n * - Any I/O / parse error during the read\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function schemaAllowsTopLevelField(toolName: string, field: string, version: string = ADCP_VERSION): boolean {\n try {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::request`;\n const file = s.fileIndex.get(cacheKey);\n if (!file) return true;\n let schema = s.rawSchemas.get(cacheKey);\n if (!schema) {\n schema = loadJson(file) as Record<string, unknown>;\n s.rawSchemas.set(cacheKey, schema);\n }\n const props = schema.properties as Record<string, unknown> | undefined;\n return props !== undefined && field in props;\n } catch {\n return true;\n }\n}\n\nexport interface SchemaEntityPath {\n /** Property path from the tool request root. `*` addresses every array item. */\n path: string[];\n /** AdCP `x-entity` annotation found on the identity-bearing leaf. */\n xEntity: string;\n}\n\n/**\n * Return every request field carrying an `x-entity` annotation. Unlike the\n * server hydration map this walks nested arrays/objects, because storyboard\n * fixture handles commonly live at `packages[*].product_id` and\n * `packages[*].pricing_option_id`.\n *\n * Missing schemas fail closed with an empty list: handle substitution must\n * never guess from a field name alone.\n */\nexport function getRequestSchemaEntityPaths(\n toolName: string,\n version: string = ADCP_VERSION\n): readonly SchemaEntityPath[] {\n try {\n const s = ensureInit(version);\n const cacheKey = `${toolName}::request`;\n const cached = s.entityPaths.get(cacheKey);\n if (cached) return cached;\n const file = s.fileIndex.get(cacheKey);\n if (!file) return [];\n\n const root = loadJson(file) as Record<string, unknown>;\n const found = new Map<string, SchemaEntityPath>();\n const stack = new Set<string>();\n\n const resolvePointer = (document: unknown, fragment: string): unknown => {\n if (!fragment || fragment === '#') return document;\n if (!fragment.startsWith('#/')) return undefined;\n let current = document;\n for (const encoded of fragment.slice(2).split('/')) {\n if (!current || typeof current !== 'object') return undefined;\n const key = encoded.replace(/~1/g, '/').replace(/~0/g, '~');\n current = (current as Record<string, unknown>)[key];\n }\n return current;\n };\n\n const resolveRef = (\n ref: string,\n currentFile: string,\n currentDocument: Record<string, unknown>\n ): { node: unknown; file: string; document: Record<string, unknown>; key: string } | undefined => {\n const hash = ref.indexOf('#');\n const refPath = hash >= 0 ? ref.slice(0, hash) : ref;\n const fragment = hash >= 0 ? ref.slice(hash) : '';\n if (!refPath) {\n return {\n node: resolvePointer(currentDocument, fragment),\n file: currentFile,\n document: currentDocument,\n key: `${currentFile}${fragment}`,\n };\n }\n\n const schemaRelative = refPath.match(/\\/schemas\\/[^/]+\\/(.+)$/)?.[1];\n const candidates = [\n schemaRelative ? path.join(s.root, schemaRelative) : undefined,\n path.resolve(path.dirname(currentFile), refPath),\n ].filter((candidate): candidate is string => candidate !== undefined);\n let targetFile = candidates.find(candidate => existsSync(candidate));\n // Standard AdCP refs encode their schema-root-relative file path, so\n // they resolve without parsing every JSON file in the bundle. Build the\n // expensive $id index only for an unusual ref that cannot be resolved\n // by path.\n if (!targetFile) {\n if (!s.schemaIdFiles) {\n const idToFile = new Map<string, string>();\n for (const schemaFile of walkJsonFiles(s.root)) {\n try {\n const schema = loadJson(schemaFile);\n if (typeof schema.$id === 'string') idToFile.set(schema.$id, schemaFile);\n } catch {\n // A malformed unrelated schema is not a usable ref target.\n }\n }\n s.schemaIdFiles = idToFile;\n }\n targetFile = s.schemaIdFiles.get(refPath);\n }\n if (!targetFile) return undefined;\n const document = loadJson(targetFile) as Record<string, unknown>;\n return {\n node: resolvePointer(document, fragment),\n file: targetFile,\n document,\n key: `${targetFile}${fragment}`,\n };\n };\n\n const walk = (\n node: unknown,\n propertyPath: string[],\n currentFile: string,\n currentDocument: Record<string, unknown>,\n depth: number\n ): void => {\n if (!node || typeof node !== 'object' || depth > 48) return;\n const obj = node as Record<string, unknown>;\n if (typeof obj['x-entity'] === 'string' && propertyPath.length > 0) {\n const entityPath = { path: [...propertyPath], xEntity: obj['x-entity'] as string };\n found.set(`${entityPath.path.join('.')}\\0${entityPath.xEntity}`, entityPath);\n }\n\n if (typeof obj.$ref === 'string') {\n const target = resolveRef(obj.$ref, currentFile, currentDocument);\n if (target && target.node !== undefined) {\n const guard = `${target.key}\\0${propertyPath.join('.')}`;\n if (!stack.has(guard)) {\n stack.add(guard);\n walk(target.node, propertyPath, target.file, target.document, depth + 1);\n stack.delete(guard);\n }\n }\n }\n\n const properties = obj.properties;\n if (properties && typeof properties === 'object' && !Array.isArray(properties)) {\n for (const [key, child] of Object.entries(properties as Record<string, unknown>)) {\n walk(child, [...propertyPath, key], currentFile, currentDocument, depth + 1);\n }\n }\n if (obj.items !== undefined) {\n walk(obj.items, [...propertyPath, '*'], currentFile, currentDocument, depth + 1);\n }\n for (const keyword of ['allOf', 'anyOf', 'oneOf'] as const) {\n const branches = obj[keyword];\n if (Array.isArray(branches)) {\n for (const branch of branches) walk(branch, propertyPath, currentFile, currentDocument, depth + 1);\n }\n }\n for (const keyword of ['if', 'then', 'else', 'not'] as const) {\n if (obj[keyword] !== undefined) {\n walk(obj[keyword], propertyPath, currentFile, currentDocument, depth + 1);\n }\n }\n };\n\n walk(root, [], file, root, 0);\n const result = [...found.values()].sort((a, b) => {\n const byPath = a.path.join('.').localeCompare(b.path.join('.'));\n return byPath || a.xEntity.localeCompare(b.xEntity);\n });\n s.entityPaths.set(cacheKey, result);\n return result;\n } catch {\n return [];\n }\n}\n\n/**\n * Resolve a JSON Schema `default` value by walking a dot-separated property\n * path through a schema's nested `properties` maps.\n *\n * This intentionally does not instantiate AJV's `useDefaults` mutation mode.\n * Callers decide when a schema default is semantically meaningful for their\n * runtime object; this helper only reports what the bundled schema declares.\n *\n * Fails closed (`undefined`) when the schema is unavailable, the path is not a\n * concrete properties path, or the target schema node has no `default`.\n *\n * @internal — not part of the public API surface; may change without a major bump.\n */\nexport function getSchemaDefaultByPath(schemaRef: string, dottedPath: string, version: string = ADCP_VERSION): unknown {\n try {\n const s = ensureInit(version);\n const normalized = normalizeSchemaRef(schemaRef);\n if (!normalized) return undefined;\n\n const cacheKey = `schema-ref::${normalized}`;\n const file = path.join(s.root, normalized);\n if (!existsSync(file)) return undefined;\n\n let schema = s.rawSchemas.get(cacheKey);\n if (!schema) {\n schema = loadJson(file) as Record<string, unknown>;\n s.rawSchemas.set(cacheKey, schema);\n }\n\n const node = resolveSchemaPropertyPath(schema, dottedPath);\n if (!node || !Object.prototype.hasOwnProperty.call(node, 'default')) return undefined;\n return cloneJsonValue((node as { default: unknown }).default);\n } catch {\n return undefined;\n }\n}\n\nfunction resolveSchemaPropertyPath(\n schema: Record<string, unknown>,\n dottedPath: string\n): Record<string, unknown> | undefined {\n let current: unknown = schema;\n for (const key of dottedPath.split('.')) {\n if (!current || typeof current !== 'object') return undefined;\n const props = (current as Record<string, unknown>).properties;\n if (!props || typeof props !== 'object') return undefined;\n if (!Object.prototype.hasOwnProperty.call(props, key)) return undefined;\n current = (props as Record<string, unknown>)[key];\n }\n return current && typeof current === 'object' ? (current as Record<string, unknown>) : undefined;\n}\n\nfunction cloneJsonValue(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value;\n return JSON.parse(JSON.stringify(value)) as unknown;\n}\n"],"mappings":"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","names":["path","Ajv","addFormats"]}
@@ -249,6 +249,13 @@ function withExternalSchemaRoot(version, root, fn) {
249
249
  }
250
250
  return scopedExternalSchemaRoots.run(next, fn);
251
251
  }
252
+ function isExternalSchemaRootActive(version) {
253
+ const key = resolveBundleKey(version);
254
+ const scopedRoot = scopedExternalSchemaRoots.getStore()?.get(key);
255
+ if (scopedRoot && existsSync(scopedRoot)) return true;
256
+ const registeredRoot = externalSchemaRoots.get(key);
257
+ return registeredRoot !== void 0 && existsSync(registeredRoot);
258
+ }
252
259
  function walkJsonFiles(dir) {
253
260
  if (!existsSync(dir)) return [];
254
261
  const out = [];
@@ -652,6 +659,7 @@ export {
652
659
  getSchemaValidatorByRef,
653
660
  getValidator,
654
661
  hasSchemaBundle,
662
+ isExternalSchemaRootActive,
655
663
  listValidatorKeys,
656
664
  registerExternalSchemaRoot,
657
665
  resolveBundleKey,