@adcp/sdk 14.0.0-rc.43 → 14.0.0-rc.44
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/acceptance-policy/evaluator.d.mts +46 -0
- package/dist/lib/acceptance-policy/evaluator.d.ts +46 -0
- package/dist/lib/acceptance-policy/evaluator.js +447 -0
- package/dist/lib/acceptance-policy/evaluator.mjs +423 -0
- package/dist/lib/acceptance-policy/index.d.mts +20 -0
- package/dist/lib/acceptance-policy/index.d.ts +20 -0
- package/dist/lib/acceptance-policy/index.js +43 -5
- package/dist/lib/acceptance-policy/index.mjs +42 -5
- package/dist/lib/canonical-references/index.d.mts +2 -0
- package/dist/lib/canonical-references/index.d.ts +2 -0
- package/dist/lib/canonical-references/index.js +2 -1
- package/dist/lib/canonical-references/index.mjs +2 -1
- package/dist/lib/index.d.mts +3 -2
- package/dist/lib/index.d.ts +3 -2
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.mjs +2 -0
- package/dist/lib/net/index.d.mts +1 -1
- package/dist/lib/net/index.d.ts +1 -1
- package/dist/lib/net/ssrf-fetch.d.mts +41 -0
- package/dist/lib/net/ssrf-fetch.d.ts +41 -0
- package/dist/lib/net/ssrf-fetch.js +2 -1
- package/dist/lib/net/ssrf-fetch.mjs +2 -1
- package/dist/lib/protocols/transportDiagnostics.js +1 -3
- package/dist/lib/protocols/transportDiagnostics.mjs +1 -3
- package/dist/lib/registry/types.generated.d.mts +42 -0
- package/dist/lib/registry/types.generated.d.ts +42 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/signing/brand-jwks.d.mts +37 -3
- package/dist/lib/signing/brand-jwks.d.ts +37 -3
- package/dist/lib/signing/brand-jwks.js +6 -1
- package/dist/lib/signing/brand-jwks.mjs +6 -1
- package/dist/lib/signing/jwks-https.d.mts +4 -0
- package/dist/lib/signing/jwks-https.d.ts +4 -0
- package/dist/lib/signing/jwks-https.js +4 -1
- package/dist/lib/signing/jwks-https.mjs +4 -1
- package/dist/lib/signing/server.d.mts +1 -0
- package/dist/lib/signing/server.d.ts +1 -0
- package/dist/lib/testing/storyboard/acceptance-policy-discovery.d.mts +26 -0
- package/dist/lib/testing/storyboard/acceptance-policy-discovery.d.ts +26 -0
- package/dist/lib/testing/storyboard/acceptance-policy-discovery.js +319 -0
- package/dist/lib/testing/storyboard/acceptance-policy-discovery.mjs +299 -0
- package/dist/lib/testing/storyboard/request-signing/grader.d.mts +11 -0
- package/dist/lib/testing/storyboard/request-signing/grader.d.ts +11 -0
- package/dist/lib/testing/storyboard/request-signing/grader.js +13 -0
- package/dist/lib/testing/storyboard/request-signing/grader.mjs +12 -0
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.js +20 -1
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +21 -2
- package/dist/lib/testing/storyboard/runner.js +125 -35
- package/dist/lib/testing/storyboard/runner.mjs +127 -35
- package/dist/lib/testing/storyboard/types.d.mts +13 -0
- package/dist/lib/testing/storyboard/types.d.ts +13 -0
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/v2/projection/creative-delivery.js +52 -0
- package/dist/lib/v2/projection/creative-delivery.mjs +53 -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.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/ACCEPTANCE-POLICY-DISCOVERY.md +126 -2
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Conservative, advisory evaluation of already-verified acceptance profiles. */
|
|
2
|
+
import type { AcceptanceContext } from '../types/core.generated.mjs';
|
|
3
|
+
import type { AcceptancePolicyProfileResolution, AcceptancePolicyRequirement, AcceptancePolicyRule, AcceptancePolicySurface } from './index.mjs';
|
|
4
|
+
export type AcceptancePolicyOutcome = 'allowed' | 'prohibited' | 'requires_disclosure' | 'requires_setup' | 'requires_review' | 'unknown';
|
|
5
|
+
export type AcceptancePolicyAssessmentDiagnosticCode = 'profile_unresolved' | 'profile_conflict' | 'invalid_profile' | 'assessment_limit_exceeded' | 'partial_coverage' | 'incomplete_context' | 'invalid_context' | 'invalid_evaluation_time' | 'schema_unavailable';
|
|
6
|
+
export interface AcceptancePolicyAssessmentDiagnostic {
|
|
7
|
+
code: AcceptancePolicyAssessmentDiagnosticCode;
|
|
8
|
+
profileId?: string;
|
|
9
|
+
ruleId?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AssessAcceptancePolicyInput {
|
|
12
|
+
/** Seller-default and product profiles to compose. Unresolved entries fail closed. */
|
|
13
|
+
profiles: readonly AcceptancePolicyProfileResolution[];
|
|
14
|
+
acceptanceContext: AcceptanceContext;
|
|
15
|
+
appliesTo: AcceptancePolicySurface;
|
|
16
|
+
/** Evaluation instant for rule windows. Defaults to the current time. */
|
|
17
|
+
evaluatedAt?: Date | string;
|
|
18
|
+
/** Schema bundle used to validate acceptanceContext and each resolved profile. Defaults to the SDK pin. */
|
|
19
|
+
adcpVersion?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface AcceptancePolicyAssessment {
|
|
22
|
+
/** Advisory only. The seller's response to an exact request remains authoritative. */
|
|
23
|
+
advisory: true;
|
|
24
|
+
outcome: AcceptancePolicyOutcome;
|
|
25
|
+
profileIds: string[];
|
|
26
|
+
matchingRuleIds: string[];
|
|
27
|
+
matchedRules: AcceptancePolicyMatchedRule[];
|
|
28
|
+
requirements: AcceptancePolicyRequirement[];
|
|
29
|
+
diagnostics: AcceptancePolicyAssessmentDiagnostic[];
|
|
30
|
+
}
|
|
31
|
+
export interface AcceptancePolicyMatchedRule {
|
|
32
|
+
profileId: string;
|
|
33
|
+
ruleId: string;
|
|
34
|
+
disposition: AcceptancePolicyRule['disposition'];
|
|
35
|
+
policyIds: string[];
|
|
36
|
+
requirements: AcceptancePolicyRequirement[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Compose verified seller-default and product acceptance profiles
|
|
40
|
+
* restrictively for one decision surface.
|
|
41
|
+
*
|
|
42
|
+
* The result is preflight guidance, not authorization. Missing profiles,
|
|
43
|
+
* partial coverage, out-of-scope complete profiles, and omitted buyer facts
|
|
44
|
+
* remain `unknown`; an explicit matching prohibition still wins.
|
|
45
|
+
*/
|
|
46
|
+
export declare function assessAcceptancePolicy(input: AssessAcceptancePolicyInput): AcceptancePolicyAssessment;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Conservative, advisory evaluation of already-verified acceptance profiles. */
|
|
2
|
+
import type { AcceptanceContext } from '../types/core.generated';
|
|
3
|
+
import type { AcceptancePolicyProfileResolution, AcceptancePolicyRequirement, AcceptancePolicyRule, AcceptancePolicySurface } from './index';
|
|
4
|
+
export type AcceptancePolicyOutcome = 'allowed' | 'prohibited' | 'requires_disclosure' | 'requires_setup' | 'requires_review' | 'unknown';
|
|
5
|
+
export type AcceptancePolicyAssessmentDiagnosticCode = 'profile_unresolved' | 'profile_conflict' | 'invalid_profile' | 'assessment_limit_exceeded' | 'partial_coverage' | 'incomplete_context' | 'invalid_context' | 'invalid_evaluation_time' | 'schema_unavailable';
|
|
6
|
+
export interface AcceptancePolicyAssessmentDiagnostic {
|
|
7
|
+
code: AcceptancePolicyAssessmentDiagnosticCode;
|
|
8
|
+
profileId?: string;
|
|
9
|
+
ruleId?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AssessAcceptancePolicyInput {
|
|
12
|
+
/** Seller-default and product profiles to compose. Unresolved entries fail closed. */
|
|
13
|
+
profiles: readonly AcceptancePolicyProfileResolution[];
|
|
14
|
+
acceptanceContext: AcceptanceContext;
|
|
15
|
+
appliesTo: AcceptancePolicySurface;
|
|
16
|
+
/** Evaluation instant for rule windows. Defaults to the current time. */
|
|
17
|
+
evaluatedAt?: Date | string;
|
|
18
|
+
/** Schema bundle used to validate acceptanceContext and each resolved profile. Defaults to the SDK pin. */
|
|
19
|
+
adcpVersion?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface AcceptancePolicyAssessment {
|
|
22
|
+
/** Advisory only. The seller's response to an exact request remains authoritative. */
|
|
23
|
+
advisory: true;
|
|
24
|
+
outcome: AcceptancePolicyOutcome;
|
|
25
|
+
profileIds: string[];
|
|
26
|
+
matchingRuleIds: string[];
|
|
27
|
+
matchedRules: AcceptancePolicyMatchedRule[];
|
|
28
|
+
requirements: AcceptancePolicyRequirement[];
|
|
29
|
+
diagnostics: AcceptancePolicyAssessmentDiagnostic[];
|
|
30
|
+
}
|
|
31
|
+
export interface AcceptancePolicyMatchedRule {
|
|
32
|
+
profileId: string;
|
|
33
|
+
ruleId: string;
|
|
34
|
+
disposition: AcceptancePolicyRule['disposition'];
|
|
35
|
+
policyIds: string[];
|
|
36
|
+
requirements: AcceptancePolicyRequirement[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Compose verified seller-default and product acceptance profiles
|
|
40
|
+
* restrictively for one decision surface.
|
|
41
|
+
*
|
|
42
|
+
* The result is preflight guidance, not authorization. Missing profiles,
|
|
43
|
+
* partial coverage, out-of-scope complete profiles, and omitted buyer facts
|
|
44
|
+
* remain `unknown`; an explicit matching prohibition still wins.
|
|
45
|
+
*/
|
|
46
|
+
export declare function assessAcceptancePolicy(input: AssessAcceptancePolicyInput): AcceptancePolicyAssessment;
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var evaluator_exports = {};
|
|
20
|
+
__export(evaluator_exports, {
|
|
21
|
+
assessAcceptancePolicy: () => assessAcceptancePolicy
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(evaluator_exports);
|
|
24
|
+
var import_schema_loader = require('../validation/schema-loader.js');
|
|
25
|
+
var import_version = require('../version.js');
|
|
26
|
+
const CONTEXT_SCHEMA_REF = "media-buy/acceptance-context.json";
|
|
27
|
+
const PROFILE_SCHEMA_REF = "media-buy/acceptance-policy-profile.json";
|
|
28
|
+
const MAX_ASSESSMENT_PROFILES = 1024;
|
|
29
|
+
const MAX_ASSESSMENT_RULES = 1e4;
|
|
30
|
+
const MAX_ASSESSMENT_CONTEXT_VALUES = 4096;
|
|
31
|
+
const MAX_ASSESSMENT_JSON_NODES = 1e5;
|
|
32
|
+
const MAX_ASSESSMENT_STRING_CODE_UNITS = 1024 * 1024;
|
|
33
|
+
const MAX_ASSESSMENT_JSON_DEPTH = 64;
|
|
34
|
+
const MAX_ASSESSMENT_DIAGNOSTICS = 32;
|
|
35
|
+
const SURFACES = /* @__PURE__ */ new Set([
|
|
36
|
+
"account",
|
|
37
|
+
"media_buy",
|
|
38
|
+
"creative",
|
|
39
|
+
"landing_page",
|
|
40
|
+
"targeting",
|
|
41
|
+
"delivery",
|
|
42
|
+
"format"
|
|
43
|
+
]);
|
|
44
|
+
const REVIEW_REQUIREMENTS = /* @__PURE__ */ new Set([
|
|
45
|
+
"prior_authorization",
|
|
46
|
+
"sales_assisted",
|
|
47
|
+
"funding_restriction",
|
|
48
|
+
"targeting_restriction",
|
|
49
|
+
"creative_restriction",
|
|
50
|
+
"destination_restriction",
|
|
51
|
+
"format_restriction",
|
|
52
|
+
"time_restriction",
|
|
53
|
+
"custom"
|
|
54
|
+
]);
|
|
55
|
+
const SETUP_REQUIREMENTS = /* @__PURE__ */ new Set([
|
|
56
|
+
"advertiser_verification",
|
|
57
|
+
"advertiser_eligibility",
|
|
58
|
+
"certification",
|
|
59
|
+
"license",
|
|
60
|
+
"account_setup"
|
|
61
|
+
]);
|
|
62
|
+
const DISCLOSURE_REQUIREMENTS = /* @__PURE__ */ new Set(["category_declaration", "disclosure", "transparency_reporting"]);
|
|
63
|
+
function diagnostic(code, profileId, ruleId) {
|
|
64
|
+
return {
|
|
65
|
+
code,
|
|
66
|
+
...profileId !== void 0 && { profileId },
|
|
67
|
+
...ruleId !== void 0 && { ruleId }
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function dedupeDiagnostics(diagnostics) {
|
|
71
|
+
const seen = /* @__PURE__ */ new Set();
|
|
72
|
+
const result = [];
|
|
73
|
+
for (const value of diagnostics) {
|
|
74
|
+
const key = `${value.code}\0${value.profileId ?? ""}\0${value.ruleId ?? ""}`;
|
|
75
|
+
if (seen.has(key)) continue;
|
|
76
|
+
seen.add(key);
|
|
77
|
+
result.push(value);
|
|
78
|
+
if (result.length >= MAX_ASSESSMENT_DIAGNOSTICS) break;
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
function unknownAssessment(profileIds, diagnostics) {
|
|
83
|
+
return {
|
|
84
|
+
advisory: true,
|
|
85
|
+
outcome: "unknown",
|
|
86
|
+
profileIds,
|
|
87
|
+
matchingRuleIds: [],
|
|
88
|
+
matchedRules: [],
|
|
89
|
+
requirements: [],
|
|
90
|
+
diagnostics: dedupeDiagnostics(diagnostics)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function expandedJurisdictions(profile, groups) {
|
|
94
|
+
const jurisdictions = /* @__PURE__ */ new Set();
|
|
95
|
+
for (const group of groups) {
|
|
96
|
+
if (!Object.prototype.hasOwnProperty.call(profile.region_aliases ?? {}, group)) continue;
|
|
97
|
+
for (const jurisdiction of profile.region_aliases?.[group] ?? []) jurisdictions.add(jurisdiction);
|
|
98
|
+
}
|
|
99
|
+
return jurisdictions;
|
|
100
|
+
}
|
|
101
|
+
function profileAliasesResolve(profile) {
|
|
102
|
+
const aliases = profile.region_aliases ?? {};
|
|
103
|
+
const groups = [
|
|
104
|
+
...profile.scope?.jurisdiction_groups ?? [],
|
|
105
|
+
...profile.rules.flatMap((rule) => rule.jurisdiction_groups ?? [])
|
|
106
|
+
];
|
|
107
|
+
return groups.every((group) => Object.prototype.hasOwnProperty.call(aliases, group));
|
|
108
|
+
}
|
|
109
|
+
function completeScopeCovers(profile, context, appliesTo) {
|
|
110
|
+
const scope = profile.scope;
|
|
111
|
+
if (!scope?.applies_to?.includes(appliesTo)) return false;
|
|
112
|
+
if (!context.subjects?.length || !scope.subject_categories?.length) return false;
|
|
113
|
+
const scopedCategories = new Set(scope.subject_categories);
|
|
114
|
+
if (context.subjects.some((subject) => !scopedCategories.has(subject.subject_category))) return false;
|
|
115
|
+
if (scope.all_jurisdictions === true) return true;
|
|
116
|
+
if (!context.delivery_jurisdictions?.length) return false;
|
|
117
|
+
const covered = new Set(scope.jurisdictions ?? []);
|
|
118
|
+
for (const jurisdiction of expandedJurisdictions(profile, scope.jurisdiction_groups ?? [])) {
|
|
119
|
+
covered.add(jurisdiction);
|
|
120
|
+
}
|
|
121
|
+
return context.delivery_jurisdictions.every((jurisdiction) => covered.has(jurisdiction));
|
|
122
|
+
}
|
|
123
|
+
function ruleMatches(profile, rule, contextIndex, appliesTo, evaluatedAtMs) {
|
|
124
|
+
if (!rule.applies_to.includes(appliesTo)) return false;
|
|
125
|
+
let uncertain = false;
|
|
126
|
+
if (rule.effective_at !== void 0) {
|
|
127
|
+
const effectiveAtMs = Date.parse(rule.effective_at);
|
|
128
|
+
if (!Number.isFinite(effectiveAtMs)) uncertain = true;
|
|
129
|
+
else if (evaluatedAtMs < effectiveAtMs) return false;
|
|
130
|
+
}
|
|
131
|
+
if (rule.expires_at !== void 0) {
|
|
132
|
+
const expiresAtMs = Date.parse(rule.expires_at);
|
|
133
|
+
if (!Number.isFinite(expiresAtMs)) uncertain = true;
|
|
134
|
+
else if (evaluatedAtMs >= expiresAtMs) return false;
|
|
135
|
+
}
|
|
136
|
+
const subjects = contextIndex.subjectsByCategory.get(rule.subject_category);
|
|
137
|
+
if (!contextIndex.hasSubjects) {
|
|
138
|
+
uncertain = true;
|
|
139
|
+
} else if (!subjects) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
if (subjects && rule.subject_facets?.length) {
|
|
143
|
+
if (!rule.subject_facets.some((facet) => subjects.facets.has(facet))) {
|
|
144
|
+
if (!subjects.hasMissingFacets) return false;
|
|
145
|
+
uncertain = true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (rule.advertiser_roles?.length) {
|
|
149
|
+
if (contextIndex.advertiserRoles.size === 0) {
|
|
150
|
+
uncertain = true;
|
|
151
|
+
} else if (!rule.advertiser_roles.some((role) => contextIndex.advertiserRoles.has(role))) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (rule.jurisdictions?.length || rule.jurisdiction_groups?.length) {
|
|
156
|
+
if (rule.jurisdiction_groups?.some(
|
|
157
|
+
(group) => !Object.prototype.hasOwnProperty.call(profile.region_aliases ?? {}, group)
|
|
158
|
+
)) {
|
|
159
|
+
return "unknown";
|
|
160
|
+
}
|
|
161
|
+
if (contextIndex.deliveryJurisdictions.size === 0) {
|
|
162
|
+
uncertain = true;
|
|
163
|
+
} else {
|
|
164
|
+
const expected = new Set(rule.jurisdictions ?? []);
|
|
165
|
+
for (const jurisdiction of expandedJurisdictions(profile, rule.jurisdiction_groups ?? [])) {
|
|
166
|
+
expected.add(jurisdiction);
|
|
167
|
+
}
|
|
168
|
+
if (![...expected].some((jurisdiction) => contextIndex.deliveryJurisdictions.has(jurisdiction))) return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return uncertain ? "unknown" : true;
|
|
172
|
+
}
|
|
173
|
+
function requirementsOutcome(requirements) {
|
|
174
|
+
const kinds = new Set(requirements.map((requirement) => String(requirement.kind)));
|
|
175
|
+
if ([...kinds].some((kind) => REVIEW_REQUIREMENTS.has(kind))) return "requires_review";
|
|
176
|
+
if ([...kinds].some((kind) => SETUP_REQUIREMENTS.has(kind))) return "requires_setup";
|
|
177
|
+
if ([...kinds].every((kind) => DISCLOSURE_REQUIREMENTS.has(kind))) return "requires_disclosure";
|
|
178
|
+
return "requires_review";
|
|
179
|
+
}
|
|
180
|
+
function cloneRequirement(requirement) {
|
|
181
|
+
return JSON.parse(JSON.stringify(requirement));
|
|
182
|
+
}
|
|
183
|
+
function consumeAssessmentComplexity(value, budget) {
|
|
184
|
+
const pending = [{ value, depth: 0 }];
|
|
185
|
+
const ancestors = /* @__PURE__ */ new WeakSet();
|
|
186
|
+
let queuedNodes = 1;
|
|
187
|
+
while (pending.length > 0) {
|
|
188
|
+
const current = pending.pop();
|
|
189
|
+
if (current.exit) {
|
|
190
|
+
ancestors.delete(current.value);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
queuedNodes -= 1;
|
|
194
|
+
budget.nodes += 1;
|
|
195
|
+
if (budget.nodes > MAX_ASSESSMENT_JSON_NODES) return "limit";
|
|
196
|
+
if (current.depth > MAX_ASSESSMENT_JSON_DEPTH) return "invalid";
|
|
197
|
+
if (typeof current.value === "string") {
|
|
198
|
+
budget.stringCodeUnits += current.value.length;
|
|
199
|
+
if (budget.stringCodeUnits > MAX_ASSESSMENT_STRING_CODE_UNITS) return "limit";
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (current.value === null || typeof current.value !== "object") continue;
|
|
203
|
+
if (ancestors.has(current.value)) return "invalid";
|
|
204
|
+
ancestors.add(current.value);
|
|
205
|
+
pending.push({ ...current, exit: true });
|
|
206
|
+
if (Array.isArray(current.value)) {
|
|
207
|
+
if (budget.nodes + queuedNodes + current.value.length > MAX_ASSESSMENT_JSON_NODES) return "limit";
|
|
208
|
+
queuedNodes += current.value.length;
|
|
209
|
+
for (const child of current.value) pending.push({ value: child, depth: current.depth + 1 });
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const record = current.value;
|
|
213
|
+
for (const key in record) {
|
|
214
|
+
if (!Object.prototype.hasOwnProperty.call(record, key)) continue;
|
|
215
|
+
budget.stringCodeUnits += key.length;
|
|
216
|
+
if (budget.stringCodeUnits > MAX_ASSESSMENT_STRING_CODE_UNITS) return "limit";
|
|
217
|
+
if (budget.nodes + queuedNodes + 1 > MAX_ASSESSMENT_JSON_NODES) return "limit";
|
|
218
|
+
queuedNodes += 1;
|
|
219
|
+
pending.push({ value: record[key], depth: current.depth + 1 });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return "valid";
|
|
223
|
+
}
|
|
224
|
+
function exceedsContextValueLimit(context) {
|
|
225
|
+
const subjects = Array.isArray(context.subjects) ? context.subjects : [];
|
|
226
|
+
const advertiserRoles = Array.isArray(context.advertiser_roles) ? context.advertiser_roles : [];
|
|
227
|
+
const deliveryJurisdictions = Array.isArray(context.delivery_jurisdictions) ? context.delivery_jurisdictions : [];
|
|
228
|
+
if (subjects.length > MAX_ASSESSMENT_CONTEXT_VALUES || advertiserRoles.length > MAX_ASSESSMENT_CONTEXT_VALUES || deliveryJurisdictions.length > MAX_ASSESSMENT_CONTEXT_VALUES) {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
let values = subjects.length + advertiserRoles.length + deliveryJurisdictions.length;
|
|
232
|
+
for (const subject of subjects) {
|
|
233
|
+
if (!subject || typeof subject !== "object" || !Array.isArray(subject.subject_facets)) continue;
|
|
234
|
+
values += subject.subject_facets.length;
|
|
235
|
+
if (values > MAX_ASSESSMENT_CONTEXT_VALUES) return true;
|
|
236
|
+
}
|
|
237
|
+
return values > MAX_ASSESSMENT_CONTEXT_VALUES;
|
|
238
|
+
}
|
|
239
|
+
function assessAcceptancePolicy(input) {
|
|
240
|
+
if (!input || typeof input !== "object" || !Array.isArray(input.profiles)) {
|
|
241
|
+
return unknownAssessment([], [diagnostic("invalid_profile")]);
|
|
242
|
+
}
|
|
243
|
+
if (input.profiles.length > MAX_ASSESSMENT_PROFILES) {
|
|
244
|
+
return unknownAssessment([], [diagnostic("assessment_limit_exceeded")]);
|
|
245
|
+
}
|
|
246
|
+
const profileIds = [
|
|
247
|
+
...new Set(
|
|
248
|
+
input.profiles.flatMap(
|
|
249
|
+
(value) => value && typeof value === "object" && value.resolution === "resolved" && typeof value.profileId === "string" ? [value.profileId] : []
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
];
|
|
253
|
+
if (input.profiles.length === 0) {
|
|
254
|
+
return unknownAssessment(profileIds, [diagnostic("profile_unresolved")]);
|
|
255
|
+
}
|
|
256
|
+
if (!input.acceptanceContext || typeof input.acceptanceContext !== "object") {
|
|
257
|
+
return unknownAssessment(profileIds, [diagnostic("invalid_context")]);
|
|
258
|
+
}
|
|
259
|
+
if (!SURFACES.has(input.appliesTo)) {
|
|
260
|
+
return unknownAssessment(profileIds, [diagnostic("incomplete_context")]);
|
|
261
|
+
}
|
|
262
|
+
if (exceedsContextValueLimit(input.acceptanceContext)) {
|
|
263
|
+
return unknownAssessment(profileIds, [diagnostic("assessment_limit_exceeded")]);
|
|
264
|
+
}
|
|
265
|
+
const contextComplexity = consumeAssessmentComplexity(input.acceptanceContext, {
|
|
266
|
+
nodes: 0,
|
|
267
|
+
stringCodeUnits: 0
|
|
268
|
+
});
|
|
269
|
+
if (contextComplexity === "limit") {
|
|
270
|
+
return unknownAssessment(profileIds, [diagnostic("assessment_limit_exceeded")]);
|
|
271
|
+
}
|
|
272
|
+
if (contextComplexity === "invalid") {
|
|
273
|
+
return unknownAssessment(profileIds, [diagnostic("invalid_context")]);
|
|
274
|
+
}
|
|
275
|
+
let contextValidator;
|
|
276
|
+
let profileValidator;
|
|
277
|
+
try {
|
|
278
|
+
const adcpVersion = input.adcpVersion ?? import_version.ADCP_VERSION;
|
|
279
|
+
contextValidator = (0, import_schema_loader.getSchemaValidatorByRef)(CONTEXT_SCHEMA_REF, adcpVersion);
|
|
280
|
+
profileValidator = (0, import_schema_loader.getSchemaValidatorByRef)(PROFILE_SCHEMA_REF, adcpVersion);
|
|
281
|
+
} catch {
|
|
282
|
+
return unknownAssessment(profileIds, [diagnostic("schema_unavailable")]);
|
|
283
|
+
}
|
|
284
|
+
if (!contextValidator || !profileValidator) {
|
|
285
|
+
return unknownAssessment(profileIds, [diagnostic("schema_unavailable")]);
|
|
286
|
+
}
|
|
287
|
+
if (!contextValidator(input.acceptanceContext)) {
|
|
288
|
+
return unknownAssessment(profileIds, [diagnostic("invalid_context")]);
|
|
289
|
+
}
|
|
290
|
+
const mutableSubjectsByCategory = /* @__PURE__ */ new Map();
|
|
291
|
+
for (const subject of input.acceptanceContext.subjects ?? []) {
|
|
292
|
+
const indexed = mutableSubjectsByCategory.get(subject.subject_category) ?? {
|
|
293
|
+
facets: /* @__PURE__ */ new Set(),
|
|
294
|
+
hasMissingFacets: false
|
|
295
|
+
};
|
|
296
|
+
if (!subject.subject_facets?.length) indexed.hasMissingFacets = true;
|
|
297
|
+
else for (const facet of subject.subject_facets) indexed.facets.add(facet);
|
|
298
|
+
mutableSubjectsByCategory.set(subject.subject_category, indexed);
|
|
299
|
+
}
|
|
300
|
+
const contextIndex = {
|
|
301
|
+
hasSubjects: (input.acceptanceContext.subjects?.length ?? 0) > 0,
|
|
302
|
+
subjectsByCategory: mutableSubjectsByCategory,
|
|
303
|
+
advertiserRoles: new Set(input.acceptanceContext.advertiser_roles ?? []),
|
|
304
|
+
deliveryJurisdictions: new Set(input.acceptanceContext.delivery_jurisdictions ?? [])
|
|
305
|
+
};
|
|
306
|
+
const evaluatedAt = input.evaluatedAt ?? /* @__PURE__ */ new Date();
|
|
307
|
+
const evaluatedAtMs = evaluatedAt instanceof Date ? evaluatedAt.getTime() : Date.parse(evaluatedAt);
|
|
308
|
+
if (!Number.isFinite(evaluatedAtMs)) {
|
|
309
|
+
return unknownAssessment(profileIds, [diagnostic("invalid_evaluation_time")]);
|
|
310
|
+
}
|
|
311
|
+
const diagnostics = [];
|
|
312
|
+
const matchingRules = [];
|
|
313
|
+
let uncertain = false;
|
|
314
|
+
const profiles = [];
|
|
315
|
+
const profileIdentities = /* @__PURE__ */ new Map();
|
|
316
|
+
const seenProfileIdentities = /* @__PURE__ */ new Set();
|
|
317
|
+
const countedProfileIdentities = /* @__PURE__ */ new Set();
|
|
318
|
+
const measuredProfileObjects = /* @__PURE__ */ new WeakSet();
|
|
319
|
+
const invalidProfileObjects = /* @__PURE__ */ new WeakSet();
|
|
320
|
+
const profileValidationResults = /* @__PURE__ */ new WeakMap();
|
|
321
|
+
const profileAliasResults = /* @__PURE__ */ new WeakMap();
|
|
322
|
+
const complexityBudget = { nodes: 0, stringCodeUnits: 0 };
|
|
323
|
+
let candidateRuleCount = 0;
|
|
324
|
+
for (const value of input.profiles) {
|
|
325
|
+
if (!value || typeof value !== "object" || typeof value.profileId !== "string") {
|
|
326
|
+
uncertain = true;
|
|
327
|
+
diagnostics.push(diagnostic("invalid_profile"));
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (value.resolution !== "resolved") {
|
|
331
|
+
uncertain = true;
|
|
332
|
+
diagnostics.push(
|
|
333
|
+
value.resolution === "missing" || value.resolution === "unresolved" ? diagnostic("profile_unresolved", value.profileId) : diagnostic("invalid_profile", value.profileId)
|
|
334
|
+
);
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
const profileValue = value.profile;
|
|
338
|
+
if (profileValue && typeof profileValue === "object" && invalidProfileObjects.has(profileValue)) {
|
|
339
|
+
uncertain = true;
|
|
340
|
+
diagnostics.push(diagnostic("invalid_profile", value.profileId));
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (profileValue && typeof profileValue === "object" && !measuredProfileObjects.has(profileValue)) {
|
|
344
|
+
measuredProfileObjects.add(profileValue);
|
|
345
|
+
const complexity = consumeAssessmentComplexity(profileValue, complexityBudget);
|
|
346
|
+
if (complexity === "limit") {
|
|
347
|
+
return unknownAssessment(profileIds, [...diagnostics, diagnostic("assessment_limit_exceeded")]);
|
|
348
|
+
}
|
|
349
|
+
if (complexity === "invalid") {
|
|
350
|
+
invalidProfileObjects.add(profileValue);
|
|
351
|
+
uncertain = true;
|
|
352
|
+
diagnostics.push(diagnostic("invalid_profile", value.profileId));
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const candidateIdentityKey = typeof value.profile?.version === "string" && typeof value.profile?.content_digest === "string" ? `${value.profileId}\0${value.profile.version}\0${value.profile.content_digest}` : void 0;
|
|
357
|
+
if ((candidateIdentityKey === void 0 || !countedProfileIdentities.has(candidateIdentityKey)) && Array.isArray(value.profile?.rules)) {
|
|
358
|
+
if (candidateIdentityKey !== void 0) countedProfileIdentities.add(candidateIdentityKey);
|
|
359
|
+
candidateRuleCount += value.profile.rules.length;
|
|
360
|
+
if (candidateRuleCount > MAX_ASSESSMENT_RULES) {
|
|
361
|
+
return unknownAssessment(profileIds, [...diagnostics, diagnostic("assessment_limit_exceeded")]);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
let validProfile = false;
|
|
365
|
+
if (profileValue && typeof profileValue === "object" && profileValidationResults.has(profileValue)) {
|
|
366
|
+
validProfile = profileValidationResults.get(profileValue) ?? false;
|
|
367
|
+
} else {
|
|
368
|
+
try {
|
|
369
|
+
validProfile = profileValidator(value.profile);
|
|
370
|
+
} catch {
|
|
371
|
+
validProfile = false;
|
|
372
|
+
}
|
|
373
|
+
if (profileValue && typeof profileValue === "object") {
|
|
374
|
+
profileValidationResults.set(profileValue, validProfile);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (!validProfile || value.profile.profile_id !== value.profileId) {
|
|
378
|
+
uncertain = true;
|
|
379
|
+
diagnostics.push(diagnostic("invalid_profile", value.profileId));
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
let aliasesValid = profileAliasResults.get(profileValue);
|
|
383
|
+
if (aliasesValid === void 0) {
|
|
384
|
+
aliasesValid = profileAliasesResolve(value.profile);
|
|
385
|
+
profileAliasResults.set(profileValue, aliasesValid);
|
|
386
|
+
}
|
|
387
|
+
if (!aliasesValid) {
|
|
388
|
+
uncertain = true;
|
|
389
|
+
diagnostics.push(diagnostic("invalid_profile", value.profileId));
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
const identityKey = `${value.profileId}\0${value.profile.version}\0${value.profile.content_digest}`;
|
|
393
|
+
if (seenProfileIdentities.has(identityKey)) continue;
|
|
394
|
+
seenProfileIdentities.add(identityKey);
|
|
395
|
+
const knownIdentity = profileIdentities.get(value.profileId);
|
|
396
|
+
if (knownIdentity && (knownIdentity.version !== value.profile.version || knownIdentity.contentDigest !== value.profile.content_digest)) {
|
|
397
|
+
uncertain = true;
|
|
398
|
+
diagnostics.push(diagnostic("profile_conflict", value.profileId));
|
|
399
|
+
profiles.push(value.profile);
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
if (knownIdentity) continue;
|
|
403
|
+
profileIdentities.set(value.profileId, {
|
|
404
|
+
version: value.profile.version,
|
|
405
|
+
contentDigest: value.profile.content_digest
|
|
406
|
+
});
|
|
407
|
+
profiles.push(value.profile);
|
|
408
|
+
}
|
|
409
|
+
for (const profile of profiles) {
|
|
410
|
+
if (profile.coverage === "partial") {
|
|
411
|
+
uncertain = true;
|
|
412
|
+
diagnostics.push(diagnostic("partial_coverage", profile.profile_id));
|
|
413
|
+
} else if (!completeScopeCovers(profile, input.acceptanceContext, input.appliesTo)) {
|
|
414
|
+
uncertain = true;
|
|
415
|
+
diagnostics.push(diagnostic("incomplete_context", profile.profile_id));
|
|
416
|
+
}
|
|
417
|
+
for (const rule of profile.rules) {
|
|
418
|
+
const match = ruleMatches(profile, rule, contextIndex, input.appliesTo, evaluatedAtMs);
|
|
419
|
+
if (match === true) matchingRules.push({ profileId: profile.profile_id, rule });
|
|
420
|
+
if (match === "unknown") {
|
|
421
|
+
uncertain = true;
|
|
422
|
+
diagnostics.push(diagnostic("incomplete_context", profile.profile_id, rule.rule_id));
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const requirements = matchingRules.flatMap((value) => value.rule.requirements ?? []);
|
|
427
|
+
const outcome = matchingRules.some((value) => value.rule.disposition === "prohibited") ? "prohibited" : uncertain ? "unknown" : requirements.length > 0 ? requirementsOutcome(requirements) : "allowed";
|
|
428
|
+
return {
|
|
429
|
+
advisory: true,
|
|
430
|
+
outcome,
|
|
431
|
+
profileIds: [...profileIdentities.keys()],
|
|
432
|
+
matchingRuleIds: matchingRules.map((value) => value.rule.rule_id),
|
|
433
|
+
matchedRules: matchingRules.map(({ profileId, rule }) => ({
|
|
434
|
+
profileId,
|
|
435
|
+
ruleId: rule.rule_id,
|
|
436
|
+
disposition: rule.disposition,
|
|
437
|
+
policyIds: [...rule.policy_ids ?? []],
|
|
438
|
+
requirements: (rule.requirements ?? []).map(cloneRequirement)
|
|
439
|
+
})),
|
|
440
|
+
requirements: requirements.map(cloneRequirement),
|
|
441
|
+
diagnostics: dedupeDiagnostics(diagnostics)
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
445
|
+
0 && (module.exports = {
|
|
446
|
+
assessAcceptancePolicy
|
|
447
|
+
});
|