@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,127 @@
|
|
|
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 revocations_exports = {};
|
|
20
|
+
__export(revocations_exports, {
|
|
21
|
+
InMemorySupplyPathAuthorityStore: () => InMemorySupplyPathAuthorityStore,
|
|
22
|
+
InMemorySupplyPathRevocationStore: () => InMemorySupplyPathRevocationStore,
|
|
23
|
+
defaultSupplyPathAuthorities: () => defaultSupplyPathAuthorities,
|
|
24
|
+
defaultSupplyPathRevocations: () => defaultSupplyPathRevocations,
|
|
25
|
+
parseRevocations: () => parseRevocations
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(revocations_exports);
|
|
28
|
+
var import_validation = require('./validation.js');
|
|
29
|
+
class AuthorityAdmissionBudget {
|
|
30
|
+
windowStart = Date.now();
|
|
31
|
+
admitted = 0;
|
|
32
|
+
consume() {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
if (now >= this.windowStart + 6e4) {
|
|
35
|
+
this.windowStart = now;
|
|
36
|
+
this.admitted = 0;
|
|
37
|
+
}
|
|
38
|
+
if (this.admitted >= 128) throw new Error("Supply-path new-authority admission rate exceeded");
|
|
39
|
+
this.admitted++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
class InMemorySupplyPathRevocationStore {
|
|
43
|
+
admission = new AuthorityAdmissionBudget();
|
|
44
|
+
entries = /* @__PURE__ */ new Map();
|
|
45
|
+
async observe(authority, revoked) {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
for (const [key, value] of this.entries) if (value.expires <= now) this.entries.delete(key);
|
|
48
|
+
const scoped = new Set(
|
|
49
|
+
[...this.entries.values()].filter((value) => value.authority === authority).map((value) => value.entry.publisher_domain)
|
|
50
|
+
);
|
|
51
|
+
const existingAuthority = scoped.size > 0;
|
|
52
|
+
for (const entry of revoked) scoped.add(entry.publisher_domain);
|
|
53
|
+
if (scoped.size > 1024) throw new Error("Supply-path publisher authority revocation capacity exceeded");
|
|
54
|
+
const newEntries = revoked.filter((entry) => !this.entries.has(JSON.stringify([authority, entry.publisher_domain])));
|
|
55
|
+
const newCount = new Set(newEntries.map((entry) => entry.publisher_domain)).size;
|
|
56
|
+
if (this.entries.size + newCount > 1e4) throw new Error("Supply-path revocation store capacity exceeded");
|
|
57
|
+
if (!existingAuthority && scoped.size > 0) this.admission.consume();
|
|
58
|
+
for (const entry of revoked) {
|
|
59
|
+
const key = JSON.stringify([authority, entry.publisher_domain]);
|
|
60
|
+
const prior = this.entries.get(key);
|
|
61
|
+
if (prior) {
|
|
62
|
+
if (Date.parse(entry.revoked_at) < Date.parse(prior.entry.revoked_at))
|
|
63
|
+
prior.entry.revoked_at = entry.revoked_at;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
this.entries.set(key, { authority, entry: { ...entry }, expires: now + 7 * 864e5 });
|
|
67
|
+
}
|
|
68
|
+
return [...this.entries.values()].filter((value) => value.authority === authority).map((value) => ({ ...value.entry }));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const defaultSupplyPathRevocations = new InMemorySupplyPathRevocationStore();
|
|
72
|
+
function parseRevocations(value) {
|
|
73
|
+
if (value === void 0) return [];
|
|
74
|
+
if (!Array.isArray(value) || value.length > 1024) return null;
|
|
75
|
+
const entries = [];
|
|
76
|
+
for (const raw of value) {
|
|
77
|
+
const publisher = (0, import_validation.domain)((0, import_validation.record)(raw) ? raw.publisher_domain : raw);
|
|
78
|
+
if (!publisher) return null;
|
|
79
|
+
const timestamp = (0, import_validation.record)(raw) ? raw.revoked_at : void 0;
|
|
80
|
+
if (timestamp !== void 0 && (typeof timestamp !== "string" || !Number.isFinite(Date.parse(timestamp))))
|
|
81
|
+
return null;
|
|
82
|
+
entries.push({
|
|
83
|
+
publisher_domain: publisher,
|
|
84
|
+
revoked_at: typeof timestamp === "string" ? timestamp : "unspecified"
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return entries;
|
|
88
|
+
}
|
|
89
|
+
class InMemorySupplyPathAuthorityStore {
|
|
90
|
+
admission = new AuthorityAdmissionBudget();
|
|
91
|
+
locations = /* @__PURE__ */ new Map();
|
|
92
|
+
async check(publisherDomain, location) {
|
|
93
|
+
this.assertBoundedLocation(location);
|
|
94
|
+
const pinned = this.locations.get(publisherDomain);
|
|
95
|
+
return pinned === void 0 || pinned === location;
|
|
96
|
+
}
|
|
97
|
+
async observe(publisherDomain, location) {
|
|
98
|
+
this.assertBoundedLocation(location);
|
|
99
|
+
const pinned = this.locations.get(publisherDomain);
|
|
100
|
+
if (pinned !== void 0) return pinned === location;
|
|
101
|
+
if (this.locations.size >= 1e4) throw new Error("Supply-path authority store capacity exceeded");
|
|
102
|
+
this.admission.consume();
|
|
103
|
+
this.locations.set(publisherDomain, location);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
/** Call only after independently confirming a publisher's migration. Never call from an automatic retry. */
|
|
107
|
+
approveChange(publisherDomain, location) {
|
|
108
|
+
this.assertBoundedLocation(location);
|
|
109
|
+
if (!this.locations.has(publisherDomain) && this.locations.size >= 1e4)
|
|
110
|
+
throw new Error("Supply-path authority store capacity exceeded");
|
|
111
|
+
if (!this.locations.has(publisherDomain)) this.admission.consume();
|
|
112
|
+
this.locations.set(publisherDomain, location);
|
|
113
|
+
}
|
|
114
|
+
assertBoundedLocation(location) {
|
|
115
|
+
if (typeof location !== "string" || location.length === 0 || location.length > 8192)
|
|
116
|
+
throw new TypeError("Supply-path authority location must contain 1 to 8192 characters");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const defaultSupplyPathAuthorities = new InMemorySupplyPathAuthorityStore();
|
|
120
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
121
|
+
0 && (module.exports = {
|
|
122
|
+
InMemorySupplyPathAuthorityStore,
|
|
123
|
+
InMemorySupplyPathRevocationStore,
|
|
124
|
+
defaultSupplyPathAuthorities,
|
|
125
|
+
defaultSupplyPathRevocations,
|
|
126
|
+
parseRevocations
|
|
127
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { domain, record } from "./validation.mjs";
|
|
2
|
+
class AuthorityAdmissionBudget {
|
|
3
|
+
windowStart = Date.now();
|
|
4
|
+
admitted = 0;
|
|
5
|
+
consume() {
|
|
6
|
+
const now = Date.now();
|
|
7
|
+
if (now >= this.windowStart + 6e4) {
|
|
8
|
+
this.windowStart = now;
|
|
9
|
+
this.admitted = 0;
|
|
10
|
+
}
|
|
11
|
+
if (this.admitted >= 128) throw new Error("Supply-path new-authority admission rate exceeded");
|
|
12
|
+
this.admitted++;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class InMemorySupplyPathRevocationStore {
|
|
16
|
+
admission = new AuthorityAdmissionBudget();
|
|
17
|
+
entries = /* @__PURE__ */ new Map();
|
|
18
|
+
async observe(authority, revoked) {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
for (const [key, value] of this.entries) if (value.expires <= now) this.entries.delete(key);
|
|
21
|
+
const scoped = new Set(
|
|
22
|
+
[...this.entries.values()].filter((value) => value.authority === authority).map((value) => value.entry.publisher_domain)
|
|
23
|
+
);
|
|
24
|
+
const existingAuthority = scoped.size > 0;
|
|
25
|
+
for (const entry of revoked) scoped.add(entry.publisher_domain);
|
|
26
|
+
if (scoped.size > 1024) throw new Error("Supply-path publisher authority revocation capacity exceeded");
|
|
27
|
+
const newEntries = revoked.filter((entry) => !this.entries.has(JSON.stringify([authority, entry.publisher_domain])));
|
|
28
|
+
const newCount = new Set(newEntries.map((entry) => entry.publisher_domain)).size;
|
|
29
|
+
if (this.entries.size + newCount > 1e4) throw new Error("Supply-path revocation store capacity exceeded");
|
|
30
|
+
if (!existingAuthority && scoped.size > 0) this.admission.consume();
|
|
31
|
+
for (const entry of revoked) {
|
|
32
|
+
const key = JSON.stringify([authority, entry.publisher_domain]);
|
|
33
|
+
const prior = this.entries.get(key);
|
|
34
|
+
if (prior) {
|
|
35
|
+
if (Date.parse(entry.revoked_at) < Date.parse(prior.entry.revoked_at))
|
|
36
|
+
prior.entry.revoked_at = entry.revoked_at;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
this.entries.set(key, { authority, entry: { ...entry }, expires: now + 7 * 864e5 });
|
|
40
|
+
}
|
|
41
|
+
return [...this.entries.values()].filter((value) => value.authority === authority).map((value) => ({ ...value.entry }));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const defaultSupplyPathRevocations = new InMemorySupplyPathRevocationStore();
|
|
45
|
+
function parseRevocations(value) {
|
|
46
|
+
if (value === void 0) return [];
|
|
47
|
+
if (!Array.isArray(value) || value.length > 1024) return null;
|
|
48
|
+
const entries = [];
|
|
49
|
+
for (const raw of value) {
|
|
50
|
+
const publisher = domain(record(raw) ? raw.publisher_domain : raw);
|
|
51
|
+
if (!publisher) return null;
|
|
52
|
+
const timestamp = record(raw) ? raw.revoked_at : void 0;
|
|
53
|
+
if (timestamp !== void 0 && (typeof timestamp !== "string" || !Number.isFinite(Date.parse(timestamp))))
|
|
54
|
+
return null;
|
|
55
|
+
entries.push({
|
|
56
|
+
publisher_domain: publisher,
|
|
57
|
+
revoked_at: typeof timestamp === "string" ? timestamp : "unspecified"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return entries;
|
|
61
|
+
}
|
|
62
|
+
class InMemorySupplyPathAuthorityStore {
|
|
63
|
+
admission = new AuthorityAdmissionBudget();
|
|
64
|
+
locations = /* @__PURE__ */ new Map();
|
|
65
|
+
async check(publisherDomain, location) {
|
|
66
|
+
this.assertBoundedLocation(location);
|
|
67
|
+
const pinned = this.locations.get(publisherDomain);
|
|
68
|
+
return pinned === void 0 || pinned === location;
|
|
69
|
+
}
|
|
70
|
+
async observe(publisherDomain, location) {
|
|
71
|
+
this.assertBoundedLocation(location);
|
|
72
|
+
const pinned = this.locations.get(publisherDomain);
|
|
73
|
+
if (pinned !== void 0) return pinned === location;
|
|
74
|
+
if (this.locations.size >= 1e4) throw new Error("Supply-path authority store capacity exceeded");
|
|
75
|
+
this.admission.consume();
|
|
76
|
+
this.locations.set(publisherDomain, location);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/** Call only after independently confirming a publisher's migration. Never call from an automatic retry. */
|
|
80
|
+
approveChange(publisherDomain, location) {
|
|
81
|
+
this.assertBoundedLocation(location);
|
|
82
|
+
if (!this.locations.has(publisherDomain) && this.locations.size >= 1e4)
|
|
83
|
+
throw new Error("Supply-path authority store capacity exceeded");
|
|
84
|
+
if (!this.locations.has(publisherDomain)) this.admission.consume();
|
|
85
|
+
this.locations.set(publisherDomain, location);
|
|
86
|
+
}
|
|
87
|
+
assertBoundedLocation(location) {
|
|
88
|
+
if (typeof location !== "string" || location.length === 0 || location.length > 8192)
|
|
89
|
+
throw new TypeError("Supply-path authority location must contain 1 to 8192 characters");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const defaultSupplyPathAuthorities = new InMemorySupplyPathAuthorityStore();
|
|
93
|
+
export {
|
|
94
|
+
InMemorySupplyPathAuthorityStore,
|
|
95
|
+
InMemorySupplyPathRevocationStore,
|
|
96
|
+
defaultSupplyPathAuthorities,
|
|
97
|
+
defaultSupplyPathRevocations,
|
|
98
|
+
parseRevocations
|
|
99
|
+
};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/** Supply-path contract from adcontextprotocol/adcp#6897. */
|
|
2
|
+
import type { SsrfFetchOptions } from '../net/ssrf-fetch.mjs';
|
|
3
|
+
import type { RegistryClient } from '../registry/index.mjs';
|
|
4
|
+
/** Untrusted evidence. The evaluator validates every authorization-relevant field. */
|
|
5
|
+
export interface SupplyPathManifest {
|
|
6
|
+
authorized_agents?: unknown;
|
|
7
|
+
properties?: unknown;
|
|
8
|
+
collections?: unknown;
|
|
9
|
+
revoked_publisher_domains?: unknown;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export type SupplyPathState = 'verified_owner_sold' | 'host_delegated' | 'owner_attested' | 'unverified';
|
|
13
|
+
export type OwnerCollectionFailure = 'manifest_not_found' | 'no_collections_declared' | 'collection_not_declared' | 'publisher_revoked';
|
|
14
|
+
export type OwnerCarriageFailure = 'collection_leg_failed' | 'no_distribution_for_host' | 'property_ids_unresolved' | 'host_manifest_not_found';
|
|
15
|
+
export type OwnerAgentFailure = 'manifest_not_found' | 'agent_not_declared_by_owner';
|
|
16
|
+
export type HostAuthorizationFailure = 'manifest_not_found' | 'no_agent_entry' | 'collection_scope_mismatch' | 'property_scope_mismatch' | 'unsupported_constraints';
|
|
17
|
+
export interface Leg<F extends string> {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
failure?: F | 'evaluation_limit_exceeded';
|
|
20
|
+
detail?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface SupplyPathLegs {
|
|
23
|
+
/** Owner's adagents.json declares the collection (kind noted in detail). */
|
|
24
|
+
owner_collection_declared: Leg<OwnerCollectionFailure>;
|
|
25
|
+
/** The collection's distribution[] names the host, and any property_ids resolve in the host manifest. */
|
|
26
|
+
owner_distribution_carriage: Leg<OwnerCarriageFailure> & {
|
|
27
|
+
property_ids_matched?: string[];
|
|
28
|
+
property_ids_unmatched?: string[];
|
|
29
|
+
};
|
|
30
|
+
/** Owner's own adagents.json lists the sales agent. */
|
|
31
|
+
owner_agent_declared: Leg<OwnerAgentFailure>;
|
|
32
|
+
/** Host adagents.json authorizes the agent for the property, collection-scoped. */
|
|
33
|
+
host_authorization: Leg<HostAuthorizationFailure> & {
|
|
34
|
+
matched_entry?: {
|
|
35
|
+
url: string;
|
|
36
|
+
authorization_type?: string;
|
|
37
|
+
delegation_type?: string;
|
|
38
|
+
collections?: Array<{
|
|
39
|
+
publisher_domain: string;
|
|
40
|
+
collection_ids?: string[];
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/** Host ads.txt / app-ads.txt names the owner via inventorypartnerdomain=. */
|
|
45
|
+
inventory_partner_domain: Leg<'not_declared' | 'ads_txt_unavailable' | 'not_evaluated'>;
|
|
46
|
+
}
|
|
47
|
+
export interface SupplyPathVerdict {
|
|
48
|
+
/** Version of the canonical evaluator semantics and shared vector corpus. */
|
|
49
|
+
semantics_version: '1';
|
|
50
|
+
/** Concrete winning collection, including domain-level inquiries. */
|
|
51
|
+
resolved_collection_id?: string;
|
|
52
|
+
state: SupplyPathState;
|
|
53
|
+
legs: SupplyPathLegs;
|
|
54
|
+
}
|
|
55
|
+
export interface SupplyPathInput {
|
|
56
|
+
/** Canonicalized owner (channel publisher) domain. */
|
|
57
|
+
ownerDomain: string;
|
|
58
|
+
/** Canonicalized host (carrying property publisher) domain. */
|
|
59
|
+
hostDomain: string;
|
|
60
|
+
/** Seller agent URL as the buyer sees it. */
|
|
61
|
+
agentUrl: string;
|
|
62
|
+
/** Owner-assigned collection ID. Omit to verify the path at domain level (bulk deals). */
|
|
63
|
+
collectionId?: string;
|
|
64
|
+
/** Optional concrete product scope, resolved from the host manifest. Empty means unresolved. */
|
|
65
|
+
requiredHostPropertyIds?: string[];
|
|
66
|
+
/** Cross-origin authoritative documents must explicitly attribute every host property. */
|
|
67
|
+
requireExplicitHostPublisherDomain?: boolean;
|
|
68
|
+
/** Cross-origin owner catalogs must explicitly attribute collections and owner agent grants. */
|
|
69
|
+
requireExplicitOwnerPublisherDomain?: boolean;
|
|
70
|
+
ownerManifest: SupplyPathManifest | null;
|
|
71
|
+
hostManifest: SupplyPathManifest | null;
|
|
72
|
+
/**
|
|
73
|
+
* inventorypartnerdomain values from the host's ads.txt/app-ads.txt,
|
|
74
|
+
* already canonicalized. null = the files could not be fetched (distinct
|
|
75
|
+
* from fetched-and-absent, which is an empty array).
|
|
76
|
+
*/
|
|
77
|
+
hostInventoryPartnerDomains: string[] | null;
|
|
78
|
+
/** Per-file parsed evidence, so bulk inquiries evaluate each collection's applicable surfaces independently. */
|
|
79
|
+
hostInventoryPartnerDomainsByFile?: Partial<Record<'ads.txt' | 'app-ads.txt', string[] | null>>;
|
|
80
|
+
/** Previously observed authority-scoped revocations, even when a current manifest is unavailable. */
|
|
81
|
+
heldRevocations?: {
|
|
82
|
+
owner?: string[];
|
|
83
|
+
host?: string[];
|
|
84
|
+
};
|
|
85
|
+
/** False when the caller deliberately skipped IAB evidence after host authorization succeeded. */
|
|
86
|
+
inventoryPartnerDomainEvaluated?: boolean;
|
|
87
|
+
}
|
|
88
|
+
/** Canonical registry request; collection_id omission is a domain-level inquiry. */
|
|
89
|
+
export interface SupplyPathRequest {
|
|
90
|
+
owner_domain: string;
|
|
91
|
+
host_domain: string;
|
|
92
|
+
agent_url: string;
|
|
93
|
+
collection_id?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface RegistrySupplyPathResult extends SupplyPathRequest, Omit<SupplyPathVerdict, 'legs'> {
|
|
96
|
+
legs: {
|
|
97
|
+
[K in keyof SupplyPathLegs]: Omit<SupplyPathLegs[K], 'failure'> & {
|
|
98
|
+
failure?: string;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
sources: {
|
|
102
|
+
owner_adagents_url: string;
|
|
103
|
+
host_adagents_url: string;
|
|
104
|
+
cached: boolean;
|
|
105
|
+
/** Cache observation times, distinct from the verdict's checked_at. */
|
|
106
|
+
owner_fetched_at: string | null;
|
|
107
|
+
host_fetched_at: string | null;
|
|
108
|
+
owner_resolved_url: string | null;
|
|
109
|
+
host_resolved_url: string | null;
|
|
110
|
+
};
|
|
111
|
+
checked_at: string;
|
|
112
|
+
}
|
|
113
|
+
export interface SupplyPathEvidence {
|
|
114
|
+
kind: 'adagents' | 'ads.txt' | 'app-ads.txt';
|
|
115
|
+
publisher_domain: string;
|
|
116
|
+
requested_url: string;
|
|
117
|
+
resolved_url?: string;
|
|
118
|
+
fetched_at: string;
|
|
119
|
+
status?: number;
|
|
120
|
+
/** Hash of the exact decompressed response bytes, including pointer/redirect bodies. */
|
|
121
|
+
sha256?: string;
|
|
122
|
+
byte_length?: number;
|
|
123
|
+
connection_pinned?: boolean;
|
|
124
|
+
error?: string;
|
|
125
|
+
/** Sanitized transport code such as ECONNREFUSED; never contains the underlying error message. */
|
|
126
|
+
cause_code?: string;
|
|
127
|
+
/** Present for HTTP redirects and authoritative_location delegation. */
|
|
128
|
+
delegated_to?: string;
|
|
129
|
+
/** Exact bytes for audit/replay when retainEvidenceBodies is enabled. */
|
|
130
|
+
body_base64?: string;
|
|
131
|
+
}
|
|
132
|
+
export interface AuthoritativeSupplyPathResult extends Omit<RegistrySupplyPathResult, 'sources'> {
|
|
133
|
+
source: 'authoritative';
|
|
134
|
+
legs: SupplyPathLegs;
|
|
135
|
+
property_selectors?: import('../discovery/types.mjs').SinglePublisherPropertySelector[];
|
|
136
|
+
sources: Pick<RegistrySupplyPathResult['sources'], 'owner_adagents_url' | 'host_adagents_url'> & {
|
|
137
|
+
cached: false;
|
|
138
|
+
evidence: SupplyPathEvidence[];
|
|
139
|
+
held_revocations: Array<{
|
|
140
|
+
authority: string;
|
|
141
|
+
entries: readonly import('./revocations.mjs').SupplyPathRevocation[];
|
|
142
|
+
}>;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export interface AuthoritativeSupplyPathOptions {
|
|
146
|
+
source: 'authoritative';
|
|
147
|
+
/** Defaults to a process-local seven-day hold; supply durable storage across workers/restarts. */
|
|
148
|
+
revocationStore?: import('./revocations.mjs').SupplyPathRevocationStore;
|
|
149
|
+
/** Read-only check plus atomic observe pins only validated manifests; changed locations require confirmed migration. */
|
|
150
|
+
authorityStore?: import('./revocations.mjs').SupplyPathAuthorityStore;
|
|
151
|
+
/** Optional product property scope. Every selected host property must be proven. */
|
|
152
|
+
propertySelectors?: import('../discovery/types.mjs').SinglePublisherPropertySelector[];
|
|
153
|
+
/** Overall deadline, including all evidence and redirect fetches. Default 15 seconds, max 60 seconds. */
|
|
154
|
+
timeoutMs?: number;
|
|
155
|
+
/** Per-response decompressed byte cap. Default 256 KiB, max 20 MiB. */
|
|
156
|
+
maxBodyBytes?: number;
|
|
157
|
+
signal?: AbortSignal;
|
|
158
|
+
/** Default false. Bodies contain counterparty-controlled content; store as opaque evidence. */
|
|
159
|
+
retainEvidenceBodies?: boolean;
|
|
160
|
+
/** Trusted egress implementation; takes responsibility for DNS and address policy. */
|
|
161
|
+
trustedFetchFn?: SsrfFetchOptions['trustedFetchFn'];
|
|
162
|
+
}
|
|
163
|
+
export interface RegistrySupplyPathOptions {
|
|
164
|
+
source: 'registry';
|
|
165
|
+
/** Caller-configured registry; omitted uses the canonical registry client. */
|
|
166
|
+
registry?: Pick<RegistryClient, 'verifySupplyPath'>;
|
|
167
|
+
}
|
|
168
|
+
export type VerifySupplyPathOptions = AuthoritativeSupplyPathOptions | RegistrySupplyPathOptions;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/** Supply-path contract from adcontextprotocol/adcp#6897. */
|
|
2
|
+
import type { SsrfFetchOptions } from '../net/ssrf-fetch';
|
|
3
|
+
import type { RegistryClient } from '../registry';
|
|
4
|
+
/** Untrusted evidence. The evaluator validates every authorization-relevant field. */
|
|
5
|
+
export interface SupplyPathManifest {
|
|
6
|
+
authorized_agents?: unknown;
|
|
7
|
+
properties?: unknown;
|
|
8
|
+
collections?: unknown;
|
|
9
|
+
revoked_publisher_domains?: unknown;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export type SupplyPathState = 'verified_owner_sold' | 'host_delegated' | 'owner_attested' | 'unverified';
|
|
13
|
+
export type OwnerCollectionFailure = 'manifest_not_found' | 'no_collections_declared' | 'collection_not_declared' | 'publisher_revoked';
|
|
14
|
+
export type OwnerCarriageFailure = 'collection_leg_failed' | 'no_distribution_for_host' | 'property_ids_unresolved' | 'host_manifest_not_found';
|
|
15
|
+
export type OwnerAgentFailure = 'manifest_not_found' | 'agent_not_declared_by_owner';
|
|
16
|
+
export type HostAuthorizationFailure = 'manifest_not_found' | 'no_agent_entry' | 'collection_scope_mismatch' | 'property_scope_mismatch' | 'unsupported_constraints';
|
|
17
|
+
export interface Leg<F extends string> {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
failure?: F | 'evaluation_limit_exceeded';
|
|
20
|
+
detail?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface SupplyPathLegs {
|
|
23
|
+
/** Owner's adagents.json declares the collection (kind noted in detail). */
|
|
24
|
+
owner_collection_declared: Leg<OwnerCollectionFailure>;
|
|
25
|
+
/** The collection's distribution[] names the host, and any property_ids resolve in the host manifest. */
|
|
26
|
+
owner_distribution_carriage: Leg<OwnerCarriageFailure> & {
|
|
27
|
+
property_ids_matched?: string[];
|
|
28
|
+
property_ids_unmatched?: string[];
|
|
29
|
+
};
|
|
30
|
+
/** Owner's own adagents.json lists the sales agent. */
|
|
31
|
+
owner_agent_declared: Leg<OwnerAgentFailure>;
|
|
32
|
+
/** Host adagents.json authorizes the agent for the property, collection-scoped. */
|
|
33
|
+
host_authorization: Leg<HostAuthorizationFailure> & {
|
|
34
|
+
matched_entry?: {
|
|
35
|
+
url: string;
|
|
36
|
+
authorization_type?: string;
|
|
37
|
+
delegation_type?: string;
|
|
38
|
+
collections?: Array<{
|
|
39
|
+
publisher_domain: string;
|
|
40
|
+
collection_ids?: string[];
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/** Host ads.txt / app-ads.txt names the owner via inventorypartnerdomain=. */
|
|
45
|
+
inventory_partner_domain: Leg<'not_declared' | 'ads_txt_unavailable' | 'not_evaluated'>;
|
|
46
|
+
}
|
|
47
|
+
export interface SupplyPathVerdict {
|
|
48
|
+
/** Version of the canonical evaluator semantics and shared vector corpus. */
|
|
49
|
+
semantics_version: '1';
|
|
50
|
+
/** Concrete winning collection, including domain-level inquiries. */
|
|
51
|
+
resolved_collection_id?: string;
|
|
52
|
+
state: SupplyPathState;
|
|
53
|
+
legs: SupplyPathLegs;
|
|
54
|
+
}
|
|
55
|
+
export interface SupplyPathInput {
|
|
56
|
+
/** Canonicalized owner (channel publisher) domain. */
|
|
57
|
+
ownerDomain: string;
|
|
58
|
+
/** Canonicalized host (carrying property publisher) domain. */
|
|
59
|
+
hostDomain: string;
|
|
60
|
+
/** Seller agent URL as the buyer sees it. */
|
|
61
|
+
agentUrl: string;
|
|
62
|
+
/** Owner-assigned collection ID. Omit to verify the path at domain level (bulk deals). */
|
|
63
|
+
collectionId?: string;
|
|
64
|
+
/** Optional concrete product scope, resolved from the host manifest. Empty means unresolved. */
|
|
65
|
+
requiredHostPropertyIds?: string[];
|
|
66
|
+
/** Cross-origin authoritative documents must explicitly attribute every host property. */
|
|
67
|
+
requireExplicitHostPublisherDomain?: boolean;
|
|
68
|
+
/** Cross-origin owner catalogs must explicitly attribute collections and owner agent grants. */
|
|
69
|
+
requireExplicitOwnerPublisherDomain?: boolean;
|
|
70
|
+
ownerManifest: SupplyPathManifest | null;
|
|
71
|
+
hostManifest: SupplyPathManifest | null;
|
|
72
|
+
/**
|
|
73
|
+
* inventorypartnerdomain values from the host's ads.txt/app-ads.txt,
|
|
74
|
+
* already canonicalized. null = the files could not be fetched (distinct
|
|
75
|
+
* from fetched-and-absent, which is an empty array).
|
|
76
|
+
*/
|
|
77
|
+
hostInventoryPartnerDomains: string[] | null;
|
|
78
|
+
/** Per-file parsed evidence, so bulk inquiries evaluate each collection's applicable surfaces independently. */
|
|
79
|
+
hostInventoryPartnerDomainsByFile?: Partial<Record<'ads.txt' | 'app-ads.txt', string[] | null>>;
|
|
80
|
+
/** Previously observed authority-scoped revocations, even when a current manifest is unavailable. */
|
|
81
|
+
heldRevocations?: {
|
|
82
|
+
owner?: string[];
|
|
83
|
+
host?: string[];
|
|
84
|
+
};
|
|
85
|
+
/** False when the caller deliberately skipped IAB evidence after host authorization succeeded. */
|
|
86
|
+
inventoryPartnerDomainEvaluated?: boolean;
|
|
87
|
+
}
|
|
88
|
+
/** Canonical registry request; collection_id omission is a domain-level inquiry. */
|
|
89
|
+
export interface SupplyPathRequest {
|
|
90
|
+
owner_domain: string;
|
|
91
|
+
host_domain: string;
|
|
92
|
+
agent_url: string;
|
|
93
|
+
collection_id?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface RegistrySupplyPathResult extends SupplyPathRequest, Omit<SupplyPathVerdict, 'legs'> {
|
|
96
|
+
legs: {
|
|
97
|
+
[K in keyof SupplyPathLegs]: Omit<SupplyPathLegs[K], 'failure'> & {
|
|
98
|
+
failure?: string;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
sources: {
|
|
102
|
+
owner_adagents_url: string;
|
|
103
|
+
host_adagents_url: string;
|
|
104
|
+
cached: boolean;
|
|
105
|
+
/** Cache observation times, distinct from the verdict's checked_at. */
|
|
106
|
+
owner_fetched_at: string | null;
|
|
107
|
+
host_fetched_at: string | null;
|
|
108
|
+
owner_resolved_url: string | null;
|
|
109
|
+
host_resolved_url: string | null;
|
|
110
|
+
};
|
|
111
|
+
checked_at: string;
|
|
112
|
+
}
|
|
113
|
+
export interface SupplyPathEvidence {
|
|
114
|
+
kind: 'adagents' | 'ads.txt' | 'app-ads.txt';
|
|
115
|
+
publisher_domain: string;
|
|
116
|
+
requested_url: string;
|
|
117
|
+
resolved_url?: string;
|
|
118
|
+
fetched_at: string;
|
|
119
|
+
status?: number;
|
|
120
|
+
/** Hash of the exact decompressed response bytes, including pointer/redirect bodies. */
|
|
121
|
+
sha256?: string;
|
|
122
|
+
byte_length?: number;
|
|
123
|
+
connection_pinned?: boolean;
|
|
124
|
+
error?: string;
|
|
125
|
+
/** Sanitized transport code such as ECONNREFUSED; never contains the underlying error message. */
|
|
126
|
+
cause_code?: string;
|
|
127
|
+
/** Present for HTTP redirects and authoritative_location delegation. */
|
|
128
|
+
delegated_to?: string;
|
|
129
|
+
/** Exact bytes for audit/replay when retainEvidenceBodies is enabled. */
|
|
130
|
+
body_base64?: string;
|
|
131
|
+
}
|
|
132
|
+
export interface AuthoritativeSupplyPathResult extends Omit<RegistrySupplyPathResult, 'sources'> {
|
|
133
|
+
source: 'authoritative';
|
|
134
|
+
legs: SupplyPathLegs;
|
|
135
|
+
property_selectors?: import('../discovery/types').SinglePublisherPropertySelector[];
|
|
136
|
+
sources: Pick<RegistrySupplyPathResult['sources'], 'owner_adagents_url' | 'host_adagents_url'> & {
|
|
137
|
+
cached: false;
|
|
138
|
+
evidence: SupplyPathEvidence[];
|
|
139
|
+
held_revocations: Array<{
|
|
140
|
+
authority: string;
|
|
141
|
+
entries: readonly import('./revocations').SupplyPathRevocation[];
|
|
142
|
+
}>;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export interface AuthoritativeSupplyPathOptions {
|
|
146
|
+
source: 'authoritative';
|
|
147
|
+
/** Defaults to a process-local seven-day hold; supply durable storage across workers/restarts. */
|
|
148
|
+
revocationStore?: import('./revocations').SupplyPathRevocationStore;
|
|
149
|
+
/** Read-only check plus atomic observe pins only validated manifests; changed locations require confirmed migration. */
|
|
150
|
+
authorityStore?: import('./revocations').SupplyPathAuthorityStore;
|
|
151
|
+
/** Optional product property scope. Every selected host property must be proven. */
|
|
152
|
+
propertySelectors?: import('../discovery/types').SinglePublisherPropertySelector[];
|
|
153
|
+
/** Overall deadline, including all evidence and redirect fetches. Default 15 seconds, max 60 seconds. */
|
|
154
|
+
timeoutMs?: number;
|
|
155
|
+
/** Per-response decompressed byte cap. Default 256 KiB, max 20 MiB. */
|
|
156
|
+
maxBodyBytes?: number;
|
|
157
|
+
signal?: AbortSignal;
|
|
158
|
+
/** Default false. Bodies contain counterparty-controlled content; store as opaque evidence. */
|
|
159
|
+
retainEvidenceBodies?: boolean;
|
|
160
|
+
/** Trusted egress implementation; takes responsibility for DNS and address policy. */
|
|
161
|
+
trustedFetchFn?: SsrfFetchOptions['trustedFetchFn'];
|
|
162
|
+
}
|
|
163
|
+
export interface RegistrySupplyPathOptions {
|
|
164
|
+
source: 'registry';
|
|
165
|
+
/** Caller-configured registry; omitted uses the canonical registry client. */
|
|
166
|
+
registry?: Pick<RegistryClient, 'verifySupplyPath'>;
|
|
167
|
+
}
|
|
168
|
+
export type VerifySupplyPathOptions = AuthoritativeSupplyPathOptions | RegistrySupplyPathOptions;
|
|
@@ -0,0 +1,16 @@
|
|
|
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 __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
var types_exports = {};
|
|
16
|
+
module.exports = __toCommonJS(types_exports);
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SupplyPathRequest } from './types.mjs';
|
|
2
|
+
export declare function record(value: unknown): value is Record<string, unknown>;
|
|
3
|
+
export declare function records(value: unknown): Record<string, unknown>[];
|
|
4
|
+
export declare function strings(value: unknown): value is string[];
|
|
5
|
+
/** Domain identity never strips www or conflates sibling publisher namespaces. */
|
|
6
|
+
export declare function domain(value: unknown): string | null;
|
|
7
|
+
export declare function agentIdentity(value: unknown): string | null;
|
|
8
|
+
export declare function validateSupplyPathRequest(input: SupplyPathRequest): SupplyPathRequest;
|
|
9
|
+
/** Runtime boundary for cached remote verdicts. Unknown extensions are preserved. */
|
|
10
|
+
export declare function assertRegistrySupplyPathResult(value: unknown, request: SupplyPathRequest): asserts value is import('./types.mjs').RegistrySupplyPathResult;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SupplyPathRequest } from './types';
|
|
2
|
+
export declare function record(value: unknown): value is Record<string, unknown>;
|
|
3
|
+
export declare function records(value: unknown): Record<string, unknown>[];
|
|
4
|
+
export declare function strings(value: unknown): value is string[];
|
|
5
|
+
/** Domain identity never strips www or conflates sibling publisher namespaces. */
|
|
6
|
+
export declare function domain(value: unknown): string | null;
|
|
7
|
+
export declare function agentIdentity(value: unknown): string | null;
|
|
8
|
+
export declare function validateSupplyPathRequest(input: SupplyPathRequest): SupplyPathRequest;
|
|
9
|
+
/** Runtime boundary for cached remote verdicts. Unknown extensions are preserved. */
|
|
10
|
+
export declare function assertRegistrySupplyPathResult(value: unknown, request: SupplyPathRequest): asserts value is import('./types').RegistrySupplyPathResult;
|