@adcp/sdk 14.0.0-beta.8 → 14.0.0-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/ConversationTypes.d.mts +8 -0
- package/dist/lib/core/ConversationTypes.d.ts +8 -0
- package/dist/lib/core/ConversationTypes.d.ts.map +1 -1
- package/dist/lib/core/ConversationTypes.js.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +30 -3
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/core/SingleAgentClient.mjs +30 -3
- package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
- package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
- package/dist/lib/core/TaskExecutor.js +32 -5
- package/dist/lib/core/TaskExecutor.js.map +1 -1
- package/dist/lib/core/TaskExecutor.mjs +32 -5
- package/dist/lib/core/TaskExecutor.mjs.map +1 -1
- package/dist/lib/index.d.mts +2 -2
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +2 -1
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/schemas/index.d.mts +14 -0
- package/dist/lib/schemas/index.d.ts +14 -0
- package/dist/lib/schemas/index.d.ts.map +1 -1
- package/dist/lib/schemas/index.js +13 -1
- package/dist/lib/schemas/index.js.map +1 -1
- package/dist/lib/schemas/index.mjs +13 -1
- package/dist/lib/schemas/index.mjs.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/adcp-server.d.mts +1 -0
- package/dist/lib/server/adcp-server.d.ts +1 -0
- package/dist/lib/server/adcp-server.d.ts.map +1 -1
- package/dist/lib/server/adcp-server.js +1 -1
- package/dist/lib/server/adcp-server.js.map +1 -1
- package/dist/lib/server/adcp-server.mjs +1 -1
- package/dist/lib/server/adcp-server.mjs.map +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +10 -2
- package/dist/lib/server/create-adcp-server.d.ts +10 -2
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
- package/dist/lib/server/create-adcp-server.js +26 -19
- package/dist/lib/server/create-adcp-server.js.map +1 -1
- package/dist/lib/server/create-adcp-server.mjs +26 -26
- package/dist/lib/server/create-adcp-server.mjs.map +1 -1
- package/dist/lib/server/decisioning/capabilities.d.mts +15 -1
- package/dist/lib/server/decisioning/capabilities.d.ts +15 -1
- package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -1
- package/dist/lib/server/decisioning/capabilities.js.map +1 -1
- package/dist/lib/server/decisioning/capabilities.mjs.map +1 -1
- package/dist/lib/server/decisioning/index.d.mts +2 -2
- package/dist/lib/server/decisioning/index.d.ts +2 -2
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js +2 -0
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/index.mjs +2 -0
- package/dist/lib/server/decisioning/index.mjs.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.d.mts +3 -2
- package/dist/lib/server/decisioning/proposal/types.d.ts +3 -2
- package/dist/lib/server/decisioning/proposal/types.d.ts.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/types.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +14 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +14 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +402 -9
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +405 -9
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.d.mts +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.d.ts +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.js +2 -2
- package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs +2 -2
- package/dist/lib/server/decisioning/runtime/validate-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.mts +7 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.ts +7 -1
- package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
- package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
- package/dist/lib/storage/interfaces.d.mts +2 -0
- package/dist/lib/storage/interfaces.d.ts +2 -0
- package/dist/lib/storage/interfaces.d.ts.map +1 -1
- package/dist/lib/storage/interfaces.js.map +1 -1
- package/dist/lib/testing/compliance/comply.d.mts +18 -0
- package/dist/lib/testing/compliance/comply.d.ts +18 -0
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
- package/dist/lib/testing/compliance/comply.js +30 -5
- package/dist/lib/testing/compliance/comply.js.map +1 -1
- package/dist/lib/testing/compliance/comply.mjs +28 -4
- package/dist/lib/testing/compliance/comply.mjs.map +1 -1
- package/dist/lib/testing/compliance/index.d.mts +1 -1
- package/dist/lib/testing/compliance/index.d.ts +1 -1
- package/dist/lib/testing/compliance/index.d.ts.map +1 -1
- package/dist/lib/testing/compliance/index.js +4 -2
- package/dist/lib/testing/compliance/index.js.map +1 -1
- package/dist/lib/testing/compliance/index.mjs +4 -2
- package/dist/lib/testing/compliance/index.mjs.map +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/list-creatives.d.ts +129 -6
- package/dist/lib/types/schemas.generated.d.ts +411 -16
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +22 -6
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/types/schemas.generated.mjs +22 -6
- package/dist/lib/types/schemas.generated.mjs.map +1 -1
- package/dist/lib/types/tools.generated.d.mts +80 -6
- package/dist/lib/types/tools.generated.d.ts +80 -6
- package/dist/lib/types/tools.generated.d.ts.map +1 -1
- package/dist/lib/types/tools.generated.js.map +1 -1
- package/dist/lib/utils/adcp-version-config.d.mts +12 -0
- package/dist/lib/utils/adcp-version-config.d.ts +12 -0
- package/dist/lib/utils/adcp-version-config.d.ts.map +1 -1
- package/dist/lib/utils/adcp-version-config.js +5 -3
- package/dist/lib/utils/adcp-version-config.js.map +1 -1
- package/dist/lib/utils/adcp-version-config.mjs +4 -3
- package/dist/lib/utils/adcp-version-config.mjs.map +1 -1
- package/dist/lib/utils/pricing-adapter.d.mts +2 -0
- package/dist/lib/utils/pricing-adapter.d.ts +2 -0
- package/dist/lib/utils/pricing-adapter.d.ts.map +1 -1
- package/dist/lib/utils/pricing-adapter.js +68 -1
- package/dist/lib/utils/pricing-adapter.js.map +1 -1
- package/dist/lib/utils/pricing-adapter.mjs +67 -1
- package/dist/lib/utils/pricing-adapter.mjs.map +1 -1
- package/dist/lib/v2/projection/index.d.mts +1 -1
- package/dist/lib/v2/projection/index.d.ts +1 -1
- package/dist/lib/v2/projection/index.d.ts.map +1 -1
- package/dist/lib/v2/projection/index.js.map +1 -1
- package/dist/lib/v2/projection/index.mjs.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.d.mts +17 -3
- package/dist/lib/v2/projection/v1-to-v2.d.ts +17 -3
- package/dist/lib/v2/projection/v1-to-v2.d.ts.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.js.map +1 -1
- package/dist/lib/v2/projection/v1-to-v2.mjs.map +1 -1
- package/dist/lib/validation/schema-loader.d.mts +17 -0
- package/dist/lib/validation/schema-loader.d.ts +17 -0
- package/dist/lib/validation/schema-loader.d.ts.map +1 -1
- package/dist/lib/validation/schema-loader.js +24 -0
- package/dist/lib/validation/schema-loader.js.map +1 -1
- package/dist/lib/validation/schema-loader.mjs +23 -0
- package/dist/lib/validation/schema-loader.mjs.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/docs/llms.txt +2 -2
- package/docs/migration-13-to-14.md +59 -0
- package/package.json +1 -1
|
@@ -51,3 +51,15 @@ export declare function shouldOmit31Fields(resolvedClientVersion: string | undef
|
|
|
51
51
|
* Returns the original reference unchanged when `brand_kit_override` is absent.
|
|
52
52
|
*/
|
|
53
53
|
export declare function omit31BrandFields<T>(brand: T): T;
|
|
54
|
+
/**
|
|
55
|
+
* Filter `COMPATIBLE_ADCP_VERSIONS` to entries with a shipped bundle on this
|
|
56
|
+
* SDK build. The compatibility list is the historical set of accepted version
|
|
57
|
+
* strings (legacy aliases, superseded betas, current GA), but only a subset
|
|
58
|
+
* has bundles in `dist/lib/schemas-data/` at any given build. Returning
|
|
59
|
+
* "currently bundled: v2.5, v2.6, v3, 3.0.0-beta.3, 3.0.0, 3.0.1" would
|
|
60
|
+
* mislead a caller who pinned `'v2.5'` and got "no bundle".
|
|
61
|
+
*
|
|
62
|
+
* Always includes `ADCP_VERSION` even when its bundle hasn't been built yet
|
|
63
|
+
* (dev-tree case) so the error remains actionable on first build.
|
|
64
|
+
*/
|
|
65
|
+
export declare function listBundledAdcpVersions(): string[];
|
|
@@ -51,4 +51,16 @@ export declare function shouldOmit31Fields(resolvedClientVersion: string | undef
|
|
|
51
51
|
* Returns the original reference unchanged when `brand_kit_override` is absent.
|
|
52
52
|
*/
|
|
53
53
|
export declare function omit31BrandFields<T>(brand: T): T;
|
|
54
|
+
/**
|
|
55
|
+
* Filter `COMPATIBLE_ADCP_VERSIONS` to entries with a shipped bundle on this
|
|
56
|
+
* SDK build. The compatibility list is the historical set of accepted version
|
|
57
|
+
* strings (legacy aliases, superseded betas, current GA), but only a subset
|
|
58
|
+
* has bundles in `dist/lib/schemas-data/` at any given build. Returning
|
|
59
|
+
* "currently bundled: v2.5, v2.6, v3, 3.0.0-beta.3, 3.0.0, 3.0.1" would
|
|
60
|
+
* mislead a caller who pinned `'v2.5'` and got "no bundle".
|
|
61
|
+
*
|
|
62
|
+
* Always includes `ADCP_VERSION` even when its bundle hasn't been built yet
|
|
63
|
+
* (dev-tree case) so the error remains actionable on first build.
|
|
64
|
+
*/
|
|
65
|
+
export declare function listBundledAdcpVersions(): string[];
|
|
54
66
|
//# sourceMappingURL=adcp-version-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adcp-version-config.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/adcp-version-config.ts"],"names":[],"mappings":"AA0BA,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAK1F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CA4C1E;AAED,uFAAuF;AACvF,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG1E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,kBAAkB,UAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAqB1F;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CASrG;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAgBvE;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAgBvE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,SAAS,GACxG,OAAO,CAST;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,qBAAqB,EAAE,MAAM,GAAG,SAAS,EACzC,IAAI,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,SAAS,GACxG,OAAO,CAGT;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAMhD"}
|
|
1
|
+
{"version":3,"file":"adcp-version-config.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/adcp-version-config.ts"],"names":[],"mappings":"AA0BA,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAK1F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CA4C1E;AAED,uFAAuF;AACvF,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG1E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,kBAAkB,UAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAqB1F;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CASrG;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAgBvE;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAgBvE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,SAAS,GACxG,OAAO,CAST;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,qBAAqB,EAAE,MAAM,GAAG,SAAS,EACzC,IAAI,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,SAAS,GACxG,OAAO,CAGT;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAMhD;AAOD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAMlD"}
|
|
@@ -24,6 +24,7 @@ __export(adcp_version_config_exports, {
|
|
|
24
24
|
isMovingAdcpPrereleaseFamilyAlias: () => isMovingAdcpPrereleaseFamilyAlias,
|
|
25
25
|
isPre31AdcpVersion: () => isPre31AdcpVersion,
|
|
26
26
|
isPre32AdcpVersion: () => isPre32AdcpVersion,
|
|
27
|
+
listBundledAdcpVersions: () => listBundledAdcpVersions,
|
|
27
28
|
omit31BrandFields: () => omit31BrandFields,
|
|
28
29
|
resolveAdcpVersion: () => resolveAdcpVersion,
|
|
29
30
|
sellerAdvertises31: () => sellerAdvertises31,
|
|
@@ -58,7 +59,7 @@ function resolveAdcpVersion(adcpVersion) {
|
|
|
58
59
|
const major = (0, import_version.parseAdcpMajorVersion)(adcpVersion);
|
|
59
60
|
if (!Number.isFinite(major)) {
|
|
60
61
|
throw new import_errors.ConfigurationError(
|
|
61
|
-
`adcpVersion ${JSON.stringify(adcpVersion)} is not a valid AdCP version. Expected a semver string (e.g. '3.0.1', '3.1.0-beta.1') or a legacy alias. Currently bundled: ${
|
|
62
|
+
`adcpVersion ${JSON.stringify(adcpVersion)} is not a valid AdCP version. Expected a semver string (e.g. '3.0.1', '3.1.0-beta.1') or a legacy alias. Currently bundled: ${listBundledAdcpVersions().join(", ")}.`,
|
|
62
63
|
"adcpVersion"
|
|
63
64
|
);
|
|
64
65
|
}
|
|
@@ -66,7 +67,7 @@ function resolveAdcpVersion(adcpVersion) {
|
|
|
66
67
|
if (!(0, import_schema_loader.hasSchemaBundle)(adcpVersion)) {
|
|
67
68
|
const resolvedKey = (0, import_schema_loader.resolveBundleKey)(adcpVersion);
|
|
68
69
|
throw new import_errors.ConfigurationError(
|
|
69
|
-
`adcpVersion ${JSON.stringify(adcpVersion)} resolves to bundle key "${resolvedKey}", but no schema bundle for that key ships with this SDK build. Currently bundled: ${
|
|
70
|
+
`adcpVersion ${JSON.stringify(adcpVersion)} resolves to bundle key "${resolvedKey}", but no schema bundle for that key ships with this SDK build. Currently bundled: ${listBundledAdcpVersions().join(", ")}. If you're testing against a beta that the spec repo has tagged but the SDK hasn't synced yet, run \`npm run sync-schemas\` and \`npm run build:lib\` to populate the cache, then re-construct.`,
|
|
70
71
|
"adcpVersion"
|
|
71
72
|
);
|
|
72
73
|
}
|
|
@@ -158,7 +159,7 @@ function prereleaseFamilyAlias(version) {
|
|
|
158
159
|
const match = /^(\d+\.\d+-[0-9A-Za-z-]+)\.\d+$/.exec(version);
|
|
159
160
|
return match?.[1];
|
|
160
161
|
}
|
|
161
|
-
function
|
|
162
|
+
function listBundledAdcpVersions() {
|
|
162
163
|
const bundled = import_version.COMPATIBLE_ADCP_VERSIONS.filter((v) => (0, import_schema_loader.hasSchemaBundle)(v));
|
|
163
164
|
if (!bundled.includes(import_version.ADCP_VERSION)) {
|
|
164
165
|
return [import_version.ADCP_VERSION, ...bundled];
|
|
@@ -173,6 +174,7 @@ function listBundledVersions() {
|
|
|
173
174
|
isMovingAdcpPrereleaseFamilyAlias,
|
|
174
175
|
isPre31AdcpVersion,
|
|
175
176
|
isPre32AdcpVersion,
|
|
177
|
+
listBundledAdcpVersions,
|
|
176
178
|
omit31BrandFields,
|
|
177
179
|
resolveAdcpVersion,
|
|
178
180
|
sellerAdvertises31,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/utils/adcp-version-config.ts"],"sourcesContent":["// Validation helpers for the per-instance `adcpVersion` constructor option.\n//\n// Stage 2 plumbed the option onto every client/server constructor with a\n// fence: cross-major pins were rejected at construction because the wire\n// field and validators still keyed off the global `ADCP_MAJOR_VERSION`.\n//\n// Stage 3 lifts that fence. Validators now key off the resolved bundle in\n// `dist/lib/schemas-data/<MAJOR.MINOR>/`, and the protocol layer derives\n// the wire-level `adcp_major_version` from the per-instance pin. Construction\n// now accepts any pin that has a schema bundle reachable from the SDK build,\n// and rejects pins for which no bundle is present (`'4.0.0'` while the SDK\n// only ships major-3 schemas, mistyped versions, etc.) with a clear pointer\n// at `sync-schemas` + `build:lib`.\n\nimport { ADCP_VERSION, COMPATIBLE_ADCP_VERSIONS, parseAdcpMajorVersion } from '../version';\nimport { ConfigurationError } from '../errors';\nimport { hasSchemaBundle, resolveBundleKey, toReleasePrecisionWire } from '../validation/schema-loader';\nimport { gte as semverGte, valid as validSemver } from 'semver';\n\nfunction comparableAdcpSemver(version: string): string | undefined {\n const match = /^v?(\\d+)\\.(\\d+)(?:\\.(\\d+))?((?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)$/.exec(version.trim());\n if (!match) return undefined;\n const normalized = `${match[1]}.${match[2]}.${match[3] ?? '0'}${match[4] ?? ''}`;\n return validSemver(normalized) ?? undefined;\n}\n\n/** Compare full-semver and release-precision AdCP identifiers safely. */\nexport function isAdcpVersionAtLeast(version: string | undefined, minimum: string): boolean {\n if (version === undefined) return false;\n const comparable = comparableAdcpSemver(version);\n const comparableMinimum = comparableAdcpSemver(minimum);\n return comparable !== undefined && comparableMinimum !== undefined && semverGte(comparable, comparableMinimum);\n}\n\n/**\n * Resolve and validate a configured `adcpVersion`. Returns the value to store\n * on the instance — either the caller's pin or the SDK default.\n *\n * Throws `ConfigurationError` when:\n * - The pin is unparseable as a semver / legacy alias\n * - The pin parses but no schema bundle exists for the resolved key\n *\n * Cross-major pins are accepted as long as the corresponding bundle ships\n * with this SDK build (e.g. `'3.1.0-beta.1'` when `dist/lib/schemas-data/\n * 3.1.0-beta.1/` exists). Pins of the SDK's currently-pinned `ADCP_VERSION`\n * always succeed without an fs check — the bundle is guaranteed.\n */\nexport function resolveAdcpVersion(adcpVersion: string | undefined): string {\n if (adcpVersion === undefined) return ADCP_VERSION;\n\n const currentReleasePrecision = toReleasePrecisionWire(ADCP_VERSION);\n if (isMovingAdcpPrereleaseFamilyAlias(adcpVersion)) {\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} is a moving prerelease-family alias. ` +\n `Pin the exact 3.2 beta artifact (${JSON.stringify(currentReleasePrecision)}) instead.`,\n 'adcpVersion'\n );\n }\n\n const major = parseAdcpMajorVersion(adcpVersion);\n if (!Number.isFinite(major)) {\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} is not a valid AdCP version. ` +\n `Expected a semver string (e.g. '3.0.1', '3.1.0-beta.1') or a legacy alias. ` +\n `Currently bundled: ${listBundledVersions().join(', ')}.`,\n 'adcpVersion'\n );\n }\n\n // Skip the bundle-existence check when the pin resolves to the same bundle\n // as the SDK default — every published tarball includes that bundle by\n // construction. The bundle-key compare (rather than literal-string compare)\n // catches the common patterns: `'3.0'`, `'3.0.0'`, and `'3.0.1'` all\n // resolve to the same `'3.0'` bundle when `ADCP_VERSION === '3.0.1'`, so\n // none of those paths pay an fs round-trip.\n if (resolveBundleKey(adcpVersion) === resolveBundleKey(ADCP_VERSION)) return adcpVersion;\n\n if (!hasSchemaBundle(adcpVersion)) {\n const resolvedKey = resolveBundleKey(adcpVersion);\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} resolves to bundle key \"${resolvedKey}\", ` +\n `but no schema bundle for that key ships with this SDK build. ` +\n `Currently bundled: ${listBundledVersions().join(', ')}. ` +\n `If you're testing against a beta that the spec repo has tagged but the SDK hasn't synced yet, ` +\n `run \\`npm run sync-schemas\\` and \\`npm run build:lib\\` to populate the cache, ` +\n `then re-construct.`,\n 'adcpVersion'\n );\n }\n\n return adcpVersion;\n}\n\n/** Whether a value is the ambiguous moving family alias for the pinned 3.2 preview. */\nexport function isMovingAdcpPrereleaseFamilyAlias(version: string): boolean {\n if (!ADCP_VERSION.startsWith('3.2.0-')) return false;\n return prereleaseFamilyAlias(toReleasePrecisionWire(ADCP_VERSION)) === version;\n}\n\nexport function adcpVersionAliases(version: string, includeFamilyAlias = true): Set<string> {\n const aliases = new Set<string>([version]);\n const add = (value: string) => {\n aliases.add(value);\n if (includeFamilyAlias) {\n const family = prereleaseFamilyAlias(value);\n if (family && !(ADCP_VERSION.startsWith('3.2.0-') && family.startsWith('3.2-'))) aliases.add(family);\n }\n };\n\n try {\n add(resolveBundleKey(version));\n } catch {\n // Keep the raw version only; the caller will report the mismatch.\n }\n try {\n add(toReleasePrecisionWire(version));\n } catch {\n // Keep the raw version only; the caller will report the mismatch.\n }\n return aliases;\n}\n\nexport function isAdcpVersionSupported(version: string, supportedVersions: readonly string[]): boolean {\n if (supportedVersions.length === 0) return true;\n const aliases = adcpVersionAliases(version);\n return supportedVersions.some(v => {\n for (const supportedAlias of adcpVersionAliases(v, false)) {\n if (aliases.has(supportedAlias)) return true;\n }\n return false;\n });\n}\n\nexport function isPre31AdcpVersion(version: string | undefined): boolean {\n if (version === undefined) return false;\n const trimmed = version.trim();\n if (trimmed.length === 0) return false;\n\n const withoutLegacyPrefix = trimmed.startsWith('v') ? trimmed.slice(1) : trimmed;\n const match = /^(\\d+)(?:\\.(\\d+))?/.exec(withoutLegacyPrefix);\n if (!match?.[1]) return false;\n\n const major = Number.parseInt(match[1], 10);\n if (!Number.isFinite(major)) return false;\n if (major < 3) return true;\n if (major > 3) return false;\n\n const minor = match[2] === undefined ? 0 : Number.parseInt(match[2], 10);\n return Number.isFinite(minor) && minor < 1;\n}\n\n/** Whether a release pin predates the canonical creative identity surface in AdCP 3.2. */\nexport function isPre32AdcpVersion(version: string | undefined): boolean {\n if (version === undefined) return false;\n const trimmed = version.trim();\n if (trimmed.length === 0) return false;\n\n const withoutLegacyPrefix = trimmed.startsWith('v') ? trimmed.slice(1) : trimmed;\n const match = /^(\\d+)(?:\\.(\\d+))?/.exec(withoutLegacyPrefix);\n if (!match?.[1]) return false;\n\n const major = Number.parseInt(match[1], 10);\n if (!Number.isFinite(major)) return false;\n if (major < 3) return true;\n if (major > 3) return false;\n\n const minor = match[2] === undefined ? 0 : Number.parseInt(match[2], 10);\n return Number.isFinite(minor) && minor < 2;\n}\n\n/**\n * Does the seller authoritatively advertise AdCP 3.1+ support?\n *\n * `supportedVersions` is the negotiation field; the response envelope's\n * `adcp_version` is direct evidence of the wire release the seller just\n * served. `buildVersion` is advisory and MUST NOT select a wire shape.\n */\nexport function sellerAdvertises31(\n caps: { supportedVersions?: string[]; buildVersion?: string; _raw?: Record<string, unknown> } | undefined\n): boolean {\n if (!caps) return false;\n const supportedVersions = caps.supportedVersions ?? [];\n if (supportedVersions.length > 0) {\n return supportedVersions.some(v => !isPre31AdcpVersion(v));\n }\n const responseVersion = typeof caps._raw?.adcp_version === 'string' ? caps._raw.adcp_version : undefined;\n if (responseVersion !== undefined && !isPre31AdcpVersion(responseVersion)) return true;\n return false;\n}\n\n/**\n * Whether to omit AdCP 3.1-only request fields from the wire. Omit when the\n * client is pinned below 3.1, or when the seller does not advertise 3.1\n * support (legacy 3.0 sellers, and sellers whose capabilities were synthesized\n * from a tool list rather than declared).\n */\nexport function shouldOmit31Fields(\n resolvedClientVersion: string | undefined,\n caps: { supportedVersions?: string[]; buildVersion?: string; _raw?: Record<string, unknown> } | undefined\n): boolean {\n if (isPre31AdcpVersion(resolvedClientVersion)) return true;\n return !sellerAdvertises31(caps);\n}\n\n/**\n * Strip the AdCP 3.1-only `brand_kit_override` field from a BrandReference.\n * `industries` and `data_subject_contestation` are declared in AdCP 3.0 and\n * must be left on the wire for 3.0 sellers that accept and route on them.\n * Returns the original reference unchanged when `brand_kit_override` is absent.\n */\nexport function omit31BrandFields<T>(brand: T): T {\n if (!brand || typeof brand !== 'object' || Array.isArray(brand)) return brand;\n const b = brand as Record<string, unknown>;\n if (!('brand_kit_override' in b)) return brand;\n const { brand_kit_override, ...rest } = b;\n return rest as T;\n}\n\nfunction prereleaseFamilyAlias(version: string): string | undefined {\n const match = /^(\\d+\\.\\d+-[0-9A-Za-z-]+)\\.\\d+$/.exec(version);\n return match?.[1];\n}\n\n/**\n * Filter `COMPATIBLE_ADCP_VERSIONS` to entries with a shipped bundle on this\n * SDK build. The compatibility list is the historical set of accepted version\n * strings (legacy aliases, superseded betas, current GA), but only a subset\n * has bundles in `dist/lib/schemas-data/` at any given build. Returning\n * \"currently bundled: v2.5, v2.6, v3, 3.0.0-beta.3, 3.0.0, 3.0.1\" would\n * mislead a caller who pinned `'v2.5'` and got \"no bundle\".\n *\n * Always includes `ADCP_VERSION` even when its bundle hasn't been built yet\n * (dev-tree case) so the error remains actionable on first build.\n */\nfunction listBundledVersions(): string[] {\n const bundled = COMPATIBLE_ADCP_VERSIONS.filter(v => hasSchemaBundle(v));\n if (!bundled.includes(ADCP_VERSION as (typeof COMPATIBLE_ADCP_VERSIONS)[number])) {\n return [ADCP_VERSION, ...bundled];\n }\n return [...bundled];\n}\n"],"mappings":"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","names":["validSemver","semverGte"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils/adcp-version-config.ts"],"sourcesContent":["// Validation helpers for the per-instance `adcpVersion` constructor option.\n//\n// Stage 2 plumbed the option onto every client/server constructor with a\n// fence: cross-major pins were rejected at construction because the wire\n// field and validators still keyed off the global `ADCP_MAJOR_VERSION`.\n//\n// Stage 3 lifts that fence. Validators now key off the resolved bundle in\n// `dist/lib/schemas-data/<MAJOR.MINOR>/`, and the protocol layer derives\n// the wire-level `adcp_major_version` from the per-instance pin. Construction\n// now accepts any pin that has a schema bundle reachable from the SDK build,\n// and rejects pins for which no bundle is present (`'4.0.0'` while the SDK\n// only ships major-3 schemas, mistyped versions, etc.) with a clear pointer\n// at `sync-schemas` + `build:lib`.\n\nimport { ADCP_VERSION, COMPATIBLE_ADCP_VERSIONS, parseAdcpMajorVersion } from '../version';\nimport { ConfigurationError } from '../errors';\nimport { hasSchemaBundle, resolveBundleKey, toReleasePrecisionWire } from '../validation/schema-loader';\nimport { gte as semverGte, valid as validSemver } from 'semver';\n\nfunction comparableAdcpSemver(version: string): string | undefined {\n const match = /^v?(\\d+)\\.(\\d+)(?:\\.(\\d+))?((?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)$/.exec(version.trim());\n if (!match) return undefined;\n const normalized = `${match[1]}.${match[2]}.${match[3] ?? '0'}${match[4] ?? ''}`;\n return validSemver(normalized) ?? undefined;\n}\n\n/** Compare full-semver and release-precision AdCP identifiers safely. */\nexport function isAdcpVersionAtLeast(version: string | undefined, minimum: string): boolean {\n if (version === undefined) return false;\n const comparable = comparableAdcpSemver(version);\n const comparableMinimum = comparableAdcpSemver(minimum);\n return comparable !== undefined && comparableMinimum !== undefined && semverGte(comparable, comparableMinimum);\n}\n\n/**\n * Resolve and validate a configured `adcpVersion`. Returns the value to store\n * on the instance — either the caller's pin or the SDK default.\n *\n * Throws `ConfigurationError` when:\n * - The pin is unparseable as a semver / legacy alias\n * - The pin parses but no schema bundle exists for the resolved key\n *\n * Cross-major pins are accepted as long as the corresponding bundle ships\n * with this SDK build (e.g. `'3.1.0-beta.1'` when `dist/lib/schemas-data/\n * 3.1.0-beta.1/` exists). Pins of the SDK's currently-pinned `ADCP_VERSION`\n * always succeed without an fs check — the bundle is guaranteed.\n */\nexport function resolveAdcpVersion(adcpVersion: string | undefined): string {\n if (adcpVersion === undefined) return ADCP_VERSION;\n\n const currentReleasePrecision = toReleasePrecisionWire(ADCP_VERSION);\n if (isMovingAdcpPrereleaseFamilyAlias(adcpVersion)) {\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} is a moving prerelease-family alias. ` +\n `Pin the exact 3.2 beta artifact (${JSON.stringify(currentReleasePrecision)}) instead.`,\n 'adcpVersion'\n );\n }\n\n const major = parseAdcpMajorVersion(adcpVersion);\n if (!Number.isFinite(major)) {\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} is not a valid AdCP version. ` +\n `Expected a semver string (e.g. '3.0.1', '3.1.0-beta.1') or a legacy alias. ` +\n `Currently bundled: ${listBundledAdcpVersions().join(', ')}.`,\n 'adcpVersion'\n );\n }\n\n // Skip the bundle-existence check when the pin resolves to the same bundle\n // as the SDK default — every published tarball includes that bundle by\n // construction. The bundle-key compare (rather than literal-string compare)\n // catches the common patterns: `'3.0'`, `'3.0.0'`, and `'3.0.1'` all\n // resolve to the same `'3.0'` bundle when `ADCP_VERSION === '3.0.1'`, so\n // none of those paths pay an fs round-trip.\n if (resolveBundleKey(adcpVersion) === resolveBundleKey(ADCP_VERSION)) return adcpVersion;\n\n if (!hasSchemaBundle(adcpVersion)) {\n const resolvedKey = resolveBundleKey(adcpVersion);\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} resolves to bundle key \"${resolvedKey}\", ` +\n `but no schema bundle for that key ships with this SDK build. ` +\n `Currently bundled: ${listBundledAdcpVersions().join(', ')}. ` +\n `If you're testing against a beta that the spec repo has tagged but the SDK hasn't synced yet, ` +\n `run \\`npm run sync-schemas\\` and \\`npm run build:lib\\` to populate the cache, ` +\n `then re-construct.`,\n 'adcpVersion'\n );\n }\n\n return adcpVersion;\n}\n\n/** Whether a value is the ambiguous moving family alias for the pinned 3.2 preview. */\nexport function isMovingAdcpPrereleaseFamilyAlias(version: string): boolean {\n if (!ADCP_VERSION.startsWith('3.2.0-')) return false;\n return prereleaseFamilyAlias(toReleasePrecisionWire(ADCP_VERSION)) === version;\n}\n\nexport function adcpVersionAliases(version: string, includeFamilyAlias = true): Set<string> {\n const aliases = new Set<string>([version]);\n const add = (value: string) => {\n aliases.add(value);\n if (includeFamilyAlias) {\n const family = prereleaseFamilyAlias(value);\n if (family && !(ADCP_VERSION.startsWith('3.2.0-') && family.startsWith('3.2-'))) aliases.add(family);\n }\n };\n\n try {\n add(resolveBundleKey(version));\n } catch {\n // Keep the raw version only; the caller will report the mismatch.\n }\n try {\n add(toReleasePrecisionWire(version));\n } catch {\n // Keep the raw version only; the caller will report the mismatch.\n }\n return aliases;\n}\n\nexport function isAdcpVersionSupported(version: string, supportedVersions: readonly string[]): boolean {\n if (supportedVersions.length === 0) return true;\n const aliases = adcpVersionAliases(version);\n return supportedVersions.some(v => {\n for (const supportedAlias of adcpVersionAliases(v, false)) {\n if (aliases.has(supportedAlias)) return true;\n }\n return false;\n });\n}\n\nexport function isPre31AdcpVersion(version: string | undefined): boolean {\n if (version === undefined) return false;\n const trimmed = version.trim();\n if (trimmed.length === 0) return false;\n\n const withoutLegacyPrefix = trimmed.startsWith('v') ? trimmed.slice(1) : trimmed;\n const match = /^(\\d+)(?:\\.(\\d+))?/.exec(withoutLegacyPrefix);\n if (!match?.[1]) return false;\n\n const major = Number.parseInt(match[1], 10);\n if (!Number.isFinite(major)) return false;\n if (major < 3) return true;\n if (major > 3) return false;\n\n const minor = match[2] === undefined ? 0 : Number.parseInt(match[2], 10);\n return Number.isFinite(minor) && minor < 1;\n}\n\n/** Whether a release pin predates the canonical creative identity surface in AdCP 3.2. */\nexport function isPre32AdcpVersion(version: string | undefined): boolean {\n if (version === undefined) return false;\n const trimmed = version.trim();\n if (trimmed.length === 0) return false;\n\n const withoutLegacyPrefix = trimmed.startsWith('v') ? trimmed.slice(1) : trimmed;\n const match = /^(\\d+)(?:\\.(\\d+))?/.exec(withoutLegacyPrefix);\n if (!match?.[1]) return false;\n\n const major = Number.parseInt(match[1], 10);\n if (!Number.isFinite(major)) return false;\n if (major < 3) return true;\n if (major > 3) return false;\n\n const minor = match[2] === undefined ? 0 : Number.parseInt(match[2], 10);\n return Number.isFinite(minor) && minor < 2;\n}\n\n/**\n * Does the seller authoritatively advertise AdCP 3.1+ support?\n *\n * `supportedVersions` is the negotiation field; the response envelope's\n * `adcp_version` is direct evidence of the wire release the seller just\n * served. `buildVersion` is advisory and MUST NOT select a wire shape.\n */\nexport function sellerAdvertises31(\n caps: { supportedVersions?: string[]; buildVersion?: string; _raw?: Record<string, unknown> } | undefined\n): boolean {\n if (!caps) return false;\n const supportedVersions = caps.supportedVersions ?? [];\n if (supportedVersions.length > 0) {\n return supportedVersions.some(v => !isPre31AdcpVersion(v));\n }\n const responseVersion = typeof caps._raw?.adcp_version === 'string' ? caps._raw.adcp_version : undefined;\n if (responseVersion !== undefined && !isPre31AdcpVersion(responseVersion)) return true;\n return false;\n}\n\n/**\n * Whether to omit AdCP 3.1-only request fields from the wire. Omit when the\n * client is pinned below 3.1, or when the seller does not advertise 3.1\n * support (legacy 3.0 sellers, and sellers whose capabilities were synthesized\n * from a tool list rather than declared).\n */\nexport function shouldOmit31Fields(\n resolvedClientVersion: string | undefined,\n caps: { supportedVersions?: string[]; buildVersion?: string; _raw?: Record<string, unknown> } | undefined\n): boolean {\n if (isPre31AdcpVersion(resolvedClientVersion)) return true;\n return !sellerAdvertises31(caps);\n}\n\n/**\n * Strip the AdCP 3.1-only `brand_kit_override` field from a BrandReference.\n * `industries` and `data_subject_contestation` are declared in AdCP 3.0 and\n * must be left on the wire for 3.0 sellers that accept and route on them.\n * Returns the original reference unchanged when `brand_kit_override` is absent.\n */\nexport function omit31BrandFields<T>(brand: T): T {\n if (!brand || typeof brand !== 'object' || Array.isArray(brand)) return brand;\n const b = brand as Record<string, unknown>;\n if (!('brand_kit_override' in b)) return brand;\n const { brand_kit_override, ...rest } = b;\n return rest as T;\n}\n\nfunction prereleaseFamilyAlias(version: string): string | undefined {\n const match = /^(\\d+\\.\\d+-[0-9A-Za-z-]+)\\.\\d+$/.exec(version);\n return match?.[1];\n}\n\n/**\n * Filter `COMPATIBLE_ADCP_VERSIONS` to entries with a shipped bundle on this\n * SDK build. The compatibility list is the historical set of accepted version\n * strings (legacy aliases, superseded betas, current GA), but only a subset\n * has bundles in `dist/lib/schemas-data/` at any given build. Returning\n * \"currently bundled: v2.5, v2.6, v3, 3.0.0-beta.3, 3.0.0, 3.0.1\" would\n * mislead a caller who pinned `'v2.5'` and got \"no bundle\".\n *\n * Always includes `ADCP_VERSION` even when its bundle hasn't been built yet\n * (dev-tree case) so the error remains actionable on first build.\n */\nexport function listBundledAdcpVersions(): string[] {\n const bundled = COMPATIBLE_ADCP_VERSIONS.filter(v => hasSchemaBundle(v));\n if (!bundled.includes(ADCP_VERSION as (typeof COMPATIBLE_ADCP_VERSIONS)[number])) {\n return [ADCP_VERSION, ...bundled];\n }\n return [...bundled];\n}\n"],"mappings":"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","names":["validSemver","semverGte"]}
|
|
@@ -26,7 +26,7 @@ function resolveAdcpVersion(adcpVersion) {
|
|
|
26
26
|
const major = parseAdcpMajorVersion(adcpVersion);
|
|
27
27
|
if (!Number.isFinite(major)) {
|
|
28
28
|
throw new ConfigurationError(
|
|
29
|
-
`adcpVersion ${JSON.stringify(adcpVersion)} is not a valid AdCP version. Expected a semver string (e.g. '3.0.1', '3.1.0-beta.1') or a legacy alias. Currently bundled: ${
|
|
29
|
+
`adcpVersion ${JSON.stringify(adcpVersion)} is not a valid AdCP version. Expected a semver string (e.g. '3.0.1', '3.1.0-beta.1') or a legacy alias. Currently bundled: ${listBundledAdcpVersions().join(", ")}.`,
|
|
30
30
|
"adcpVersion"
|
|
31
31
|
);
|
|
32
32
|
}
|
|
@@ -34,7 +34,7 @@ function resolveAdcpVersion(adcpVersion) {
|
|
|
34
34
|
if (!hasSchemaBundle(adcpVersion)) {
|
|
35
35
|
const resolvedKey = resolveBundleKey(adcpVersion);
|
|
36
36
|
throw new ConfigurationError(
|
|
37
|
-
`adcpVersion ${JSON.stringify(adcpVersion)} resolves to bundle key "${resolvedKey}", but no schema bundle for that key ships with this SDK build. Currently bundled: ${
|
|
37
|
+
`adcpVersion ${JSON.stringify(adcpVersion)} resolves to bundle key "${resolvedKey}", but no schema bundle for that key ships with this SDK build. Currently bundled: ${listBundledAdcpVersions().join(", ")}. If you're testing against a beta that the spec repo has tagged but the SDK hasn't synced yet, run \`npm run sync-schemas\` and \`npm run build:lib\` to populate the cache, then re-construct.`,
|
|
38
38
|
"adcpVersion"
|
|
39
39
|
);
|
|
40
40
|
}
|
|
@@ -126,7 +126,7 @@ function prereleaseFamilyAlias(version) {
|
|
|
126
126
|
const match = /^(\d+\.\d+-[0-9A-Za-z-]+)\.\d+$/.exec(version);
|
|
127
127
|
return match?.[1];
|
|
128
128
|
}
|
|
129
|
-
function
|
|
129
|
+
function listBundledAdcpVersions() {
|
|
130
130
|
const bundled = COMPATIBLE_ADCP_VERSIONS.filter((v) => hasSchemaBundle(v));
|
|
131
131
|
if (!bundled.includes(ADCP_VERSION)) {
|
|
132
132
|
return [ADCP_VERSION, ...bundled];
|
|
@@ -140,6 +140,7 @@ export {
|
|
|
140
140
|
isMovingAdcpPrereleaseFamilyAlias,
|
|
141
141
|
isPre31AdcpVersion,
|
|
142
142
|
isPre32AdcpVersion,
|
|
143
|
+
listBundledAdcpVersions,
|
|
143
144
|
omit31BrandFields,
|
|
144
145
|
resolveAdcpVersion,
|
|
145
146
|
sellerAdvertises31,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/utils/adcp-version-config.ts"],"sourcesContent":["// Validation helpers for the per-instance `adcpVersion` constructor option.\n//\n// Stage 2 plumbed the option onto every client/server constructor with a\n// fence: cross-major pins were rejected at construction because the wire\n// field and validators still keyed off the global `ADCP_MAJOR_VERSION`.\n//\n// Stage 3 lifts that fence. Validators now key off the resolved bundle in\n// `dist/lib/schemas-data/<MAJOR.MINOR>/`, and the protocol layer derives\n// the wire-level `adcp_major_version` from the per-instance pin. Construction\n// now accepts any pin that has a schema bundle reachable from the SDK build,\n// and rejects pins for which no bundle is present (`'4.0.0'` while the SDK\n// only ships major-3 schemas, mistyped versions, etc.) with a clear pointer\n// at `sync-schemas` + `build:lib`.\n\nimport { ADCP_VERSION, COMPATIBLE_ADCP_VERSIONS, parseAdcpMajorVersion } from '../version';\nimport { ConfigurationError } from '../errors';\nimport { hasSchemaBundle, resolveBundleKey, toReleasePrecisionWire } from '../validation/schema-loader';\nimport { gte as semverGte, valid as validSemver } from 'semver';\n\nfunction comparableAdcpSemver(version: string): string | undefined {\n const match = /^v?(\\d+)\\.(\\d+)(?:\\.(\\d+))?((?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)$/.exec(version.trim());\n if (!match) return undefined;\n const normalized = `${match[1]}.${match[2]}.${match[3] ?? '0'}${match[4] ?? ''}`;\n return validSemver(normalized) ?? undefined;\n}\n\n/** Compare full-semver and release-precision AdCP identifiers safely. */\nexport function isAdcpVersionAtLeast(version: string | undefined, minimum: string): boolean {\n if (version === undefined) return false;\n const comparable = comparableAdcpSemver(version);\n const comparableMinimum = comparableAdcpSemver(minimum);\n return comparable !== undefined && comparableMinimum !== undefined && semverGte(comparable, comparableMinimum);\n}\n\n/**\n * Resolve and validate a configured `adcpVersion`. Returns the value to store\n * on the instance — either the caller's pin or the SDK default.\n *\n * Throws `ConfigurationError` when:\n * - The pin is unparseable as a semver / legacy alias\n * - The pin parses but no schema bundle exists for the resolved key\n *\n * Cross-major pins are accepted as long as the corresponding bundle ships\n * with this SDK build (e.g. `'3.1.0-beta.1'` when `dist/lib/schemas-data/\n * 3.1.0-beta.1/` exists). Pins of the SDK's currently-pinned `ADCP_VERSION`\n * always succeed without an fs check — the bundle is guaranteed.\n */\nexport function resolveAdcpVersion(adcpVersion: string | undefined): string {\n if (adcpVersion === undefined) return ADCP_VERSION;\n\n const currentReleasePrecision = toReleasePrecisionWire(ADCP_VERSION);\n if (isMovingAdcpPrereleaseFamilyAlias(adcpVersion)) {\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} is a moving prerelease-family alias. ` +\n `Pin the exact 3.2 beta artifact (${JSON.stringify(currentReleasePrecision)}) instead.`,\n 'adcpVersion'\n );\n }\n\n const major = parseAdcpMajorVersion(adcpVersion);\n if (!Number.isFinite(major)) {\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} is not a valid AdCP version. ` +\n `Expected a semver string (e.g. '3.0.1', '3.1.0-beta.1') or a legacy alias. ` +\n `Currently bundled: ${listBundledVersions().join(', ')}.`,\n 'adcpVersion'\n );\n }\n\n // Skip the bundle-existence check when the pin resolves to the same bundle\n // as the SDK default — every published tarball includes that bundle by\n // construction. The bundle-key compare (rather than literal-string compare)\n // catches the common patterns: `'3.0'`, `'3.0.0'`, and `'3.0.1'` all\n // resolve to the same `'3.0'` bundle when `ADCP_VERSION === '3.0.1'`, so\n // none of those paths pay an fs round-trip.\n if (resolveBundleKey(adcpVersion) === resolveBundleKey(ADCP_VERSION)) return adcpVersion;\n\n if (!hasSchemaBundle(adcpVersion)) {\n const resolvedKey = resolveBundleKey(adcpVersion);\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} resolves to bundle key \"${resolvedKey}\", ` +\n `but no schema bundle for that key ships with this SDK build. ` +\n `Currently bundled: ${listBundledVersions().join(', ')}. ` +\n `If you're testing against a beta that the spec repo has tagged but the SDK hasn't synced yet, ` +\n `run \\`npm run sync-schemas\\` and \\`npm run build:lib\\` to populate the cache, ` +\n `then re-construct.`,\n 'adcpVersion'\n );\n }\n\n return adcpVersion;\n}\n\n/** Whether a value is the ambiguous moving family alias for the pinned 3.2 preview. */\nexport function isMovingAdcpPrereleaseFamilyAlias(version: string): boolean {\n if (!ADCP_VERSION.startsWith('3.2.0-')) return false;\n return prereleaseFamilyAlias(toReleasePrecisionWire(ADCP_VERSION)) === version;\n}\n\nexport function adcpVersionAliases(version: string, includeFamilyAlias = true): Set<string> {\n const aliases = new Set<string>([version]);\n const add = (value: string) => {\n aliases.add(value);\n if (includeFamilyAlias) {\n const family = prereleaseFamilyAlias(value);\n if (family && !(ADCP_VERSION.startsWith('3.2.0-') && family.startsWith('3.2-'))) aliases.add(family);\n }\n };\n\n try {\n add(resolveBundleKey(version));\n } catch {\n // Keep the raw version only; the caller will report the mismatch.\n }\n try {\n add(toReleasePrecisionWire(version));\n } catch {\n // Keep the raw version only; the caller will report the mismatch.\n }\n return aliases;\n}\n\nexport function isAdcpVersionSupported(version: string, supportedVersions: readonly string[]): boolean {\n if (supportedVersions.length === 0) return true;\n const aliases = adcpVersionAliases(version);\n return supportedVersions.some(v => {\n for (const supportedAlias of adcpVersionAliases(v, false)) {\n if (aliases.has(supportedAlias)) return true;\n }\n return false;\n });\n}\n\nexport function isPre31AdcpVersion(version: string | undefined): boolean {\n if (version === undefined) return false;\n const trimmed = version.trim();\n if (trimmed.length === 0) return false;\n\n const withoutLegacyPrefix = trimmed.startsWith('v') ? trimmed.slice(1) : trimmed;\n const match = /^(\\d+)(?:\\.(\\d+))?/.exec(withoutLegacyPrefix);\n if (!match?.[1]) return false;\n\n const major = Number.parseInt(match[1], 10);\n if (!Number.isFinite(major)) return false;\n if (major < 3) return true;\n if (major > 3) return false;\n\n const minor = match[2] === undefined ? 0 : Number.parseInt(match[2], 10);\n return Number.isFinite(minor) && minor < 1;\n}\n\n/** Whether a release pin predates the canonical creative identity surface in AdCP 3.2. */\nexport function isPre32AdcpVersion(version: string | undefined): boolean {\n if (version === undefined) return false;\n const trimmed = version.trim();\n if (trimmed.length === 0) return false;\n\n const withoutLegacyPrefix = trimmed.startsWith('v') ? trimmed.slice(1) : trimmed;\n const match = /^(\\d+)(?:\\.(\\d+))?/.exec(withoutLegacyPrefix);\n if (!match?.[1]) return false;\n\n const major = Number.parseInt(match[1], 10);\n if (!Number.isFinite(major)) return false;\n if (major < 3) return true;\n if (major > 3) return false;\n\n const minor = match[2] === undefined ? 0 : Number.parseInt(match[2], 10);\n return Number.isFinite(minor) && minor < 2;\n}\n\n/**\n * Does the seller authoritatively advertise AdCP 3.1+ support?\n *\n * `supportedVersions` is the negotiation field; the response envelope's\n * `adcp_version` is direct evidence of the wire release the seller just\n * served. `buildVersion` is advisory and MUST NOT select a wire shape.\n */\nexport function sellerAdvertises31(\n caps: { supportedVersions?: string[]; buildVersion?: string; _raw?: Record<string, unknown> } | undefined\n): boolean {\n if (!caps) return false;\n const supportedVersions = caps.supportedVersions ?? [];\n if (supportedVersions.length > 0) {\n return supportedVersions.some(v => !isPre31AdcpVersion(v));\n }\n const responseVersion = typeof caps._raw?.adcp_version === 'string' ? caps._raw.adcp_version : undefined;\n if (responseVersion !== undefined && !isPre31AdcpVersion(responseVersion)) return true;\n return false;\n}\n\n/**\n * Whether to omit AdCP 3.1-only request fields from the wire. Omit when the\n * client is pinned below 3.1, or when the seller does not advertise 3.1\n * support (legacy 3.0 sellers, and sellers whose capabilities were synthesized\n * from a tool list rather than declared).\n */\nexport function shouldOmit31Fields(\n resolvedClientVersion: string | undefined,\n caps: { supportedVersions?: string[]; buildVersion?: string; _raw?: Record<string, unknown> } | undefined\n): boolean {\n if (isPre31AdcpVersion(resolvedClientVersion)) return true;\n return !sellerAdvertises31(caps);\n}\n\n/**\n * Strip the AdCP 3.1-only `brand_kit_override` field from a BrandReference.\n * `industries` and `data_subject_contestation` are declared in AdCP 3.0 and\n * must be left on the wire for 3.0 sellers that accept and route on them.\n * Returns the original reference unchanged when `brand_kit_override` is absent.\n */\nexport function omit31BrandFields<T>(brand: T): T {\n if (!brand || typeof brand !== 'object' || Array.isArray(brand)) return brand;\n const b = brand as Record<string, unknown>;\n if (!('brand_kit_override' in b)) return brand;\n const { brand_kit_override, ...rest } = b;\n return rest as T;\n}\n\nfunction prereleaseFamilyAlias(version: string): string | undefined {\n const match = /^(\\d+\\.\\d+-[0-9A-Za-z-]+)\\.\\d+$/.exec(version);\n return match?.[1];\n}\n\n/**\n * Filter `COMPATIBLE_ADCP_VERSIONS` to entries with a shipped bundle on this\n * SDK build. The compatibility list is the historical set of accepted version\n * strings (legacy aliases, superseded betas, current GA), but only a subset\n * has bundles in `dist/lib/schemas-data/` at any given build. Returning\n * \"currently bundled: v2.5, v2.6, v3, 3.0.0-beta.3, 3.0.0, 3.0.1\" would\n * mislead a caller who pinned `'v2.5'` and got \"no bundle\".\n *\n * Always includes `ADCP_VERSION` even when its bundle hasn't been built yet\n * (dev-tree case) so the error remains actionable on first build.\n */\nfunction listBundledVersions(): string[] {\n const bundled = COMPATIBLE_ADCP_VERSIONS.filter(v => hasSchemaBundle(v));\n if (!bundled.includes(ADCP_VERSION as (typeof COMPATIBLE_ADCP_VERSIONS)[number])) {\n return [ADCP_VERSION, ...bundled];\n }\n return [...bundled];\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils/adcp-version-config.ts"],"sourcesContent":["// Validation helpers for the per-instance `adcpVersion` constructor option.\n//\n// Stage 2 plumbed the option onto every client/server constructor with a\n// fence: cross-major pins were rejected at construction because the wire\n// field and validators still keyed off the global `ADCP_MAJOR_VERSION`.\n//\n// Stage 3 lifts that fence. Validators now key off the resolved bundle in\n// `dist/lib/schemas-data/<MAJOR.MINOR>/`, and the protocol layer derives\n// the wire-level `adcp_major_version` from the per-instance pin. Construction\n// now accepts any pin that has a schema bundle reachable from the SDK build,\n// and rejects pins for which no bundle is present (`'4.0.0'` while the SDK\n// only ships major-3 schemas, mistyped versions, etc.) with a clear pointer\n// at `sync-schemas` + `build:lib`.\n\nimport { ADCP_VERSION, COMPATIBLE_ADCP_VERSIONS, parseAdcpMajorVersion } from '../version';\nimport { ConfigurationError } from '../errors';\nimport { hasSchemaBundle, resolveBundleKey, toReleasePrecisionWire } from '../validation/schema-loader';\nimport { gte as semverGte, valid as validSemver } from 'semver';\n\nfunction comparableAdcpSemver(version: string): string | undefined {\n const match = /^v?(\\d+)\\.(\\d+)(?:\\.(\\d+))?((?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)$/.exec(version.trim());\n if (!match) return undefined;\n const normalized = `${match[1]}.${match[2]}.${match[3] ?? '0'}${match[4] ?? ''}`;\n return validSemver(normalized) ?? undefined;\n}\n\n/** Compare full-semver and release-precision AdCP identifiers safely. */\nexport function isAdcpVersionAtLeast(version: string | undefined, minimum: string): boolean {\n if (version === undefined) return false;\n const comparable = comparableAdcpSemver(version);\n const comparableMinimum = comparableAdcpSemver(minimum);\n return comparable !== undefined && comparableMinimum !== undefined && semverGte(comparable, comparableMinimum);\n}\n\n/**\n * Resolve and validate a configured `adcpVersion`. Returns the value to store\n * on the instance — either the caller's pin or the SDK default.\n *\n * Throws `ConfigurationError` when:\n * - The pin is unparseable as a semver / legacy alias\n * - The pin parses but no schema bundle exists for the resolved key\n *\n * Cross-major pins are accepted as long as the corresponding bundle ships\n * with this SDK build (e.g. `'3.1.0-beta.1'` when `dist/lib/schemas-data/\n * 3.1.0-beta.1/` exists). Pins of the SDK's currently-pinned `ADCP_VERSION`\n * always succeed without an fs check — the bundle is guaranteed.\n */\nexport function resolveAdcpVersion(adcpVersion: string | undefined): string {\n if (adcpVersion === undefined) return ADCP_VERSION;\n\n const currentReleasePrecision = toReleasePrecisionWire(ADCP_VERSION);\n if (isMovingAdcpPrereleaseFamilyAlias(adcpVersion)) {\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} is a moving prerelease-family alias. ` +\n `Pin the exact 3.2 beta artifact (${JSON.stringify(currentReleasePrecision)}) instead.`,\n 'adcpVersion'\n );\n }\n\n const major = parseAdcpMajorVersion(adcpVersion);\n if (!Number.isFinite(major)) {\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} is not a valid AdCP version. ` +\n `Expected a semver string (e.g. '3.0.1', '3.1.0-beta.1') or a legacy alias. ` +\n `Currently bundled: ${listBundledAdcpVersions().join(', ')}.`,\n 'adcpVersion'\n );\n }\n\n // Skip the bundle-existence check when the pin resolves to the same bundle\n // as the SDK default — every published tarball includes that bundle by\n // construction. The bundle-key compare (rather than literal-string compare)\n // catches the common patterns: `'3.0'`, `'3.0.0'`, and `'3.0.1'` all\n // resolve to the same `'3.0'` bundle when `ADCP_VERSION === '3.0.1'`, so\n // none of those paths pay an fs round-trip.\n if (resolveBundleKey(adcpVersion) === resolveBundleKey(ADCP_VERSION)) return adcpVersion;\n\n if (!hasSchemaBundle(adcpVersion)) {\n const resolvedKey = resolveBundleKey(adcpVersion);\n throw new ConfigurationError(\n `adcpVersion ${JSON.stringify(adcpVersion)} resolves to bundle key \"${resolvedKey}\", ` +\n `but no schema bundle for that key ships with this SDK build. ` +\n `Currently bundled: ${listBundledAdcpVersions().join(', ')}. ` +\n `If you're testing against a beta that the spec repo has tagged but the SDK hasn't synced yet, ` +\n `run \\`npm run sync-schemas\\` and \\`npm run build:lib\\` to populate the cache, ` +\n `then re-construct.`,\n 'adcpVersion'\n );\n }\n\n return adcpVersion;\n}\n\n/** Whether a value is the ambiguous moving family alias for the pinned 3.2 preview. */\nexport function isMovingAdcpPrereleaseFamilyAlias(version: string): boolean {\n if (!ADCP_VERSION.startsWith('3.2.0-')) return false;\n return prereleaseFamilyAlias(toReleasePrecisionWire(ADCP_VERSION)) === version;\n}\n\nexport function adcpVersionAliases(version: string, includeFamilyAlias = true): Set<string> {\n const aliases = new Set<string>([version]);\n const add = (value: string) => {\n aliases.add(value);\n if (includeFamilyAlias) {\n const family = prereleaseFamilyAlias(value);\n if (family && !(ADCP_VERSION.startsWith('3.2.0-') && family.startsWith('3.2-'))) aliases.add(family);\n }\n };\n\n try {\n add(resolveBundleKey(version));\n } catch {\n // Keep the raw version only; the caller will report the mismatch.\n }\n try {\n add(toReleasePrecisionWire(version));\n } catch {\n // Keep the raw version only; the caller will report the mismatch.\n }\n return aliases;\n}\n\nexport function isAdcpVersionSupported(version: string, supportedVersions: readonly string[]): boolean {\n if (supportedVersions.length === 0) return true;\n const aliases = adcpVersionAliases(version);\n return supportedVersions.some(v => {\n for (const supportedAlias of adcpVersionAliases(v, false)) {\n if (aliases.has(supportedAlias)) return true;\n }\n return false;\n });\n}\n\nexport function isPre31AdcpVersion(version: string | undefined): boolean {\n if (version === undefined) return false;\n const trimmed = version.trim();\n if (trimmed.length === 0) return false;\n\n const withoutLegacyPrefix = trimmed.startsWith('v') ? trimmed.slice(1) : trimmed;\n const match = /^(\\d+)(?:\\.(\\d+))?/.exec(withoutLegacyPrefix);\n if (!match?.[1]) return false;\n\n const major = Number.parseInt(match[1], 10);\n if (!Number.isFinite(major)) return false;\n if (major < 3) return true;\n if (major > 3) return false;\n\n const minor = match[2] === undefined ? 0 : Number.parseInt(match[2], 10);\n return Number.isFinite(minor) && minor < 1;\n}\n\n/** Whether a release pin predates the canonical creative identity surface in AdCP 3.2. */\nexport function isPre32AdcpVersion(version: string | undefined): boolean {\n if (version === undefined) return false;\n const trimmed = version.trim();\n if (trimmed.length === 0) return false;\n\n const withoutLegacyPrefix = trimmed.startsWith('v') ? trimmed.slice(1) : trimmed;\n const match = /^(\\d+)(?:\\.(\\d+))?/.exec(withoutLegacyPrefix);\n if (!match?.[1]) return false;\n\n const major = Number.parseInt(match[1], 10);\n if (!Number.isFinite(major)) return false;\n if (major < 3) return true;\n if (major > 3) return false;\n\n const minor = match[2] === undefined ? 0 : Number.parseInt(match[2], 10);\n return Number.isFinite(minor) && minor < 2;\n}\n\n/**\n * Does the seller authoritatively advertise AdCP 3.1+ support?\n *\n * `supportedVersions` is the negotiation field; the response envelope's\n * `adcp_version` is direct evidence of the wire release the seller just\n * served. `buildVersion` is advisory and MUST NOT select a wire shape.\n */\nexport function sellerAdvertises31(\n caps: { supportedVersions?: string[]; buildVersion?: string; _raw?: Record<string, unknown> } | undefined\n): boolean {\n if (!caps) return false;\n const supportedVersions = caps.supportedVersions ?? [];\n if (supportedVersions.length > 0) {\n return supportedVersions.some(v => !isPre31AdcpVersion(v));\n }\n const responseVersion = typeof caps._raw?.adcp_version === 'string' ? caps._raw.adcp_version : undefined;\n if (responseVersion !== undefined && !isPre31AdcpVersion(responseVersion)) return true;\n return false;\n}\n\n/**\n * Whether to omit AdCP 3.1-only request fields from the wire. Omit when the\n * client is pinned below 3.1, or when the seller does not advertise 3.1\n * support (legacy 3.0 sellers, and sellers whose capabilities were synthesized\n * from a tool list rather than declared).\n */\nexport function shouldOmit31Fields(\n resolvedClientVersion: string | undefined,\n caps: { supportedVersions?: string[]; buildVersion?: string; _raw?: Record<string, unknown> } | undefined\n): boolean {\n if (isPre31AdcpVersion(resolvedClientVersion)) return true;\n return !sellerAdvertises31(caps);\n}\n\n/**\n * Strip the AdCP 3.1-only `brand_kit_override` field from a BrandReference.\n * `industries` and `data_subject_contestation` are declared in AdCP 3.0 and\n * must be left on the wire for 3.0 sellers that accept and route on them.\n * Returns the original reference unchanged when `brand_kit_override` is absent.\n */\nexport function omit31BrandFields<T>(brand: T): T {\n if (!brand || typeof brand !== 'object' || Array.isArray(brand)) return brand;\n const b = brand as Record<string, unknown>;\n if (!('brand_kit_override' in b)) return brand;\n const { brand_kit_override, ...rest } = b;\n return rest as T;\n}\n\nfunction prereleaseFamilyAlias(version: string): string | undefined {\n const match = /^(\\d+\\.\\d+-[0-9A-Za-z-]+)\\.\\d+$/.exec(version);\n return match?.[1];\n}\n\n/**\n * Filter `COMPATIBLE_ADCP_VERSIONS` to entries with a shipped bundle on this\n * SDK build. The compatibility list is the historical set of accepted version\n * strings (legacy aliases, superseded betas, current GA), but only a subset\n * has bundles in `dist/lib/schemas-data/` at any given build. Returning\n * \"currently bundled: v2.5, v2.6, v3, 3.0.0-beta.3, 3.0.0, 3.0.1\" would\n * mislead a caller who pinned `'v2.5'` and got \"no bundle\".\n *\n * Always includes `ADCP_VERSION` even when its bundle hasn't been built yet\n * (dev-tree case) so the error remains actionable on first build.\n */\nexport function listBundledAdcpVersions(): string[] {\n const bundled = COMPATIBLE_ADCP_VERSIONS.filter(v => hasSchemaBundle(v));\n if (!bundled.includes(ADCP_VERSION as (typeof COMPATIBLE_ADCP_VERSIONS)[number])) {\n return [ADCP_VERSION, ...bundled];\n }\n return [...bundled];\n}\n"],"mappings":"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","names":[]}
|
|
@@ -124,6 +124,8 @@ export declare function adaptGetProductsRequestForV2(request: any): any;
|
|
|
124
124
|
* v2 used coarser buckets; some map one-to-many (e.g. 'video' → ['olv', 'ctv']).
|
|
125
125
|
*/
|
|
126
126
|
export declare function normalizeProductChannels(product: any): any;
|
|
127
|
+
/** Normalize optional forecast timestamps at the v2.5 compatibility boundary. */
|
|
128
|
+
export declare function normalizeLegacyProductForecast(product: any): any;
|
|
127
129
|
/**
|
|
128
130
|
* Normalize all products in a get_products response to v3
|
|
129
131
|
*/
|
|
@@ -124,6 +124,8 @@ export declare function adaptGetProductsRequestForV2(request: any): any;
|
|
|
124
124
|
* v2 used coarser buckets; some map one-to-many (e.g. 'video' → ['olv', 'ctv']).
|
|
125
125
|
*/
|
|
126
126
|
export declare function normalizeProductChannels(product: any): any;
|
|
127
|
+
/** Normalize optional forecast timestamps at the v2.5 compatibility boundary. */
|
|
128
|
+
export declare function normalizeLegacyProductForecast(product: any): any;
|
|
127
129
|
/**
|
|
128
130
|
* Normalize all products in a get_products response to v3
|
|
129
131
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing-adapter.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/pricing-adapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"pricing-adapter.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/pricing-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,6 +28,7 @@ __export(pricing_adapter_exports, {
|
|
|
28
28
|
isCPAPricing: () => isCPAPricing,
|
|
29
29
|
isFixedPricing: () => isFixedPricing,
|
|
30
30
|
normalizeGetProductsResponse: () => normalizeGetProductsResponse,
|
|
31
|
+
normalizeLegacyProductForecast: () => normalizeLegacyProductForecast,
|
|
31
32
|
normalizeMediaBuyPricingResponse: () => normalizeMediaBuyPricingResponse,
|
|
32
33
|
normalizePricingOption: () => normalizePricingOption,
|
|
33
34
|
normalizeProductChannels: () => normalizeProductChannels,
|
|
@@ -203,6 +204,69 @@ function normalizeProductChannels(product) {
|
|
|
203
204
|
const normalized = product.channels.flatMap((ch) => v3ChannelMap[ch] ?? [ch]);
|
|
204
205
|
return { ...product, channels: [...new Set(normalized)] };
|
|
205
206
|
}
|
|
207
|
+
const LEGACY_ZONED_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})[Tt ](\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:[Zz]|\s*UTC|([+-])(\d{2})(?::?(\d{2}))?)$/i;
|
|
208
|
+
function normalizeLegacyZonedTimestamp(value) {
|
|
209
|
+
let candidate = value;
|
|
210
|
+
if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
|
|
211
|
+
const entries = Object.entries(candidate);
|
|
212
|
+
if (entries.length === 0) return void 0;
|
|
213
|
+
if (entries.length !== 1 || entries[0][0] !== "$date" && entries[0][0] !== "value") return value;
|
|
214
|
+
candidate = entries[0][1];
|
|
215
|
+
}
|
|
216
|
+
if (candidate === null) return void 0;
|
|
217
|
+
if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
|
|
218
|
+
return Object.keys(candidate).length === 0 ? void 0 : value;
|
|
219
|
+
}
|
|
220
|
+
if (typeof candidate !== "string") return value;
|
|
221
|
+
const match = LEGACY_ZONED_TIMESTAMP.exec(candidate.trim());
|
|
222
|
+
if (!match) return value;
|
|
223
|
+
const [
|
|
224
|
+
,
|
|
225
|
+
yearText,
|
|
226
|
+
monthText,
|
|
227
|
+
dayText,
|
|
228
|
+
hourText,
|
|
229
|
+
minuteText,
|
|
230
|
+
secondText,
|
|
231
|
+
fraction = "",
|
|
232
|
+
sign,
|
|
233
|
+
offsetHourText,
|
|
234
|
+
offsetMinuteText
|
|
235
|
+
] = match;
|
|
236
|
+
const year = Number(yearText);
|
|
237
|
+
const month = Number(monthText);
|
|
238
|
+
const day = Number(dayText);
|
|
239
|
+
const hour = Number(hourText);
|
|
240
|
+
const minute = Number(minuteText);
|
|
241
|
+
const second = Number(secondText);
|
|
242
|
+
const offsetHours = offsetHourText === void 0 ? 0 : Number(offsetHourText);
|
|
243
|
+
const offsetMinutes = offsetMinuteText === void 0 ? 0 : Number(offsetMinuteText);
|
|
244
|
+
if (sign === "-" && offsetHours === 0 && offsetMinutes === 0) return value;
|
|
245
|
+
if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59 || offsetHours > 23 || offsetMinutes > 59) {
|
|
246
|
+
return value;
|
|
247
|
+
}
|
|
248
|
+
const local = /* @__PURE__ */ new Date(0);
|
|
249
|
+
local.setUTCFullYear(year, month - 1, day);
|
|
250
|
+
local.setUTCHours(hour, minute, second, 0);
|
|
251
|
+
if (local.getUTCFullYear() !== year || local.getUTCMonth() !== month - 1 || local.getUTCDate() !== day || local.getUTCHours() !== hour || local.getUTCMinutes() !== minute || local.getUTCSeconds() !== second) {
|
|
252
|
+
return value;
|
|
253
|
+
}
|
|
254
|
+
const offset = (offsetHours * 60 + offsetMinutes) * 6e4 * (sign === "-" ? -1 : 1);
|
|
255
|
+
const utc = new Date(local.getTime() - offset);
|
|
256
|
+
if (utc.getUTCFullYear() < 0 || utc.getUTCFullYear() > 9999) return value;
|
|
257
|
+
return `${utc.toISOString().slice(0, 19)}${fraction}Z`;
|
|
258
|
+
}
|
|
259
|
+
function normalizeLegacyProductForecast(product) {
|
|
260
|
+
if (!product?.forecast || typeof product.forecast !== "object" || Array.isArray(product.forecast)) return product;
|
|
261
|
+
const forecast = { ...product.forecast };
|
|
262
|
+
for (const field of ["generated_at", "valid_until"]) {
|
|
263
|
+
if (!(field in forecast)) continue;
|
|
264
|
+
const normalized = normalizeLegacyZonedTimestamp(forecast[field]);
|
|
265
|
+
if (normalized === void 0) delete forecast[field];
|
|
266
|
+
else forecast[field] = normalized;
|
|
267
|
+
}
|
|
268
|
+
return { ...product, forecast };
|
|
269
|
+
}
|
|
206
270
|
function normalizeGetProductsResponse(response) {
|
|
207
271
|
if (!("products" in (response ?? {}))) {
|
|
208
272
|
return response;
|
|
@@ -219,7 +283,9 @@ function normalizeGetProductsResponse(response) {
|
|
|
219
283
|
}
|
|
220
284
|
return {
|
|
221
285
|
...response,
|
|
222
|
-
products: response.products.map(
|
|
286
|
+
products: response.products.map(
|
|
287
|
+
(p) => normalizeLegacyProductForecast(normalizeProductChannels(normalizeProductPricing(p)))
|
|
288
|
+
)
|
|
223
289
|
};
|
|
224
290
|
}
|
|
225
291
|
function adaptPackagePricingForV2(pkg) {
|
|
@@ -249,6 +315,7 @@ function normalizeMediaBuyPricingResponse(response) {
|
|
|
249
315
|
isCPAPricing,
|
|
250
316
|
isFixedPricing,
|
|
251
317
|
normalizeGetProductsResponse,
|
|
318
|
+
normalizeLegacyProductForecast,
|
|
252
319
|
normalizeMediaBuyPricingResponse,
|
|
253
320
|
normalizePricingOption,
|
|
254
321
|
normalizeProductChannels,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/utils/pricing-adapter.ts"],"sourcesContent":["/**\n * Pricing Option Adapter\n *\n * Handles conversion between v2.x and v3 pricing option field names.\n * The library exposes only v3 API (fixed_price, floor_price) to clients,\n * and internally adapts requests for v2.x servers.\n *\n * Field mappings:\n * - v3 fixed_price ↔ v2 rate (for fixed pricing)\n * - v3 floor_price ↔ v2 price_guidance.floor (for auction pricing)\n * - v3 presence of fixed_price ↔ v2 is_fixed: true/false\n */\n\n/**\n * v3 price guidance (percentiles only, floor moved to top level)\n */\nexport interface PriceGuidanceV3 {\n p25?: number;\n p50?: number;\n p75?: number;\n p90?: number;\n}\n\n/**\n * v2 price guidance (includes floor)\n */\nexport interface PriceGuidanceV2 {\n floor?: number;\n p25?: number;\n p50?: number;\n p75?: number;\n p90?: number;\n}\n\n/**\n * v3 pricing option structure\n */\nexport interface PricingOptionV3 {\n pricing_option_id: string;\n pricing_model: string;\n currency: string;\n /** Fixed price - if present, this is fixed pricing */\n fixed_price?: number;\n /** Floor price for auction - mutually exclusive with fixed_price */\n floor_price?: number;\n /** Percentile hints for auction bidding */\n price_guidance?: PriceGuidanceV3;\n min_spend_per_package?: number;\n parameters?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * v2 pricing option structure\n */\nexport interface PricingOptionV2 {\n pricing_option_id: string;\n pricing_model: string;\n currency: string;\n /** Fixed rate (v2 name for fixed_price) */\n rate?: number;\n /** Boolean discriminator for fixed vs auction */\n is_fixed?: boolean;\n /** Price guidance including floor */\n price_guidance?: PriceGuidanceV2;\n min_spend_per_package?: number;\n parameters?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Check if a pricing option uses v2 field names\n */\nexport function usesV2PricingFields(option: any): boolean {\n if (!option || typeof option !== 'object') return false;\n // v2 uses 'rate' or 'is_fixed' or has floor inside price_guidance\n return option.rate !== undefined || option.is_fixed !== undefined || option.price_guidance?.floor !== undefined;\n}\n\n/**\n * Check if a pricing option uses v3 field names\n */\nexport function usesV3PricingFields(option: any): boolean {\n if (!option || typeof option !== 'object') return false;\n // v3 uses fixed_price or floor_price at top level\n return option.fixed_price !== undefined || option.floor_price !== undefined;\n}\n\n/**\n * Detect if a pricing option is fixed pricing (works with v2 or v3)\n */\nexport function isFixedPricing(option: PricingOptionV2 | PricingOptionV3): boolean {\n // v3: presence of fixed_price indicates fixed pricing\n if ((option as PricingOptionV3).fixed_price !== undefined) {\n return true;\n }\n // v2: is_fixed boolean\n if ((option as PricingOptionV2).is_fixed !== undefined) {\n return (option as PricingOptionV2).is_fixed!;\n }\n // v2: presence of rate without is_fixed defaults to fixed\n if ((option as PricingOptionV2).rate !== undefined) {\n return true;\n }\n return false;\n}\n\n/**\n * Detect if a pricing option is CPA (cost per acquisition) pricing\n */\nexport function isCPAPricing(option: PricingOptionV2 | PricingOptionV3): boolean {\n return option?.pricing_model === 'cpa';\n}\n\n/**\n * Get the price value from a pricing option (works with v2 or v3)\n */\nexport function getPrice(option: PricingOptionV2 | PricingOptionV3): number | undefined {\n // v3 field takes precedence\n if ((option as PricingOptionV3).fixed_price !== undefined) {\n return (option as PricingOptionV3).fixed_price;\n }\n // Fall back to v2 field\n return (option as PricingOptionV2).rate;\n}\n\n/**\n * Get the floor price from a pricing option (works with v2 or v3)\n */\nexport function getFloorPrice(option: PricingOptionV2 | PricingOptionV3): number | undefined {\n // v3 field takes precedence\n if ((option as PricingOptionV3).floor_price !== undefined) {\n return (option as PricingOptionV3).floor_price;\n }\n // Fall back to v2 field (inside price_guidance)\n return (option as PricingOptionV2).price_guidance?.floor;\n}\n\n/**\n * Adapt a v3-style pricing option for a v2 server.\n * Converts fixed_price → rate, floor_price → price_guidance.floor\n */\nexport function adaptPricingOptionForV2(option: PricingOptionV3): PricingOptionV2 {\n // Already v2 format or no v3 fields\n if (!usesV3PricingFields(option)) {\n return option as unknown as PricingOptionV2;\n }\n\n const { fixed_price, floor_price, price_guidance, ...rest } = option;\n\n const result: PricingOptionV2 = { ...rest } as PricingOptionV2;\n\n if (fixed_price !== undefined) {\n // Fixed pricing\n result.rate = fixed_price;\n result.is_fixed = true;\n } else {\n // Auction pricing\n result.is_fixed = false;\n\n // Build v2 price_guidance with floor inside\n if (floor_price !== undefined || price_guidance) {\n result.price_guidance = {\n ...(price_guidance || {}),\n };\n if (floor_price !== undefined) {\n result.price_guidance.floor = floor_price;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Normalize a v2-style pricing option to v3.\n * Converts rate → fixed_price, price_guidance.floor → floor_price\n */\nexport function normalizePricingOption(option: PricingOptionV2 | PricingOptionV3): PricingOptionV3 {\n // Already v3 format\n if (usesV3PricingFields(option) && !usesV2PricingFields(option)) {\n return option as PricingOptionV3;\n }\n\n const v2Option = option as PricingOptionV2;\n const { rate, is_fixed, price_guidance, ...rest } = v2Option;\n\n const result: PricingOptionV3 = { ...rest } as PricingOptionV3;\n\n // Convert rate → fixed_price (for fixed pricing)\n if (rate !== undefined && (is_fixed === true || is_fixed === undefined)) {\n result.fixed_price = rate;\n }\n\n // Convert price_guidance.floor → floor_price (for auction pricing)\n if (price_guidance) {\n const { floor, ...percentiles } = price_guidance;\n\n if (floor !== undefined) {\n result.floor_price = floor;\n }\n\n // Keep percentiles in price_guidance if any exist\n if (Object.keys(percentiles).length > 0) {\n result.price_guidance = percentiles;\n }\n }\n\n return result;\n}\n\n/**\n * Adapt all pricing options in a product for v2 server\n */\nexport function adaptProductPricingForV2(product: any): any {\n if (!product?.pricing_options || !Array.isArray(product.pricing_options)) {\n return product;\n }\n\n return {\n ...product,\n pricing_options: product.pricing_options.map(adaptPricingOptionForV2),\n };\n}\n\n/**\n * Normalize all pricing options in a product to v3\n */\nexport function normalizeProductPricing(product: any): any {\n if (!product?.pricing_options || !Array.isArray(product.pricing_options)) {\n return product;\n }\n\n return {\n ...product,\n pricing_options: product.pricing_options.map(normalizePricingOption),\n };\n}\n\n/**\n * Adapt a get_products request for a v2 server.\n *\n * Converts v3 fields to their v2 equivalents:\n * - brand (BrandReference) → brand_manifest (base domain URL string)\n * - catalog → promoted_offerings (type='offering') or promoted_offerings.product_selectors (type='product')\n * - channels in filters → v2 channel names\n *\n * Strips v3-only fields v2 agents don't understand:\n * - buying_mode, buyer_campaign_ref, property_list, account_id, pagination (top-level)\n * - filters: required_features, required_axe_integrations, required_geo_targeting,\n * signal_targeting, regions, metros\n */\nexport function adaptGetProductsRequestForV2(request: any): any {\n const adapted: any = { ...request };\n\n // Convert v3 brand (BrandReference) → v2 brand_manifest (bare domain URL).\n // v2 servers resolve brand info from the base domain URL.\n if (adapted.brand?.domain) {\n adapted.brand_manifest = `https://${adapted.brand.domain}`;\n delete adapted.brand;\n }\n\n // Convert v3 catalog → v2 promoted_offerings\n if (adapted.catalog) {\n const catalog = adapted.catalog;\n if (catalog.type === 'product') {\n adapted.promoted_offerings = {\n product_selectors: {\n ...(catalog.gtins?.length && { manifest_gtins: catalog.gtins }),\n ...(catalog.ids?.length && { manifest_skus: catalog.ids }),\n ...(catalog.tags?.length && { manifest_tags: catalog.tags }),\n ...(catalog.category && { manifest_category: catalog.category }),\n ...(catalog.query && { manifest_query: catalog.query }),\n },\n };\n } else if (catalog.type === 'offering') {\n adapted.promoted_offerings = {\n ...(catalog.items?.length && { offerings: catalog.items }),\n };\n }\n delete adapted.catalog;\n }\n\n // Map v3 channel names to v2 equivalents\n if (adapted.filters?.channels) {\n const v2ChannelMap: Record<string, string> = {\n olv: 'video',\n ctv: 'video',\n streaming_audio: 'audio',\n retail_media: 'retail',\n };\n // Deduplicate after mapping (e.g. olv+ctv both become 'video')\n const mapped = adapted.filters.channels.map((ch: string) => v2ChannelMap[ch] ?? ch);\n adapted.filters = {\n ...adapted.filters,\n channels: [...new Set(mapped)],\n };\n }\n\n // Strip v3-only filter fields (format_ids exists in both v2 and v3, keep it)\n if (adapted.filters) {\n const {\n required_features,\n required_axe_integrations,\n required_geo_targeting,\n signal_targeting,\n regions,\n metros,\n ...v2Filters\n } = adapted.filters;\n adapted.filters = v2Filters;\n }\n\n // Strip v3-only top-level fields\n delete adapted.buying_mode;\n delete adapted.buyer_campaign_ref;\n delete adapted.property_list;\n delete adapted.account;\n delete adapted.pagination;\n delete adapted.adcp_major_version;\n\n return adapted;\n}\n\n/**\n * Normalize v2 channel names on a product to v3.\n * v2 used coarser buckets; some map one-to-many (e.g. 'video' → ['olv', 'ctv']).\n */\nexport function normalizeProductChannels(product: any): any {\n if (!product?.channels || !Array.isArray(product.channels)) {\n return product;\n }\n\n const v3ChannelMap: Record<string, string[]> = {\n video: ['olv', 'ctv'],\n audio: ['streaming_audio'],\n native: ['display'],\n retail: ['retail_media'],\n };\n\n const normalized = product.channels.flatMap((ch: string) => v3ChannelMap[ch] ?? [ch]);\n return { ...product, channels: [...new Set(normalized)] };\n}\n\n/**\n * Normalize all products in a get_products response to v3\n */\nexport function normalizeGetProductsResponse(response: any): any {\n // If there's no products field at all, this may be an error response — pass through\n if (!('products' in (response ?? {}))) {\n return response;\n }\n\n // If products exists but isn't an array, the response is malformed\n if (!Array.isArray(response.products)) {\n return {\n errors: [\n {\n code: 'invalid_response',\n message: `Expected products to be an array, got ${typeof response.products}`,\n },\n ],\n };\n }\n\n return {\n ...response,\n products: response.products.map((p: any) => normalizeProductChannels(normalizeProductPricing(p))),\n };\n}\n\n/**\n * Adapt a package request's pricing option selection for v2 server.\n * This handles bid_price which references pricing option floor semantics.\n */\nexport function adaptPackagePricingForV2(pkg: any): any {\n // Package requests don't typically contain pricing_options,\n // but they do contain pricing_option_id which selects one.\n // No transformation needed for bid_price - it's the same in both versions.\n return pkg;\n}\n\n/**\n * Adapt a create_media_buy request for v2 server (pricing fields)\n */\nexport function adaptMediaBuyPricingForV2(request: any): any {\n // Media buy requests select pricing options by ID, not by defining them.\n // No pricing field transformation needed in requests.\n return request;\n}\n\n/**\n * Normalize a media buy response's package pricing to v3\n */\nexport function normalizeMediaBuyPricingResponse(response: any): any {\n // Media buy responses may include products with pricing_options\n if (response?.products && Array.isArray(response.products)) {\n return {\n ...response,\n products: response.products.map(normalizeProductPricing),\n };\n }\n return response;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils/pricing-adapter.ts"],"sourcesContent":["/**\n * Pricing Option Adapter\n *\n * Handles conversion between v2.x and v3 pricing option field names.\n * The library exposes only v3 API (fixed_price, floor_price) to clients,\n * and internally adapts requests for v2.x servers.\n *\n * Field mappings:\n * - v3 fixed_price ↔ v2 rate (for fixed pricing)\n * - v3 floor_price ↔ v2 price_guidance.floor (for auction pricing)\n * - v3 presence of fixed_price ↔ v2 is_fixed: true/false\n */\n\n/**\n * v3 price guidance (percentiles only, floor moved to top level)\n */\nexport interface PriceGuidanceV3 {\n p25?: number;\n p50?: number;\n p75?: number;\n p90?: number;\n}\n\n/**\n * v2 price guidance (includes floor)\n */\nexport interface PriceGuidanceV2 {\n floor?: number;\n p25?: number;\n p50?: number;\n p75?: number;\n p90?: number;\n}\n\n/**\n * v3 pricing option structure\n */\nexport interface PricingOptionV3 {\n pricing_option_id: string;\n pricing_model: string;\n currency: string;\n /** Fixed price - if present, this is fixed pricing */\n fixed_price?: number;\n /** Floor price for auction - mutually exclusive with fixed_price */\n floor_price?: number;\n /** Percentile hints for auction bidding */\n price_guidance?: PriceGuidanceV3;\n min_spend_per_package?: number;\n parameters?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * v2 pricing option structure\n */\nexport interface PricingOptionV2 {\n pricing_option_id: string;\n pricing_model: string;\n currency: string;\n /** Fixed rate (v2 name for fixed_price) */\n rate?: number;\n /** Boolean discriminator for fixed vs auction */\n is_fixed?: boolean;\n /** Price guidance including floor */\n price_guidance?: PriceGuidanceV2;\n min_spend_per_package?: number;\n parameters?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Check if a pricing option uses v2 field names\n */\nexport function usesV2PricingFields(option: any): boolean {\n if (!option || typeof option !== 'object') return false;\n // v2 uses 'rate' or 'is_fixed' or has floor inside price_guidance\n return option.rate !== undefined || option.is_fixed !== undefined || option.price_guidance?.floor !== undefined;\n}\n\n/**\n * Check if a pricing option uses v3 field names\n */\nexport function usesV3PricingFields(option: any): boolean {\n if (!option || typeof option !== 'object') return false;\n // v3 uses fixed_price or floor_price at top level\n return option.fixed_price !== undefined || option.floor_price !== undefined;\n}\n\n/**\n * Detect if a pricing option is fixed pricing (works with v2 or v3)\n */\nexport function isFixedPricing(option: PricingOptionV2 | PricingOptionV3): boolean {\n // v3: presence of fixed_price indicates fixed pricing\n if ((option as PricingOptionV3).fixed_price !== undefined) {\n return true;\n }\n // v2: is_fixed boolean\n if ((option as PricingOptionV2).is_fixed !== undefined) {\n return (option as PricingOptionV2).is_fixed!;\n }\n // v2: presence of rate without is_fixed defaults to fixed\n if ((option as PricingOptionV2).rate !== undefined) {\n return true;\n }\n return false;\n}\n\n/**\n * Detect if a pricing option is CPA (cost per acquisition) pricing\n */\nexport function isCPAPricing(option: PricingOptionV2 | PricingOptionV3): boolean {\n return option?.pricing_model === 'cpa';\n}\n\n/**\n * Get the price value from a pricing option (works with v2 or v3)\n */\nexport function getPrice(option: PricingOptionV2 | PricingOptionV3): number | undefined {\n // v3 field takes precedence\n if ((option as PricingOptionV3).fixed_price !== undefined) {\n return (option as PricingOptionV3).fixed_price;\n }\n // Fall back to v2 field\n return (option as PricingOptionV2).rate;\n}\n\n/**\n * Get the floor price from a pricing option (works with v2 or v3)\n */\nexport function getFloorPrice(option: PricingOptionV2 | PricingOptionV3): number | undefined {\n // v3 field takes precedence\n if ((option as PricingOptionV3).floor_price !== undefined) {\n return (option as PricingOptionV3).floor_price;\n }\n // Fall back to v2 field (inside price_guidance)\n return (option as PricingOptionV2).price_guidance?.floor;\n}\n\n/**\n * Adapt a v3-style pricing option for a v2 server.\n * Converts fixed_price → rate, floor_price → price_guidance.floor\n */\nexport function adaptPricingOptionForV2(option: PricingOptionV3): PricingOptionV2 {\n // Already v2 format or no v3 fields\n if (!usesV3PricingFields(option)) {\n return option as unknown as PricingOptionV2;\n }\n\n const { fixed_price, floor_price, price_guidance, ...rest } = option;\n\n const result: PricingOptionV2 = { ...rest } as PricingOptionV2;\n\n if (fixed_price !== undefined) {\n // Fixed pricing\n result.rate = fixed_price;\n result.is_fixed = true;\n } else {\n // Auction pricing\n result.is_fixed = false;\n\n // Build v2 price_guidance with floor inside\n if (floor_price !== undefined || price_guidance) {\n result.price_guidance = {\n ...(price_guidance || {}),\n };\n if (floor_price !== undefined) {\n result.price_guidance.floor = floor_price;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Normalize a v2-style pricing option to v3.\n * Converts rate → fixed_price, price_guidance.floor → floor_price\n */\nexport function normalizePricingOption(option: PricingOptionV2 | PricingOptionV3): PricingOptionV3 {\n // Already v3 format\n if (usesV3PricingFields(option) && !usesV2PricingFields(option)) {\n return option as PricingOptionV3;\n }\n\n const v2Option = option as PricingOptionV2;\n const { rate, is_fixed, price_guidance, ...rest } = v2Option;\n\n const result: PricingOptionV3 = { ...rest } as PricingOptionV3;\n\n // Convert rate → fixed_price (for fixed pricing)\n if (rate !== undefined && (is_fixed === true || is_fixed === undefined)) {\n result.fixed_price = rate;\n }\n\n // Convert price_guidance.floor → floor_price (for auction pricing)\n if (price_guidance) {\n const { floor, ...percentiles } = price_guidance;\n\n if (floor !== undefined) {\n result.floor_price = floor;\n }\n\n // Keep percentiles in price_guidance if any exist\n if (Object.keys(percentiles).length > 0) {\n result.price_guidance = percentiles;\n }\n }\n\n return result;\n}\n\n/**\n * Adapt all pricing options in a product for v2 server\n */\nexport function adaptProductPricingForV2(product: any): any {\n if (!product?.pricing_options || !Array.isArray(product.pricing_options)) {\n return product;\n }\n\n return {\n ...product,\n pricing_options: product.pricing_options.map(adaptPricingOptionForV2),\n };\n}\n\n/**\n * Normalize all pricing options in a product to v3\n */\nexport function normalizeProductPricing(product: any): any {\n if (!product?.pricing_options || !Array.isArray(product.pricing_options)) {\n return product;\n }\n\n return {\n ...product,\n pricing_options: product.pricing_options.map(normalizePricingOption),\n };\n}\n\n/**\n * Adapt a get_products request for a v2 server.\n *\n * Converts v3 fields to their v2 equivalents:\n * - brand (BrandReference) → brand_manifest (base domain URL string)\n * - catalog → promoted_offerings (type='offering') or promoted_offerings.product_selectors (type='product')\n * - channels in filters → v2 channel names\n *\n * Strips v3-only fields v2 agents don't understand:\n * - buying_mode, buyer_campaign_ref, property_list, account_id, pagination (top-level)\n * - filters: required_features, required_axe_integrations, required_geo_targeting,\n * signal_targeting, regions, metros\n */\nexport function adaptGetProductsRequestForV2(request: any): any {\n const adapted: any = { ...request };\n\n // Convert v3 brand (BrandReference) → v2 brand_manifest (bare domain URL).\n // v2 servers resolve brand info from the base domain URL.\n if (adapted.brand?.domain) {\n adapted.brand_manifest = `https://${adapted.brand.domain}`;\n delete adapted.brand;\n }\n\n // Convert v3 catalog → v2 promoted_offerings\n if (adapted.catalog) {\n const catalog = adapted.catalog;\n if (catalog.type === 'product') {\n adapted.promoted_offerings = {\n product_selectors: {\n ...(catalog.gtins?.length && { manifest_gtins: catalog.gtins }),\n ...(catalog.ids?.length && { manifest_skus: catalog.ids }),\n ...(catalog.tags?.length && { manifest_tags: catalog.tags }),\n ...(catalog.category && { manifest_category: catalog.category }),\n ...(catalog.query && { manifest_query: catalog.query }),\n },\n };\n } else if (catalog.type === 'offering') {\n adapted.promoted_offerings = {\n ...(catalog.items?.length && { offerings: catalog.items }),\n };\n }\n delete adapted.catalog;\n }\n\n // Map v3 channel names to v2 equivalents\n if (adapted.filters?.channels) {\n const v2ChannelMap: Record<string, string> = {\n olv: 'video',\n ctv: 'video',\n streaming_audio: 'audio',\n retail_media: 'retail',\n };\n // Deduplicate after mapping (e.g. olv+ctv both become 'video')\n const mapped = adapted.filters.channels.map((ch: string) => v2ChannelMap[ch] ?? ch);\n adapted.filters = {\n ...adapted.filters,\n channels: [...new Set(mapped)],\n };\n }\n\n // Strip v3-only filter fields (format_ids exists in both v2 and v3, keep it)\n if (adapted.filters) {\n const {\n required_features,\n required_axe_integrations,\n required_geo_targeting,\n signal_targeting,\n regions,\n metros,\n ...v2Filters\n } = adapted.filters;\n adapted.filters = v2Filters;\n }\n\n // Strip v3-only top-level fields\n delete adapted.buying_mode;\n delete adapted.buyer_campaign_ref;\n delete adapted.property_list;\n delete adapted.account;\n delete adapted.pagination;\n delete adapted.adcp_major_version;\n\n return adapted;\n}\n\n/**\n * Normalize v2 channel names on a product to v3.\n * v2 used coarser buckets; some map one-to-many (e.g. 'video' → ['olv', 'ctv']).\n */\nexport function normalizeProductChannels(product: any): any {\n if (!product?.channels || !Array.isArray(product.channels)) {\n return product;\n }\n\n const v3ChannelMap: Record<string, string[]> = {\n video: ['olv', 'ctv'],\n audio: ['streaming_audio'],\n native: ['display'],\n retail: ['retail_media'],\n };\n\n const normalized = product.channels.flatMap((ch: string) => v3ChannelMap[ch] ?? [ch]);\n return { ...product, channels: [...new Set(normalized)] };\n}\n\nconst LEGACY_ZONED_TIMESTAMP =\n /^(\\d{4})-(\\d{2})-(\\d{2})[Tt ](\\d{2}):(\\d{2}):(\\d{2})(\\.\\d+)?(?:[Zz]|\\s*UTC|([+-])(\\d{2})(?::?(\\d{2}))?)$/i;\n\nfunction normalizeLegacyZonedTimestamp(value: unknown): unknown {\n let candidate = value;\n if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) {\n const entries = Object.entries(candidate as Record<string, unknown>);\n if (entries.length === 0) return undefined;\n if (entries.length !== 1 || (entries[0]![0] !== '$date' && entries[0]![0] !== 'value')) return value;\n candidate = entries[0]![1];\n }\n if (candidate === null) return undefined;\n if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) {\n return Object.keys(candidate as Record<string, unknown>).length === 0 ? undefined : value;\n }\n if (typeof candidate !== 'string') return value;\n\n const match = LEGACY_ZONED_TIMESTAMP.exec(candidate.trim());\n if (!match) return value;\n const [\n ,\n yearText,\n monthText,\n dayText,\n hourText,\n minuteText,\n secondText,\n fraction = '',\n sign,\n offsetHourText,\n offsetMinuteText,\n ] = match;\n const year = Number(yearText);\n const month = Number(monthText);\n const day = Number(dayText);\n const hour = Number(hourText);\n const minute = Number(minuteText);\n const second = Number(secondText);\n const offsetHours = offsetHourText === undefined ? 0 : Number(offsetHourText);\n const offsetMinutes = offsetMinuteText === undefined ? 0 : Number(offsetMinuteText);\n if (sign === '-' && offsetHours === 0 && offsetMinutes === 0) return value;\n if (\n month < 1 ||\n month > 12 ||\n day < 1 ||\n day > 31 ||\n hour > 23 ||\n minute > 59 ||\n second > 59 ||\n offsetHours > 23 ||\n offsetMinutes > 59\n ) {\n return value;\n }\n\n const local = new Date(0);\n local.setUTCFullYear(year, month - 1, day);\n local.setUTCHours(hour, minute, second, 0);\n if (\n local.getUTCFullYear() !== year ||\n local.getUTCMonth() !== month - 1 ||\n local.getUTCDate() !== day ||\n local.getUTCHours() !== hour ||\n local.getUTCMinutes() !== minute ||\n local.getUTCSeconds() !== second\n ) {\n return value;\n }\n\n const offset = (offsetHours * 60 + offsetMinutes) * 60_000 * (sign === '-' ? -1 : 1);\n const utc = new Date(local.getTime() - offset);\n if (utc.getUTCFullYear() < 0 || utc.getUTCFullYear() > 9999) return value;\n return `${utc.toISOString().slice(0, 19)}${fraction}Z`;\n}\n\n/** Normalize optional forecast timestamps at the v2.5 compatibility boundary. */\nexport function normalizeLegacyProductForecast(product: any): any {\n if (!product?.forecast || typeof product.forecast !== 'object' || Array.isArray(product.forecast)) return product;\n const forecast = { ...product.forecast };\n for (const field of ['generated_at', 'valid_until'] as const) {\n if (!(field in forecast)) continue;\n const normalized = normalizeLegacyZonedTimestamp(forecast[field]);\n if (normalized === undefined) delete forecast[field];\n else forecast[field] = normalized;\n }\n return { ...product, forecast };\n}\n\n/**\n * Normalize all products in a get_products response to v3\n */\nexport function normalizeGetProductsResponse(response: any): any {\n // If there's no products field at all, this may be an error response — pass through\n if (!('products' in (response ?? {}))) {\n return response;\n }\n\n // If products exists but isn't an array, the response is malformed\n if (!Array.isArray(response.products)) {\n return {\n errors: [\n {\n code: 'invalid_response',\n message: `Expected products to be an array, got ${typeof response.products}`,\n },\n ],\n };\n }\n\n return {\n ...response,\n products: response.products.map((p: any) =>\n normalizeLegacyProductForecast(normalizeProductChannels(normalizeProductPricing(p)))\n ),\n };\n}\n\n/**\n * Adapt a package request's pricing option selection for v2 server.\n * This handles bid_price which references pricing option floor semantics.\n */\nexport function adaptPackagePricingForV2(pkg: any): any {\n // Package requests don't typically contain pricing_options,\n // but they do contain pricing_option_id which selects one.\n // No transformation needed for bid_price - it's the same in both versions.\n return pkg;\n}\n\n/**\n * Adapt a create_media_buy request for v2 server (pricing fields)\n */\nexport function adaptMediaBuyPricingForV2(request: any): any {\n // Media buy requests select pricing options by ID, not by defining them.\n // No pricing field transformation needed in requests.\n return request;\n}\n\n/**\n * Normalize a media buy response's package pricing to v3\n */\nexport function normalizeMediaBuyPricingResponse(response: any): any {\n // Media buy responses may include products with pricing_options\n if (response?.products && Array.isArray(response.products)) {\n return {\n ...response,\n products: response.products.map(normalizeProductPricing),\n };\n }\n return response;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -165,6 +165,69 @@ function normalizeProductChannels(product) {
|
|
|
165
165
|
const normalized = product.channels.flatMap((ch) => v3ChannelMap[ch] ?? [ch]);
|
|
166
166
|
return { ...product, channels: [...new Set(normalized)] };
|
|
167
167
|
}
|
|
168
|
+
const LEGACY_ZONED_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})[Tt ](\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:[Zz]|\s*UTC|([+-])(\d{2})(?::?(\d{2}))?)$/i;
|
|
169
|
+
function normalizeLegacyZonedTimestamp(value) {
|
|
170
|
+
let candidate = value;
|
|
171
|
+
if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
|
|
172
|
+
const entries = Object.entries(candidate);
|
|
173
|
+
if (entries.length === 0) return void 0;
|
|
174
|
+
if (entries.length !== 1 || entries[0][0] !== "$date" && entries[0][0] !== "value") return value;
|
|
175
|
+
candidate = entries[0][1];
|
|
176
|
+
}
|
|
177
|
+
if (candidate === null) return void 0;
|
|
178
|
+
if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
|
|
179
|
+
return Object.keys(candidate).length === 0 ? void 0 : value;
|
|
180
|
+
}
|
|
181
|
+
if (typeof candidate !== "string") return value;
|
|
182
|
+
const match = LEGACY_ZONED_TIMESTAMP.exec(candidate.trim());
|
|
183
|
+
if (!match) return value;
|
|
184
|
+
const [
|
|
185
|
+
,
|
|
186
|
+
yearText,
|
|
187
|
+
monthText,
|
|
188
|
+
dayText,
|
|
189
|
+
hourText,
|
|
190
|
+
minuteText,
|
|
191
|
+
secondText,
|
|
192
|
+
fraction = "",
|
|
193
|
+
sign,
|
|
194
|
+
offsetHourText,
|
|
195
|
+
offsetMinuteText
|
|
196
|
+
] = match;
|
|
197
|
+
const year = Number(yearText);
|
|
198
|
+
const month = Number(monthText);
|
|
199
|
+
const day = Number(dayText);
|
|
200
|
+
const hour = Number(hourText);
|
|
201
|
+
const minute = Number(minuteText);
|
|
202
|
+
const second = Number(secondText);
|
|
203
|
+
const offsetHours = offsetHourText === void 0 ? 0 : Number(offsetHourText);
|
|
204
|
+
const offsetMinutes = offsetMinuteText === void 0 ? 0 : Number(offsetMinuteText);
|
|
205
|
+
if (sign === "-" && offsetHours === 0 && offsetMinutes === 0) return value;
|
|
206
|
+
if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59 || offsetHours > 23 || offsetMinutes > 59) {
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
const local = /* @__PURE__ */ new Date(0);
|
|
210
|
+
local.setUTCFullYear(year, month - 1, day);
|
|
211
|
+
local.setUTCHours(hour, minute, second, 0);
|
|
212
|
+
if (local.getUTCFullYear() !== year || local.getUTCMonth() !== month - 1 || local.getUTCDate() !== day || local.getUTCHours() !== hour || local.getUTCMinutes() !== minute || local.getUTCSeconds() !== second) {
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
const offset = (offsetHours * 60 + offsetMinutes) * 6e4 * (sign === "-" ? -1 : 1);
|
|
216
|
+
const utc = new Date(local.getTime() - offset);
|
|
217
|
+
if (utc.getUTCFullYear() < 0 || utc.getUTCFullYear() > 9999) return value;
|
|
218
|
+
return `${utc.toISOString().slice(0, 19)}${fraction}Z`;
|
|
219
|
+
}
|
|
220
|
+
function normalizeLegacyProductForecast(product) {
|
|
221
|
+
if (!product?.forecast || typeof product.forecast !== "object" || Array.isArray(product.forecast)) return product;
|
|
222
|
+
const forecast = { ...product.forecast };
|
|
223
|
+
for (const field of ["generated_at", "valid_until"]) {
|
|
224
|
+
if (!(field in forecast)) continue;
|
|
225
|
+
const normalized = normalizeLegacyZonedTimestamp(forecast[field]);
|
|
226
|
+
if (normalized === void 0) delete forecast[field];
|
|
227
|
+
else forecast[field] = normalized;
|
|
228
|
+
}
|
|
229
|
+
return { ...product, forecast };
|
|
230
|
+
}
|
|
168
231
|
function normalizeGetProductsResponse(response) {
|
|
169
232
|
if (!("products" in (response ?? {}))) {
|
|
170
233
|
return response;
|
|
@@ -181,7 +244,9 @@ function normalizeGetProductsResponse(response) {
|
|
|
181
244
|
}
|
|
182
245
|
return {
|
|
183
246
|
...response,
|
|
184
|
-
products: response.products.map(
|
|
247
|
+
products: response.products.map(
|
|
248
|
+
(p) => normalizeLegacyProductForecast(normalizeProductChannels(normalizeProductPricing(p)))
|
|
249
|
+
)
|
|
185
250
|
};
|
|
186
251
|
}
|
|
187
252
|
function adaptPackagePricingForV2(pkg) {
|
|
@@ -210,6 +275,7 @@ export {
|
|
|
210
275
|
isCPAPricing,
|
|
211
276
|
isFixedPricing,
|
|
212
277
|
normalizeGetProductsResponse,
|
|
278
|
+
normalizeLegacyProductForecast,
|
|
213
279
|
normalizeMediaBuyPricingResponse,
|
|
214
280
|
normalizePricingOption,
|
|
215
281
|
normalizeProductChannels,
|