@adcp/sdk 14.0.0-rc.39 → 14.0.0-rc.40
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/README.md +2 -0
- package/dist/lib/core/AgentClient.d.mts +4 -3
- package/dist/lib/core/AgentClient.d.ts +4 -3
- package/dist/lib/core/AsyncHandler.d.mts +3 -0
- package/dist/lib/core/AsyncHandler.d.ts +3 -0
- package/dist/lib/core/AsyncHandler.js +3 -0
- package/dist/lib/core/AsyncHandler.mjs +3 -0
- package/dist/lib/core/SingleAgentClient.d.mts +6 -1
- package/dist/lib/core/SingleAgentClient.d.ts +6 -1
- package/dist/lib/core/SingleAgentClient.js +57 -17
- package/dist/lib/core/SingleAgentClient.mjs +59 -17
- package/dist/lib/discovery/adagents-redirects.d.mts +5 -1
- package/dist/lib/discovery/adagents-redirects.d.ts +5 -1
- package/dist/lib/discovery/adagents-redirects.js +10 -3
- package/dist/lib/discovery/adagents-redirects.mjs +10 -3
- package/dist/lib/discovery/types.d.mts +42 -0
- package/dist/lib/discovery/types.d.ts +42 -0
- package/dist/lib/index.d.mts +3 -1
- package/dist/lib/index.d.ts +3 -1
- package/dist/lib/index.js +3 -1
- package/dist/lib/index.mjs +1 -0
- package/dist/lib/net/ssrf-fetch.js +47 -21
- package/dist/lib/net/ssrf-fetch.mjs +47 -21
- package/dist/lib/registry/index.d.mts +3 -0
- package/dist/lib/registry/index.d.ts +3 -0
- package/dist/lib/registry/index.js +8 -0
- package/dist/lib/registry/index.mjs +8 -0
- package/dist/lib/registry/types.d.mts +2 -1
- package/dist/lib/registry/types.d.ts +2 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/supply-path/evaluate.d.mts +17 -0
- package/dist/lib/supply-path/evaluate.d.ts +17 -0
- package/dist/lib/supply-path/evaluate.js +436 -0
- package/dist/lib/supply-path/evaluate.mjs +407 -0
- package/dist/lib/supply-path/fetch-evidence.d.mts +36 -0
- package/dist/lib/supply-path/fetch-evidence.d.ts +36 -0
- package/dist/lib/supply-path/fetch-evidence.js +293 -0
- package/dist/lib/supply-path/fetch-evidence.mjs +268 -0
- package/dist/lib/supply-path/index.d.mts +6 -0
- package/dist/lib/supply-path/index.d.ts +6 -0
- package/dist/lib/supply-path/index.js +49 -0
- package/dist/lib/supply-path/index.mjs +23 -0
- package/dist/lib/supply-path/products.d.mts +41 -0
- package/dist/lib/supply-path/products.d.ts +41 -0
- package/dist/lib/supply-path/products.js +228 -0
- package/dist/lib/supply-path/products.mjs +204 -0
- package/dist/lib/supply-path/revocations.d.mts +55 -0
- package/dist/lib/supply-path/revocations.d.ts +55 -0
- package/dist/lib/supply-path/revocations.js +127 -0
- package/dist/lib/supply-path/revocations.mjs +99 -0
- package/dist/lib/supply-path/types.d.mts +168 -0
- package/dist/lib/supply-path/types.d.ts +168 -0
- package/dist/lib/supply-path/types.js +16 -0
- package/dist/lib/supply-path/types.mjs +0 -0
- package/dist/lib/supply-path/validation.d.mts +10 -0
- package/dist/lib/supply-path/validation.d.ts +10 -0
- package/dist/lib/supply-path/validation.js +152 -0
- package/dist/lib/supply-path/validation.mjs +122 -0
- package/dist/lib/supply-path/verify.d.mts +25 -0
- package/dist/lib/supply-path/verify.d.ts +25 -0
- package/dist/lib/supply-path/verify.js +218 -0
- package/dist/lib/supply-path/verify.mjs +203 -0
- package/dist/lib/testing/storyboard/request-signing/grader.js +19 -9
- package/dist/lib/testing/storyboard/request-signing/grader.mjs +19 -9
- 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.d.mts +1 -1
- package/dist/lib/v2/projection/creative-delivery.d.ts +1 -1
- package/dist/lib/validation/schema-loader.js +7 -5
- package/dist/lib/validation/schema-loader.mjs +7 -5
- 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/SUPPLY-PATH-VERIFICATION.md +101 -0
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/examples/README.md +2 -0
- package/examples/supply-path-verification.ts +29 -0
- package/package.json +2 -1
|
@@ -0,0 +1,152 @@
|
|
|
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 validation_exports = {};
|
|
20
|
+
__export(validation_exports, {
|
|
21
|
+
agentIdentity: () => agentIdentity,
|
|
22
|
+
assertRegistrySupplyPathResult: () => assertRegistrySupplyPathResult,
|
|
23
|
+
domain: () => domain,
|
|
24
|
+
record: () => record,
|
|
25
|
+
records: () => records,
|
|
26
|
+
strings: () => strings,
|
|
27
|
+
validateSupplyPathRequest: () => validateSupplyPathRequest
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(validation_exports);
|
|
30
|
+
var import_node_net = require("node:net");
|
|
31
|
+
var import_resolve_agent_properties = require('../discovery/resolve-agent-properties.js');
|
|
32
|
+
function record(value) {
|
|
33
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
34
|
+
}
|
|
35
|
+
function records(value) {
|
|
36
|
+
return Array.isArray(value) ? value.filter(record) : [];
|
|
37
|
+
}
|
|
38
|
+
function strings(value) {
|
|
39
|
+
return Array.isArray(value) && value.length > 0 && value.every((v) => typeof v === "string" && v.trim().length > 0);
|
|
40
|
+
}
|
|
41
|
+
function domain(value) {
|
|
42
|
+
if (typeof value !== "string") return null;
|
|
43
|
+
const normalized = value.toLowerCase().replace(/\.$/, "");
|
|
44
|
+
if (normalized.length > 253 || (0, import_node_net.isIP)(normalized) || !normalized.includes(".")) return null;
|
|
45
|
+
return normalized.split(".").every((label) => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label)) ? normalized : null;
|
|
46
|
+
}
|
|
47
|
+
function agentIdentity(value) {
|
|
48
|
+
if (typeof value !== "string" || /[\s\x00-\x1f\x7f]/.test(value)) return null;
|
|
49
|
+
const canonical = (0, import_resolve_agent_properties.canonicalizeAgentUrl)(value);
|
|
50
|
+
return canonical?.startsWith("https://") ? canonical : null;
|
|
51
|
+
}
|
|
52
|
+
function validateSupplyPathRequest(input) {
|
|
53
|
+
if (!record(input)) throw new TypeError("Supply-path request must be an object");
|
|
54
|
+
const owner = domain(input.owner_domain);
|
|
55
|
+
const host = domain(input.host_domain);
|
|
56
|
+
if (!owner || !host) throw new TypeError("owner_domain and host_domain must be DNS publisher domains");
|
|
57
|
+
if (!agentIdentity(input.agent_url)) throw new TypeError("agent_url must be an HTTPS URL without credentials");
|
|
58
|
+
if (input.collection_id !== void 0 && (typeof input.collection_id !== "string" || !input.collection_id.trim() || input.collection_id.length > 256)) {
|
|
59
|
+
throw new TypeError("collection_id must be a non-empty string of at most 256 characters");
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
owner_domain: owner,
|
|
63
|
+
host_domain: host,
|
|
64
|
+
agent_url: input.agent_url,
|
|
65
|
+
...input.collection_id !== void 0 ? { collection_id: input.collection_id } : {}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function assertRegistrySupplyPathResult(value, request) {
|
|
69
|
+
const fail = (invariant) => {
|
|
70
|
+
throw new TypeError(
|
|
71
|
+
`Invalid registry supply-path response: ${invariant}; verification cannot be accepted, check the registry response contract`
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
if (!record(value)) return fail("response must be an object");
|
|
75
|
+
if (value.semantics_version !== "1")
|
|
76
|
+
throw new TypeError("Invalid registry supply-path response: semantics_version 1 required; upgrade the registry");
|
|
77
|
+
if (!record(value.legs) || !record(value.sources)) return fail("legs and sources must be objects");
|
|
78
|
+
if (!["verified_owner_sold", "host_delegated", "owner_attested", "unverified"].includes(String(value.state)))
|
|
79
|
+
return fail("state is not recognized");
|
|
80
|
+
if (domain(value.owner_domain) !== request.owner_domain || domain(value.host_domain) !== request.host_domain || agentIdentity(value.agent_url) !== agentIdentity(request.agent_url) || value.collection_id !== request.collection_id)
|
|
81
|
+
return fail("request identity does not match the submitted owner, host, agent, and collection");
|
|
82
|
+
if (typeof value.checked_at !== "string" || !Number.isFinite(Date.parse(value.checked_at)) || typeof value.sources.cached !== "boolean")
|
|
83
|
+
return fail("checked_at or sources.cached provenance is malformed");
|
|
84
|
+
for (const key of ["owner_adagents_url", "host_adagents_url"]) {
|
|
85
|
+
if (typeof value.sources[key] !== "string") return fail(`sources.${key} must be an HTTPS URL`);
|
|
86
|
+
try {
|
|
87
|
+
const url = new URL(value.sources[key]);
|
|
88
|
+
if (url.protocol !== "https:" || url.username || url.password)
|
|
89
|
+
return fail(`sources.${key} must be an HTTPS URL without credentials`);
|
|
90
|
+
} catch {
|
|
91
|
+
return fail(`sources.${key} must be a valid URL`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const key of ["owner_fetched_at", "host_fetched_at"]) {
|
|
95
|
+
const timestamp = value.sources[key];
|
|
96
|
+
if (timestamp !== null && (typeof timestamp !== "string" || !Number.isFinite(Date.parse(timestamp))))
|
|
97
|
+
return fail(`sources.${key} must be null or a valid timestamp`);
|
|
98
|
+
}
|
|
99
|
+
for (const key of ["owner_resolved_url", "host_resolved_url"]) {
|
|
100
|
+
const location = value.sources[key];
|
|
101
|
+
if (location === null) continue;
|
|
102
|
+
if (typeof location !== "string" || location.length > 8192)
|
|
103
|
+
return fail(`sources.${key} must be null or a bounded HTTPS URL`);
|
|
104
|
+
try {
|
|
105
|
+
const parsed = new URL(location);
|
|
106
|
+
if (parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.hash || parsed.port && parsed.port !== "443")
|
|
107
|
+
return fail(`sources.${key} must be an HTTPS URL without credentials, fragments, or nonstandard ports`);
|
|
108
|
+
} catch {
|
|
109
|
+
return fail(`sources.${key} must be a valid URL`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const legNames = [
|
|
113
|
+
"owner_collection_declared",
|
|
114
|
+
"owner_distribution_carriage",
|
|
115
|
+
"owner_agent_declared",
|
|
116
|
+
"host_authorization",
|
|
117
|
+
"inventory_partner_domain"
|
|
118
|
+
];
|
|
119
|
+
for (const key of legNames) {
|
|
120
|
+
const leg = value.legs[key];
|
|
121
|
+
if (!record(leg) || typeof leg.ok !== "boolean" || leg.detail !== void 0 && typeof leg.detail !== "string")
|
|
122
|
+
return fail(`legs.${key} is malformed`);
|
|
123
|
+
if (leg.ok ? leg.failure !== void 0 : typeof leg.failure !== "string" || !leg.failure.length)
|
|
124
|
+
return fail(`legs.${key} has an inconsistent ok/failure pair`);
|
|
125
|
+
for (const ids of ["property_ids_matched", "property_ids_unmatched"]) {
|
|
126
|
+
if (leg[ids] !== void 0 && (!Array.isArray(leg[ids]) || !leg[ids].every((id) => typeof id === "string")))
|
|
127
|
+
return fail(`legs.${key}.${ids} must contain only string property IDs`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const ok = (key) => value.legs[key]?.ok === true;
|
|
131
|
+
if (ok("owner_collection_declared")) {
|
|
132
|
+
if (typeof value.resolved_collection_id !== "string" || !value.resolved_collection_id.trim() || value.resolved_collection_id.length > 256 || request.collection_id !== void 0 && value.resolved_collection_id !== request.collection_id)
|
|
133
|
+
return fail("resolved_collection_id is missing, malformed, or inconsistent with the request");
|
|
134
|
+
} else if (value.resolved_collection_id !== void 0)
|
|
135
|
+
return fail("resolved_collection_id requires a successful owner collection leg");
|
|
136
|
+
if (value.state === "verified_owner_sold" && !(ok("owner_collection_declared") && ok("owner_distribution_carriage") && ok("host_authorization")))
|
|
137
|
+
return fail("verified_owner_sold is inconsistent with its required successful legs");
|
|
138
|
+
if (value.state === "host_delegated" && !(ok("owner_collection_declared") && ok("owner_agent_declared") && ok("inventory_partner_domain")))
|
|
139
|
+
return fail("host_delegated is inconsistent with its required successful legs");
|
|
140
|
+
if (value.state === "owner_attested" && !ok("owner_collection_declared"))
|
|
141
|
+
return fail("owner_attested requires a successful owner collection leg");
|
|
142
|
+
}
|
|
143
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
144
|
+
0 && (module.exports = {
|
|
145
|
+
agentIdentity,
|
|
146
|
+
assertRegistrySupplyPathResult,
|
|
147
|
+
domain,
|
|
148
|
+
record,
|
|
149
|
+
records,
|
|
150
|
+
strings,
|
|
151
|
+
validateSupplyPathRequest
|
|
152
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
import { canonicalizeAgentUrl } from "../discovery/resolve-agent-properties.mjs";
|
|
3
|
+
function record(value) {
|
|
4
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function records(value) {
|
|
7
|
+
return Array.isArray(value) ? value.filter(record) : [];
|
|
8
|
+
}
|
|
9
|
+
function strings(value) {
|
|
10
|
+
return Array.isArray(value) && value.length > 0 && value.every((v) => typeof v === "string" && v.trim().length > 0);
|
|
11
|
+
}
|
|
12
|
+
function domain(value) {
|
|
13
|
+
if (typeof value !== "string") return null;
|
|
14
|
+
const normalized = value.toLowerCase().replace(/\.$/, "");
|
|
15
|
+
if (normalized.length > 253 || isIP(normalized) || !normalized.includes(".")) return null;
|
|
16
|
+
return normalized.split(".").every((label) => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label)) ? normalized : null;
|
|
17
|
+
}
|
|
18
|
+
function agentIdentity(value) {
|
|
19
|
+
if (typeof value !== "string" || /[\s\x00-\x1f\x7f]/.test(value)) return null;
|
|
20
|
+
const canonical = canonicalizeAgentUrl(value);
|
|
21
|
+
return canonical?.startsWith("https://") ? canonical : null;
|
|
22
|
+
}
|
|
23
|
+
function validateSupplyPathRequest(input) {
|
|
24
|
+
if (!record(input)) throw new TypeError("Supply-path request must be an object");
|
|
25
|
+
const owner = domain(input.owner_domain);
|
|
26
|
+
const host = domain(input.host_domain);
|
|
27
|
+
if (!owner || !host) throw new TypeError("owner_domain and host_domain must be DNS publisher domains");
|
|
28
|
+
if (!agentIdentity(input.agent_url)) throw new TypeError("agent_url must be an HTTPS URL without credentials");
|
|
29
|
+
if (input.collection_id !== void 0 && (typeof input.collection_id !== "string" || !input.collection_id.trim() || input.collection_id.length > 256)) {
|
|
30
|
+
throw new TypeError("collection_id must be a non-empty string of at most 256 characters");
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
owner_domain: owner,
|
|
34
|
+
host_domain: host,
|
|
35
|
+
agent_url: input.agent_url,
|
|
36
|
+
...input.collection_id !== void 0 ? { collection_id: input.collection_id } : {}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function assertRegistrySupplyPathResult(value, request) {
|
|
40
|
+
const fail = (invariant) => {
|
|
41
|
+
throw new TypeError(
|
|
42
|
+
`Invalid registry supply-path response: ${invariant}; verification cannot be accepted, check the registry response contract`
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
if (!record(value)) return fail("response must be an object");
|
|
46
|
+
if (value.semantics_version !== "1")
|
|
47
|
+
throw new TypeError("Invalid registry supply-path response: semantics_version 1 required; upgrade the registry");
|
|
48
|
+
if (!record(value.legs) || !record(value.sources)) return fail("legs and sources must be objects");
|
|
49
|
+
if (!["verified_owner_sold", "host_delegated", "owner_attested", "unverified"].includes(String(value.state)))
|
|
50
|
+
return fail("state is not recognized");
|
|
51
|
+
if (domain(value.owner_domain) !== request.owner_domain || domain(value.host_domain) !== request.host_domain || agentIdentity(value.agent_url) !== agentIdentity(request.agent_url) || value.collection_id !== request.collection_id)
|
|
52
|
+
return fail("request identity does not match the submitted owner, host, agent, and collection");
|
|
53
|
+
if (typeof value.checked_at !== "string" || !Number.isFinite(Date.parse(value.checked_at)) || typeof value.sources.cached !== "boolean")
|
|
54
|
+
return fail("checked_at or sources.cached provenance is malformed");
|
|
55
|
+
for (const key of ["owner_adagents_url", "host_adagents_url"]) {
|
|
56
|
+
if (typeof value.sources[key] !== "string") return fail(`sources.${key} must be an HTTPS URL`);
|
|
57
|
+
try {
|
|
58
|
+
const url = new URL(value.sources[key]);
|
|
59
|
+
if (url.protocol !== "https:" || url.username || url.password)
|
|
60
|
+
return fail(`sources.${key} must be an HTTPS URL without credentials`);
|
|
61
|
+
} catch {
|
|
62
|
+
return fail(`sources.${key} must be a valid URL`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const key of ["owner_fetched_at", "host_fetched_at"]) {
|
|
66
|
+
const timestamp = value.sources[key];
|
|
67
|
+
if (timestamp !== null && (typeof timestamp !== "string" || !Number.isFinite(Date.parse(timestamp))))
|
|
68
|
+
return fail(`sources.${key} must be null or a valid timestamp`);
|
|
69
|
+
}
|
|
70
|
+
for (const key of ["owner_resolved_url", "host_resolved_url"]) {
|
|
71
|
+
const location = value.sources[key];
|
|
72
|
+
if (location === null) continue;
|
|
73
|
+
if (typeof location !== "string" || location.length > 8192)
|
|
74
|
+
return fail(`sources.${key} must be null or a bounded HTTPS URL`);
|
|
75
|
+
try {
|
|
76
|
+
const parsed = new URL(location);
|
|
77
|
+
if (parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.hash || parsed.port && parsed.port !== "443")
|
|
78
|
+
return fail(`sources.${key} must be an HTTPS URL without credentials, fragments, or nonstandard ports`);
|
|
79
|
+
} catch {
|
|
80
|
+
return fail(`sources.${key} must be a valid URL`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const legNames = [
|
|
84
|
+
"owner_collection_declared",
|
|
85
|
+
"owner_distribution_carriage",
|
|
86
|
+
"owner_agent_declared",
|
|
87
|
+
"host_authorization",
|
|
88
|
+
"inventory_partner_domain"
|
|
89
|
+
];
|
|
90
|
+
for (const key of legNames) {
|
|
91
|
+
const leg = value.legs[key];
|
|
92
|
+
if (!record(leg) || typeof leg.ok !== "boolean" || leg.detail !== void 0 && typeof leg.detail !== "string")
|
|
93
|
+
return fail(`legs.${key} is malformed`);
|
|
94
|
+
if (leg.ok ? leg.failure !== void 0 : typeof leg.failure !== "string" || !leg.failure.length)
|
|
95
|
+
return fail(`legs.${key} has an inconsistent ok/failure pair`);
|
|
96
|
+
for (const ids of ["property_ids_matched", "property_ids_unmatched"]) {
|
|
97
|
+
if (leg[ids] !== void 0 && (!Array.isArray(leg[ids]) || !leg[ids].every((id) => typeof id === "string")))
|
|
98
|
+
return fail(`legs.${key}.${ids} must contain only string property IDs`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const ok = (key) => value.legs[key]?.ok === true;
|
|
102
|
+
if (ok("owner_collection_declared")) {
|
|
103
|
+
if (typeof value.resolved_collection_id !== "string" || !value.resolved_collection_id.trim() || value.resolved_collection_id.length > 256 || request.collection_id !== void 0 && value.resolved_collection_id !== request.collection_id)
|
|
104
|
+
return fail("resolved_collection_id is missing, malformed, or inconsistent with the request");
|
|
105
|
+
} else if (value.resolved_collection_id !== void 0)
|
|
106
|
+
return fail("resolved_collection_id requires a successful owner collection leg");
|
|
107
|
+
if (value.state === "verified_owner_sold" && !(ok("owner_collection_declared") && ok("owner_distribution_carriage") && ok("host_authorization")))
|
|
108
|
+
return fail("verified_owner_sold is inconsistent with its required successful legs");
|
|
109
|
+
if (value.state === "host_delegated" && !(ok("owner_collection_declared") && ok("owner_agent_declared") && ok("inventory_partner_domain")))
|
|
110
|
+
return fail("host_delegated is inconsistent with its required successful legs");
|
|
111
|
+
if (value.state === "owner_attested" && !ok("owner_collection_declared"))
|
|
112
|
+
return fail("owner_attested requires a successful owner collection leg");
|
|
113
|
+
}
|
|
114
|
+
export {
|
|
115
|
+
agentIdentity,
|
|
116
|
+
assertRegistrySupplyPathResult,
|
|
117
|
+
domain,
|
|
118
|
+
record,
|
|
119
|
+
records,
|
|
120
|
+
strings,
|
|
121
|
+
validateSupplyPathRequest
|
|
122
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { SupplyPathEvidenceSession } from './fetch-evidence.mjs';
|
|
2
|
+
import type { SupplyPathRequest, VerifySupplyPathOptions, RegistrySupplyPathOptions, AuthoritativeSupplyPathOptions, RegistrySupplyPathResult, AuthoritativeSupplyPathResult } from './types.mjs';
|
|
3
|
+
/**
|
|
4
|
+
* Verify one owner/host/agent path. Authoritative mode (the default) fetches
|
|
5
|
+
* live publisher evidence; registry mode validates a remote cached verdict.
|
|
6
|
+
* Invalid evidence rejects or returns a fail-closed verdict—it is never
|
|
7
|
+
* converted into synthetic authorization.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const verdict = await verifySupplyPath({
|
|
12
|
+
* owner_domain: 'owner.example',
|
|
13
|
+
* host_domain: 'host.example',
|
|
14
|
+
* agent_url: 'https://sales.example',
|
|
15
|
+
* collection_id: 'news',
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see docs/guides/SUPPLY-PATH-VERIFICATION.md
|
|
20
|
+
*/
|
|
21
|
+
export declare function verifySupplyPath(request: SupplyPathRequest, options: RegistrySupplyPathOptions): Promise<RegistrySupplyPathResult>;
|
|
22
|
+
export declare function verifySupplyPath(request: SupplyPathRequest, options?: AuthoritativeSupplyPathOptions): Promise<AuthoritativeSupplyPathResult>;
|
|
23
|
+
export declare function verifySupplyPath(request: SupplyPathRequest, options: VerifySupplyPathOptions): Promise<RegistrySupplyPathResult | AuthoritativeSupplyPathResult>;
|
|
24
|
+
/** Internal batch entrypoint; callers cannot supply evidence through the public API. */
|
|
25
|
+
export declare function verifyAuthoritativeSupplyPath(normalized: SupplyPathRequest, options: AuthoritativeSupplyPathOptions, session: SupplyPathEvidenceSession): Promise<AuthoritativeSupplyPathResult>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { SupplyPathEvidenceSession } from './fetch-evidence';
|
|
2
|
+
import type { SupplyPathRequest, VerifySupplyPathOptions, RegistrySupplyPathOptions, AuthoritativeSupplyPathOptions, RegistrySupplyPathResult, AuthoritativeSupplyPathResult } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Verify one owner/host/agent path. Authoritative mode (the default) fetches
|
|
5
|
+
* live publisher evidence; registry mode validates a remote cached verdict.
|
|
6
|
+
* Invalid evidence rejects or returns a fail-closed verdict—it is never
|
|
7
|
+
* converted into synthetic authorization.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const verdict = await verifySupplyPath({
|
|
12
|
+
* owner_domain: 'owner.example',
|
|
13
|
+
* host_domain: 'host.example',
|
|
14
|
+
* agent_url: 'https://sales.example',
|
|
15
|
+
* collection_id: 'news',
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see docs/guides/SUPPLY-PATH-VERIFICATION.md
|
|
20
|
+
*/
|
|
21
|
+
export declare function verifySupplyPath(request: SupplyPathRequest, options: RegistrySupplyPathOptions): Promise<RegistrySupplyPathResult>;
|
|
22
|
+
export declare function verifySupplyPath(request: SupplyPathRequest, options?: AuthoritativeSupplyPathOptions): Promise<AuthoritativeSupplyPathResult>;
|
|
23
|
+
export declare function verifySupplyPath(request: SupplyPathRequest, options: VerifySupplyPathOptions): Promise<RegistrySupplyPathResult | AuthoritativeSupplyPathResult>;
|
|
24
|
+
/** Internal batch entrypoint; callers cannot supply evidence through the public API. */
|
|
25
|
+
export declare function verifyAuthoritativeSupplyPath(normalized: SupplyPathRequest, options: AuthoritativeSupplyPathOptions, session: SupplyPathEvidenceSession): Promise<AuthoritativeSupplyPathResult>;
|
|
@@ -0,0 +1,218 @@
|
|
|
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 verify_exports = {};
|
|
20
|
+
__export(verify_exports, {
|
|
21
|
+
verifyAuthoritativeSupplyPath: () => verifyAuthoritativeSupplyPath,
|
|
22
|
+
verifySupplyPath: () => verifySupplyPath
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(verify_exports);
|
|
25
|
+
var import_abort = require('../protocols/abort.js');
|
|
26
|
+
var import_publisher_property_selector = require('../discovery/publisher-property-selector.js');
|
|
27
|
+
var import_validation = require('./validation.js');
|
|
28
|
+
var import_registry = require('../registry/index.js');
|
|
29
|
+
var import_fetch_evidence = require('./fetch-evidence.js');
|
|
30
|
+
var import_evaluate = require('./evaluate.js');
|
|
31
|
+
var import_validation2 = require('./validation.js');
|
|
32
|
+
const MAX_PROPERTY_SCOPE_VALUES = 32768;
|
|
33
|
+
const MAX_PROPERTY_SELECTOR_EXPANSIONS = 4096;
|
|
34
|
+
async function verifySupplyPath(request, options = { source: "authoritative" }) {
|
|
35
|
+
const normalized = (0, import_validation2.validateSupplyPathRequest)(request);
|
|
36
|
+
if (options.source === "registry") {
|
|
37
|
+
const result = await (options.registry ?? new import_registry.RegistryClient()).verifySupplyPath(normalized);
|
|
38
|
+
(0, import_validation2.assertRegistrySupplyPathResult)(result, normalized);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
if (options.source !== "authoritative") throw new TypeError("source must be registry or authoritative");
|
|
42
|
+
const session = new import_fetch_evidence.SupplyPathEvidenceSession(options);
|
|
43
|
+
try {
|
|
44
|
+
return await (0, import_abort.withAbortSignal)(
|
|
45
|
+
[session.signal],
|
|
46
|
+
void 0,
|
|
47
|
+
() => verifyAuthoritativeSupplyPath(normalized, options, session)
|
|
48
|
+
);
|
|
49
|
+
} finally {
|
|
50
|
+
session.close();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function verifyAuthoritativeSupplyPath(normalized, options, session) {
|
|
54
|
+
if (options.propertySelectors !== void 0) {
|
|
55
|
+
if (!Array.isArray(options.propertySelectors) || !options.propertySelectors.length)
|
|
56
|
+
throw new TypeError("propertySelectors must be non-empty");
|
|
57
|
+
if (options.propertySelectors.length > 1024)
|
|
58
|
+
throw new TypeError("propertySelectors exceed the evaluation work limit");
|
|
59
|
+
for (const raw of options.propertySelectors) {
|
|
60
|
+
if (!(0, import_evaluate.isUnqualifiedPropertySelector)(raw)) throw new TypeError("Unsupported product property selector fields");
|
|
61
|
+
if (!(0, import_evaluate.hasValidPropertySelectorPredicate)(raw))
|
|
62
|
+
throw new TypeError("Product property selector predicate conflicts with selection_type");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const [ownerManifest, hostManifest] = await Promise.all([
|
|
66
|
+
session.adagents(normalized.owner_domain),
|
|
67
|
+
session.adagents(normalized.host_domain)
|
|
68
|
+
]);
|
|
69
|
+
const input = {
|
|
70
|
+
ownerDomain: normalized.owner_domain,
|
|
71
|
+
hostDomain: normalized.host_domain,
|
|
72
|
+
agentUrl: normalized.agent_url,
|
|
73
|
+
collectionId: normalized.collection_id,
|
|
74
|
+
ownerManifest,
|
|
75
|
+
hostManifest,
|
|
76
|
+
requireExplicitOwnerPublisherDomain: session.crossOriginAuthorities.has(normalized.owner_domain),
|
|
77
|
+
requireExplicitHostPublisherDomain: session.crossOriginAuthorities.has(normalized.host_domain),
|
|
78
|
+
hostInventoryPartnerDomains: null,
|
|
79
|
+
hostInventoryPartnerDomainsByFile: void 0,
|
|
80
|
+
heldRevocations: {
|
|
81
|
+
owner: session.revocations.get(normalized.owner_domain)?.map((r) => r.publisher_domain),
|
|
82
|
+
host: session.revocations.get(normalized.host_domain)?.map((r) => r.publisher_domain)
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const scopedInput = input;
|
|
86
|
+
let selectorLimitExceeded = false;
|
|
87
|
+
if (options.propertySelectors !== void 0) {
|
|
88
|
+
const ids = /* @__PURE__ */ new Set();
|
|
89
|
+
const rawProperties = hostManifest?.properties;
|
|
90
|
+
if (Array.isArray(rawProperties) && rawProperties.length > 1024) selectorLimitExceeded = true;
|
|
91
|
+
const properties = selectorLimitExceeded ? [] : (0, import_validation.records)(rawProperties).filter(
|
|
92
|
+
(p) => p.publisher_domain === void 0 && !input.requireExplicitHostPublisherDomain || (0, import_validation.domain)(p.publisher_domain) === normalized.host_domain
|
|
93
|
+
);
|
|
94
|
+
let unresolved = false;
|
|
95
|
+
let scopeValues = properties.length;
|
|
96
|
+
const availableTags = /* @__PURE__ */ new Set();
|
|
97
|
+
for (const property of properties) {
|
|
98
|
+
session.assertActive();
|
|
99
|
+
if (property.tags === void 0) continue;
|
|
100
|
+
if (!Array.isArray(property.tags) || property.tags.length > 1024 || property.tags.some((tag) => typeof tag !== "string" || !tag.trim())) {
|
|
101
|
+
selectorLimitExceeded = true;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
scopeValues += property.tags.length;
|
|
105
|
+
if (scopeValues > MAX_PROPERTY_SCOPE_VALUES) {
|
|
106
|
+
selectorLimitExceeded = true;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
for (const tag of property.tags) {
|
|
110
|
+
if (tag.length > 8192) selectorLimitExceeded = true;
|
|
111
|
+
availableTags.add(tag);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const selectors = [];
|
|
115
|
+
for (const raw of options.propertySelectors) {
|
|
116
|
+
session.assertActive();
|
|
117
|
+
if (selectorLimitExceeded) continue;
|
|
118
|
+
const selector = (0, import_publisher_property_selector.parsePublisherPropertySelector)(raw);
|
|
119
|
+
const expansionCount = "publisher_domains" in selector ? selector.publisher_domains.length : 1;
|
|
120
|
+
if (selectors.length + expansionCount > MAX_PROPERTY_SELECTOR_EXPANSIONS) {
|
|
121
|
+
selectorLimitExceeded = true;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const expanded = (0, import_publisher_property_selector.expandPublisherPropertySelector)(selector);
|
|
125
|
+
selectors.push(...expanded);
|
|
126
|
+
}
|
|
127
|
+
const selectedTags = /* @__PURE__ */ new Set();
|
|
128
|
+
let selectAll = false;
|
|
129
|
+
for (const single of selectors) {
|
|
130
|
+
session.assertActive();
|
|
131
|
+
scopeValues += 1;
|
|
132
|
+
if (scopeValues > MAX_PROPERTY_SCOPE_VALUES) selectorLimitExceeded = true;
|
|
133
|
+
if (!selectorLimitExceeded) {
|
|
134
|
+
if ((0, import_validation.domain)(single.publisher_domain) !== normalized.host_domain)
|
|
135
|
+
throw new TypeError("propertySelectors must name host_domain");
|
|
136
|
+
if (single.selection_type === "by_id") {
|
|
137
|
+
if (!(0, import_validation.strings)(single.property_ids)) throw new TypeError("Invalid product property IDs");
|
|
138
|
+
scopeValues += single.property_ids.length;
|
|
139
|
+
if (single.property_ids.length > 1024 || single.property_ids.some((id) => id.length > 8192))
|
|
140
|
+
selectorLimitExceeded = true;
|
|
141
|
+
for (const id of single.property_ids) ids.add(id);
|
|
142
|
+
} else {
|
|
143
|
+
if (single.selection_type === "by_tag" && !(0, import_validation.strings)(single.property_tags))
|
|
144
|
+
throw new TypeError("Invalid product property tags");
|
|
145
|
+
if (single.selection_type === "all") {
|
|
146
|
+
selectAll = true;
|
|
147
|
+
if (!properties.length) unresolved = true;
|
|
148
|
+
} else {
|
|
149
|
+
scopeValues += single.property_tags.length;
|
|
150
|
+
if (single.property_tags.length > 1024 || single.property_tags.some((tag) => tag.length > 8192))
|
|
151
|
+
selectorLimitExceeded = true;
|
|
152
|
+
let matched = false;
|
|
153
|
+
for (const tag of single.property_tags) {
|
|
154
|
+
if (!availableTags.has(tag)) continue;
|
|
155
|
+
matched = true;
|
|
156
|
+
selectedTags.add(tag);
|
|
157
|
+
}
|
|
158
|
+
if (!matched) unresolved = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (scopeValues > MAX_PROPERTY_SCOPE_VALUES) selectorLimitExceeded = true;
|
|
164
|
+
if (!selectorLimitExceeded && (selectAll || selectedTags.size)) {
|
|
165
|
+
for (const property of properties) {
|
|
166
|
+
session.assertActive();
|
|
167
|
+
const selected = selectAll || Array.isArray(property.tags) && property.tags.some((tag) => selectedTags.has(tag));
|
|
168
|
+
if (!selected) continue;
|
|
169
|
+
if (typeof property.property_id !== "string" || !property.property_id.length) unresolved = true;
|
|
170
|
+
else ids.add(property.property_id);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
scopedInput.requiredHostPropertyIds = selectorLimitExceeded || unresolved ? [] : [...ids];
|
|
174
|
+
}
|
|
175
|
+
session.assertActive();
|
|
176
|
+
let verdict = selectorLimitExceeded ? (0, import_evaluate.evaluationLimitVerdict)() : (0, import_evaluate.evaluateSupplyPath)(scopedInput);
|
|
177
|
+
session.assertActive();
|
|
178
|
+
if (!verdict.legs.host_authorization.ok && verdict.legs.host_authorization.failure !== "evaluation_limit_exceeded") {
|
|
179
|
+
const policy = (0, import_evaluate.supplyPathAdsTxtPolicy)(scopedInput);
|
|
180
|
+
const responses = await Promise.all(
|
|
181
|
+
policy.files.map((kind) => session.read(normalized.host_domain, kind, `https://${normalized.host_domain}/${kind}`))
|
|
182
|
+
);
|
|
183
|
+
input.hostInventoryPartnerDomainsByFile = Object.fromEntries(
|
|
184
|
+
policy.files.map((file, index) => [
|
|
185
|
+
file,
|
|
186
|
+
responses[index] ? (0, import_evaluate.parseInventoryPartnerDomains)(new TextDecoder().decode(responses[index].body)) : null
|
|
187
|
+
])
|
|
188
|
+
);
|
|
189
|
+
session.assertActive();
|
|
190
|
+
verdict = (0, import_evaluate.evaluateSupplyPath)(scopedInput);
|
|
191
|
+
session.assertActive();
|
|
192
|
+
} else if (verdict.legs.host_authorization.ok) {
|
|
193
|
+
verdict = (0, import_evaluate.evaluateSupplyPath)({ ...scopedInput, inventoryPartnerDomainEvaluated: false });
|
|
194
|
+
session.assertActive();
|
|
195
|
+
}
|
|
196
|
+
session.assertActive();
|
|
197
|
+
return {
|
|
198
|
+
...verdict,
|
|
199
|
+
...normalized,
|
|
200
|
+
source: "authoritative",
|
|
201
|
+
...options.propertySelectors ? { property_selectors: options.propertySelectors } : {},
|
|
202
|
+
sources: {
|
|
203
|
+
owner_adagents_url: `https://${normalized.owner_domain}/.well-known/adagents.json`,
|
|
204
|
+
host_adagents_url: `https://${normalized.host_domain}/.well-known/adagents.json`,
|
|
205
|
+
cached: false,
|
|
206
|
+
held_revocations: [...session.revocations].filter(([authority]) => authority === normalized.owner_domain || authority === normalized.host_domain).map(([authority, entries]) => ({ authority, entries })),
|
|
207
|
+
evidence: session.evidence.filter(
|
|
208
|
+
(e) => e.publisher_domain === normalized.owner_domain || e.publisher_domain === normalized.host_domain
|
|
209
|
+
)
|
|
210
|
+
},
|
|
211
|
+
checked_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
215
|
+
0 && (module.exports = {
|
|
216
|
+
verifyAuthoritativeSupplyPath,
|
|
217
|
+
verifySupplyPath
|
|
218
|
+
});
|