@adcp/sdk 15.9.0 → 16.0.0-beta.1
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/bin/adcp-identity.js +74 -0
- package/bin/adcp.js +2 -0
- package/dist/lib/adapters/keyed-account-backend.d.mts +37 -0
- package/dist/lib/adapters/keyed-account-backend.d.ts +37 -0
- package/dist/lib/adapters/keyed-account-backend.js +121 -0
- package/dist/lib/adapters/keyed-account-backend.mjs +94 -0
- package/dist/lib/adapters/keyed-account-store.d.mts +28 -0
- package/dist/lib/adapters/keyed-account-store.d.ts +28 -0
- package/dist/lib/adapters/keyed-account-store.js +227 -0
- package/dist/lib/adapters/keyed-account-store.mjs +203 -0
- package/dist/lib/core/SingleAgentClient.d.mts +16 -2
- package/dist/lib/core/SingleAgentClient.d.ts +16 -2
- package/dist/lib/core/SingleAgentClient.js +259 -62
- package/dist/lib/core/SingleAgentClient.mjs +261 -57
- package/dist/lib/core/TaskExecutor.d.mts +6 -0
- package/dist/lib/core/TaskExecutor.d.ts +6 -0
- package/dist/lib/core/TaskExecutor.js +66 -5
- package/dist/lib/core/TaskExecutor.mjs +71 -5
- package/dist/lib/core/postgres-webhook-registration-store.js +32 -5
- package/dist/lib/core/postgres-webhook-registration-store.mjs +32 -5
- package/dist/lib/core/redis-webhook-registration-store.js +23 -1
- package/dist/lib/core/redis-webhook-registration-store.mjs +23 -1
- package/dist/lib/core/webhook-registration.d.mts +7 -1
- package/dist/lib/core/webhook-registration.d.ts +7 -1
- package/dist/lib/core/webhook-registration.js +24 -2
- package/dist/lib/core/webhook-registration.mjs +23 -2
- package/dist/lib/identity-3.3/index.d.mts +10 -0
- package/dist/lib/identity-3.3/index.d.ts +10 -0
- package/dist/lib/identity-3.3/index.js +75 -0
- package/dist/lib/identity-3.3/index.mjs +46 -0
- package/dist/lib/identity-3.3/lifecycle.d.mts +113 -0
- package/dist/lib/identity-3.3/lifecycle.d.ts +113 -0
- package/dist/lib/identity-3.3/lifecycle.js +267 -0
- package/dist/lib/identity-3.3/lifecycle.mjs +240 -0
- package/dist/lib/identity-3.3/revocation.d.mts +50 -0
- package/dist/lib/identity-3.3/revocation.d.ts +50 -0
- package/dist/lib/identity-3.3/revocation.js +238 -0
- package/dist/lib/identity-3.3/revocation.mjs +216 -0
- package/dist/lib/identity-3.3/schemas.draft.d.mts +2472 -0
- package/dist/lib/identity-3.3/schemas.draft.d.ts +2472 -0
- package/dist/lib/identity-3.3/schemas.draft.js +1448 -0
- package/dist/lib/identity-3.3/schemas.draft.mjs +1428 -0
- package/dist/lib/identity-3.3/server.d.mts +34 -0
- package/dist/lib/identity-3.3/server.d.ts +34 -0
- package/dist/lib/identity-3.3/server.js +219 -0
- package/dist/lib/identity-3.3/server.mjs +194 -0
- package/dist/lib/identity-3.3/store.d.mts +24 -0
- package/dist/lib/identity-3.3/store.d.ts +24 -0
- package/dist/lib/identity-3.3/store.js +191 -0
- package/dist/lib/identity-3.3/store.mjs +169 -0
- package/dist/lib/identity-3.3/trust.d.mts +94 -0
- package/dist/lib/identity-3.3/trust.d.ts +94 -0
- package/dist/lib/identity-3.3/trust.js +278 -0
- package/dist/lib/identity-3.3/trust.mjs +239 -0
- package/dist/lib/identity-3.3/types.d.mts +127 -0
- package/dist/lib/identity-3.3/types.d.ts +127 -0
- package/dist/lib/identity-3.3/types.js +16 -0
- package/dist/lib/identity-3.3/types.mjs +0 -0
- package/dist/lib/identity-3.3/validation.d.mts +2 -0
- package/dist/lib/identity-3.3/validation.d.ts +2 -0
- package/dist/lib/identity-3.3/validation.js +125 -0
- package/dist/lib/identity-3.3/validation.mjs +91 -0
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/reporting/azure/index.d.mts +5 -0
- package/dist/lib/reporting/azure/index.d.ts +5 -0
- package/dist/lib/reporting/azure/index.js +26 -7
- package/dist/lib/reporting/azure/index.mjs +26 -7
- package/dist/lib/reporting/bigquery/index.d.mts +80 -25
- package/dist/lib/reporting/bigquery/index.d.ts +80 -25
- package/dist/lib/reporting/bigquery/index.js +184 -81
- package/dist/lib/reporting/bigquery/index.mjs +182 -80
- package/dist/lib/reporting/gcs/adapter.d.mts +8 -1
- package/dist/lib/reporting/gcs/adapter.d.ts +8 -1
- package/dist/lib/reporting/gcs/errors.d.mts +6 -0
- package/dist/lib/reporting/gcs/errors.d.ts +6 -0
- package/dist/lib/reporting/gcs/fence.d.mts +5 -0
- package/dist/lib/reporting/gcs/fence.d.ts +5 -0
- package/dist/lib/reporting/gcs/index.d.mts +9 -0
- package/dist/lib/reporting/gcs/index.d.ts +9 -0
- package/dist/lib/reporting/gcs/reader.d.mts +27 -3
- package/dist/lib/reporting/gcs/reader.d.ts +27 -3
- package/dist/lib/reporting/gcs/row-provider.d.mts +7 -0
- package/dist/lib/reporting/gcs/row-provider.d.ts +7 -0
- package/dist/lib/reporting/gcs/row-provider.js +34 -14
- package/dist/lib/reporting/gcs/row-provider.mjs +34 -14
- package/dist/lib/reporting/ledger/change-feed.d.mts +22 -1
- package/dist/lib/reporting/ledger/change-feed.d.ts +22 -1
- package/dist/lib/reporting/ledger/index.d.mts +11 -0
- package/dist/lib/reporting/ledger/index.d.ts +11 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +8 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +8 -0
- package/dist/lib/reporting/ledger/managed-router.d.mts +27 -2
- package/dist/lib/reporting/ledger/managed-router.d.ts +27 -2
- package/dist/lib/reporting/ledger/managed.d.mts +86 -6
- package/dist/lib/reporting/ledger/managed.d.ts +86 -6
- package/dist/lib/reporting/ledger/notification-activity.d.mts +65 -3
- package/dist/lib/reporting/ledger/notification-activity.d.ts +65 -3
- package/dist/lib/reporting/ledger/object-writes.d.mts +64 -5
- package/dist/lib/reporting/ledger/object-writes.d.ts +64 -5
- package/dist/lib/reporting/ledger/postgres.d.mts +43 -9
- package/dist/lib/reporting/ledger/postgres.d.ts +43 -9
- package/dist/lib/reporting/ledger/postgres.js +43 -27
- package/dist/lib/reporting/ledger/postgres.mjs +43 -27
- package/dist/lib/reporting/ledger/row-encoding.d.mts +92 -6
- package/dist/lib/reporting/ledger/row-encoding.d.ts +92 -6
- package/dist/lib/reporting/ledger/row-encoding.js +8 -4
- package/dist/lib/reporting/ledger/row-encoding.mjs +6 -3
- package/dist/lib/reporting/ledger/row-storage-errors.d.mts +11 -1
- package/dist/lib/reporting/ledger/row-storage-errors.d.ts +11 -1
- package/dist/lib/reporting/ledger/row-storage-migration.d.mts +19 -1
- package/dist/lib/reporting/ledger/row-storage-migration.d.ts +19 -1
- package/dist/lib/reporting/ledger/row-storage-migration.js +133 -18
- package/dist/lib/reporting/ledger/row-storage-migration.mjs +133 -18
- package/dist/lib/reporting/ledger/row-storage-object.d.mts +103 -12
- package/dist/lib/reporting/ledger/row-storage-object.d.ts +103 -12
- package/dist/lib/reporting/ledger/row-storage-object.js +106 -31
- package/dist/lib/reporting/ledger/row-storage-object.mjs +104 -31
- package/dist/lib/reporting/ledger/row-storage.d.mts +87 -20
- package/dist/lib/reporting/ledger/row-storage.d.ts +87 -20
- package/dist/lib/reporting/ledger/row-storage.js +126 -66
- package/dist/lib/reporting/ledger/row-storage.mjs +129 -67
- package/dist/lib/reporting/ledger/schedule.d.mts +13 -0
- package/dist/lib/reporting/ledger/schedule.d.ts +13 -0
- package/dist/lib/reporting/ledger/schedule.js +24 -0
- package/dist/lib/reporting/ledger/schedule.mjs +23 -0
- package/dist/lib/reporting/ledger/types.d.mts +23 -1
- package/dist/lib/reporting/ledger/types.d.ts +23 -1
- package/dist/lib/reporting/s3/index.d.mts +5 -0
- package/dist/lib/reporting/s3/index.d.ts +5 -0
- package/dist/lib/reporting/s3/index.js +37 -14
- package/dist/lib/reporting/s3/index.mjs +37 -14
- package/dist/lib/reporting/service/index.d.mts +10 -0
- package/dist/lib/reporting/service/index.d.ts +10 -0
- package/dist/lib/reporting/service/maintenance.d.mts +28 -2
- package/dist/lib/reporting/service/maintenance.d.ts +28 -2
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/account-sync-contract.d.mts +14 -0
- package/dist/lib/server/account-sync-contract.d.ts +14 -0
- package/dist/lib/server/account-sync-contract.js +225 -0
- package/dist/lib/server/account-sync-contract.mjs +197 -0
- package/dist/lib/server/adcp-server.js +5 -0
- package/dist/lib/server/adcp-server.mjs +10 -0
- package/dist/lib/server/auth-signature.d.mts +10 -0
- package/dist/lib/server/auth-signature.d.ts +10 -0
- package/dist/lib/server/auth-signature.js +61 -2
- package/dist/lib/server/auth-signature.mjs +65 -2
- package/dist/lib/server/auth.d.mts +6 -0
- package/dist/lib/server/auth.d.ts +6 -0
- package/dist/lib/server/auth.js +6 -0
- package/dist/lib/server/auth.mjs +6 -0
- package/dist/lib/server/create-adcp-server.d.mts +19 -5
- package/dist/lib/server/create-adcp-server.d.ts +19 -5
- package/dist/lib/server/create-adcp-server.js +238 -19
- package/dist/lib/server/create-adcp-server.mjs +240 -10
- package/dist/lib/server/decisioning/account.d.mts +24 -1
- package/dist/lib/server/decisioning/account.d.ts +24 -1
- package/dist/lib/server/decisioning/index.d.mts +1 -1
- package/dist/lib/server/decisioning/index.d.ts +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +0 -50
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +0 -50
- package/dist/lib/server/decisioning/runtime/from-platform.js +61 -11
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +65 -12
- package/dist/lib/server/index.d.mts +2 -0
- package/dist/lib/server/index.d.ts +2 -0
- package/dist/lib/server/index.js +12 -0
- package/dist/lib/server/index.mjs +12 -0
- package/dist/lib/server/notification-subscriptions/runtime.js +9 -1
- package/dist/lib/server/notification-subscriptions/runtime.mjs +9 -1
- package/dist/lib/server/notification-subscriptions/types.d.mts +5 -0
- package/dist/lib/server/notification-subscriptions/types.d.ts +5 -0
- package/dist/lib/server/principal/types.d.mts +1 -1
- package/dist/lib/server/principal/types.d.ts +1 -1
- package/dist/lib/server/serve.js +5 -0
- package/dist/lib/server/serve.mjs +5 -0
- package/dist/lib/server/webhook-delivery/recovery.d.mts +1 -0
- package/dist/lib/server/webhook-delivery/recovery.d.ts +1 -0
- package/dist/lib/server/webhook-delivery/recovery.js +4 -0
- package/dist/lib/server/webhook-delivery/recovery.mjs +4 -0
- package/dist/lib/server/webhook-emitter.d.mts +10 -0
- package/dist/lib/server/webhook-emitter.d.ts +10 -0
- package/dist/lib/server/webhook-emitter.js +22 -0
- package/dist/lib/server/webhook-emitter.mjs +22 -0
- package/dist/lib/signing/agent-context.d.mts +0 -5
- package/dist/lib/signing/agent-context.d.ts +0 -5
- package/dist/lib/signing/agent-context.js +9 -1
- package/dist/lib/signing/agent-context.mjs +9 -1
- package/dist/lib/signing/agent-fetch.js +27 -2
- package/dist/lib/signing/agent-fetch.mjs +32 -2
- package/dist/lib/signing/agent-resolver/canonicalize.d.mts +10 -15
- package/dist/lib/signing/agent-resolver/canonicalize.d.ts +10 -15
- package/dist/lib/signing/agent-resolver/canonicalize.js +17 -5
- package/dist/lib/signing/agent-resolver/canonicalize.mjs +16 -5
- package/dist/lib/signing/agent-resolver/index.d.mts +1 -0
- package/dist/lib/signing/agent-resolver/index.d.ts +1 -0
- package/dist/lib/signing/agent-resolver/index.js +5 -0
- package/dist/lib/signing/agent-resolver/index.mjs +3 -0
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +3 -2
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +3 -2
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +30 -3
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +30 -3
- package/dist/lib/signing/agent-resolver/strict-json.d.mts +2 -2
- package/dist/lib/signing/agent-resolver/strict-json.d.ts +2 -2
- package/dist/lib/signing/agent-resolver/strict-json.js +5 -3
- package/dist/lib/signing/agent-resolver/strict-json.mjs +5 -3
- package/dist/lib/signing/brand-jwks.d.mts +2 -2
- package/dist/lib/signing/brand-jwks.d.ts +2 -2
- package/dist/lib/signing/brand-jwks.js +4 -4
- package/dist/lib/signing/brand-jwks.mjs +4 -4
- package/dist/lib/signing/client.d.mts +1 -0
- package/dist/lib/signing/client.d.ts +1 -0
- package/dist/lib/signing/client.js +5 -0
- package/dist/lib/signing/client.mjs +3 -0
- package/dist/lib/signing/jwks-https.d.mts +1 -1
- package/dist/lib/signing/jwks-https.d.ts +1 -1
- package/dist/lib/signing/jwks-https.js +1 -1
- package/dist/lib/signing/jwks-https.mjs +1 -1
- package/dist/lib/signing/jwks.d.mts +11 -3
- package/dist/lib/signing/jwks.d.ts +11 -3
- package/dist/lib/signing/jwks.js +1 -1
- package/dist/lib/signing/jwks.mjs +1 -1
- package/dist/lib/signing/parser.d.mts +1 -1
- package/dist/lib/signing/parser.d.ts +1 -1
- package/dist/lib/signing/parser.js +5 -3
- package/dist/lib/signing/parser.mjs +6 -4
- package/dist/lib/signing/revocation.d.mts +4 -1
- package/dist/lib/signing/revocation.d.ts +4 -1
- package/dist/lib/signing/revocation.js +33 -3
- package/dist/lib/signing/revocation.mjs +31 -2
- package/dist/lib/signing/server.d.mts +1 -1
- package/dist/lib/signing/server.d.ts +1 -1
- package/dist/lib/signing/server.js +4 -0
- package/dist/lib/signing/server.mjs +4 -0
- package/dist/lib/signing/types.d.mts +3 -0
- package/dist/lib/signing/types.d.ts +3 -0
- package/dist/lib/signing/web-bot-auth.d.mts +117 -0
- package/dist/lib/signing/web-bot-auth.d.ts +117 -0
- package/dist/lib/signing/web-bot-auth.js +660 -0
- package/dist/lib/signing/web-bot-auth.mjs +624 -0
- package/dist/lib/testing/client.d.mts +1 -4
- package/dist/lib/testing/client.d.ts +1 -4
- package/dist/lib/testing/client.js +141 -20
- package/dist/lib/testing/client.mjs +137 -19
- package/dist/lib/testing/compliance/comply.js +29 -10
- package/dist/lib/testing/compliance/comply.mjs +37 -11
- package/dist/lib/testing/storyboard/account-sync-contract.d.mts +3 -0
- package/dist/lib/testing/storyboard/account-sync-contract.d.ts +3 -0
- package/dist/lib/testing/storyboard/account-sync-contract.js +79 -0
- package/dist/lib/testing/storyboard/account-sync-contract.mjs +55 -0
- package/dist/lib/testing/storyboard/default-invariants.js +2 -0
- package/dist/lib/testing/storyboard/default-invariants.mjs +2 -0
- package/dist/lib/testing/storyboard/runner.js +23 -8
- package/dist/lib/testing/storyboard/runner.mjs +24 -8
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/adcp.d.mts +4 -0
- package/dist/lib/types/adcp.d.ts +4 -0
- package/dist/lib/types/schemas.generated.d.ts +6 -6
- package/dist/lib/utils/capabilities.d.mts +1 -0
- package/dist/lib/utils/capabilities.d.ts +1 -0
- package/dist/lib/utils/capabilities.js +5 -0
- package/dist/lib/utils/capabilities.mjs +5 -0
- package/dist/lib/v2/projection/creative-delivery.d.mts +3 -1
- package/dist/lib/v2/projection/creative-delivery.d.ts +3 -1
- package/dist/lib/v2/projection/creative-delivery.js +26 -10
- package/dist/lib/v2/projection/creative-delivery.mjs +26 -10
- package/dist/lib/v2/projection/index.d.mts +1 -1
- package/dist/lib/v2/projection/index.d.ts +1 -1
- package/dist/lib/v2/projection/legacy-routes.d.mts +24 -2
- package/dist/lib/v2/projection/legacy-routes.d.ts +24 -2
- package/dist/lib/v2/projection/legacy-routes.js +28 -2
- package/dist/lib/v2/projection/legacy-routes.mjs +26 -2
- package/dist/lib/validation/schema-loader.d.mts +2 -0
- package/dist/lib/validation/schema-loader.d.ts +2 -0
- package/dist/lib/validation/schema-loader.js +43 -4
- package/dist/lib/validation/schema-loader.mjs +39 -3
- 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/DISCOVERY-CACHE-AND-SESSION-REUSE.md +4 -0
- package/docs/guides/REPORTING-LEDGER-CUTOVER.md +1 -1
- package/docs/guides/REPORTING-LEDGER.md +132 -46
- package/docs/guides/REPORTING-OPERATIONS.md +25 -4
- package/docs/guides/REPORTING-STABILITY.md +76 -0
- package/docs/guides/account-resolution.md +101 -0
- package/docs/llms.txt +3 -2
- package/docs/migration-12-to-13.md +7 -0
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-agent-identity-3.3.md +355 -0
- package/docs/migration-agent-resolution-3.3.md +5 -0
- package/docs/migration-reporting-row-storage-alignment.md +137 -0
- package/examples/storyboards/account-sync-contract.yaml +57 -0
- package/package.json +15 -1
|
@@ -0,0 +1,267 @@
|
|
|
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 lifecycle_exports = {};
|
|
20
|
+
__export(lifecycle_exports, {
|
|
21
|
+
InMemoryOriginIdentityStore: () => InMemoryOriginIdentityStore,
|
|
22
|
+
OriginIdentityLifecycle: () => OriginIdentityLifecycle,
|
|
23
|
+
evaluateOnboardingRequirements: () => evaluateOnboardingRequirements,
|
|
24
|
+
validateAgentOnboarding: () => validateAgentOnboarding
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(lifecycle_exports);
|
|
27
|
+
var import_crypto = require("crypto");
|
|
28
|
+
var import_tldts = require("tldts");
|
|
29
|
+
var import_canonicalize = require('../signing/agent-resolver/canonicalize.js');
|
|
30
|
+
var import_etld = require('../signing/agent-resolver/etld.js');
|
|
31
|
+
var import_trust = require('./trust.js');
|
|
32
|
+
class InMemoryOriginIdentityStore {
|
|
33
|
+
durability = "process-local";
|
|
34
|
+
bindings = /* @__PURE__ */ new Map();
|
|
35
|
+
applications = /* @__PURE__ */ new Map();
|
|
36
|
+
async getBinding(origin) {
|
|
37
|
+
const value = this.bindings.get((0, import_canonicalize.canonicalAgentOrigin)(origin));
|
|
38
|
+
return value && structuredClone(value);
|
|
39
|
+
}
|
|
40
|
+
async bind(binding) {
|
|
41
|
+
const origin = (0, import_canonicalize.canonicalAgentOrigin)(binding.origin);
|
|
42
|
+
if (origin !== binding.origin || !binding.principalId || !binding.audit.approvedBy || !binding.audit.reason || !Number.isFinite(Date.parse(binding.audit.approvedAt)))
|
|
43
|
+
throw new TypeError("Explicit bindings require canonical origin and audit evidence");
|
|
44
|
+
const existing = this.bindings.get(origin);
|
|
45
|
+
if (existing && JSON.stringify(existing) !== JSON.stringify(binding)) throw new import_trust.IdentityAuthorizationError();
|
|
46
|
+
this.bindings.set(origin, structuredClone(binding));
|
|
47
|
+
}
|
|
48
|
+
async bindOpen(binding, maxPerOperator) {
|
|
49
|
+
const existing = this.bindings.get(binding.origin);
|
|
50
|
+
if (existing) throw new import_trust.IdentityAuthorizationError();
|
|
51
|
+
if (!binding.openAccess || !Number.isInteger(maxPerOperator) || maxPerOperator < 1 || [...this.bindings.values()].filter((b) => b.operator === binding.operator && b.openAccess).length >= maxPerOperator)
|
|
52
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
53
|
+
await this.bind(binding);
|
|
54
|
+
return structuredClone(binding);
|
|
55
|
+
}
|
|
56
|
+
async getApplication(origin) {
|
|
57
|
+
const value = this.applications.get((0, import_canonicalize.canonicalAgentOrigin)(origin));
|
|
58
|
+
return value && structuredClone(value);
|
|
59
|
+
}
|
|
60
|
+
async compareAndSetApplication(origin, expectedRevision, application) {
|
|
61
|
+
origin = (0, import_canonicalize.canonicalAgentOrigin)(origin);
|
|
62
|
+
if (this.applications.get(origin)?.revision !== expectedRevision || application.revision !== (expectedRevision ?? 0) + 1)
|
|
63
|
+
return false;
|
|
64
|
+
this.applications.set(origin, structuredClone(application));
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const BUYER_GATES = /* @__PURE__ */ new Set(["aao_verified", "storyboard", "sandbox", "experimental_feature"]);
|
|
69
|
+
const SELLER_GATES = /* @__PURE__ */ new Set(["agent_identity", "grant", "billing_entity", "contract", "credit_application"]);
|
|
70
|
+
async function evaluateOnboardingRequirements(requirements, direction, check) {
|
|
71
|
+
const relevant = direction === "seller" ? SELLER_GATES : BUYER_GATES;
|
|
72
|
+
const wrong = direction === "seller" ? BUYER_GATES : SELLER_GATES;
|
|
73
|
+
const unsatisfied = [];
|
|
74
|
+
for (const requirement of requirements) {
|
|
75
|
+
if (wrong.has(requirement.kind)) continue;
|
|
76
|
+
const wellFormed = requirement.kind !== "aao_verified" || !!requirement.role && !!requirement.verification_modes?.length && !!requirement.specialisms?.length && !!requirement.adcp_version;
|
|
77
|
+
const hasId = !["storyboard", "experimental_feature"].includes(requirement.kind) || !!requirement.id;
|
|
78
|
+
if (!relevant.has(requirement.kind) || !wellFormed || !hasId || !await check(requirement))
|
|
79
|
+
unsatisfied.push(requirement);
|
|
80
|
+
}
|
|
81
|
+
return { satisfied: !unsatisfied.length, unsatisfied };
|
|
82
|
+
}
|
|
83
|
+
function validateAgentOnboarding(posture, account, experimentalFeatures) {
|
|
84
|
+
if (!(0, import_trust.validateIdentity33Schema)("core/agent-onboarding", posture) || !experimentalFeatures.includes("account.agent_onboarding") || posture.sandbox && account.sandbox !== true || Object.keys(posture.billing ?? {}).some((k) => !account.supported_billing?.includes(k)))
|
|
85
|
+
throw new TypeError("Invalid experimental agent onboarding posture");
|
|
86
|
+
}
|
|
87
|
+
class OriginIdentityLifecycle {
|
|
88
|
+
constructor(options) {
|
|
89
|
+
this.options = options;
|
|
90
|
+
}
|
|
91
|
+
options;
|
|
92
|
+
/** Identity-established origins get no durable identifier. Reads never create. */
|
|
93
|
+
async getPrincipal(originUrl) {
|
|
94
|
+
const origin = (0, import_canonicalize.canonicalAgentOrigin)(originUrl);
|
|
95
|
+
const binding = await this.options.store.getBinding(origin);
|
|
96
|
+
const application = await this.options.store.getApplication(origin);
|
|
97
|
+
return {
|
|
98
|
+
...binding ? { binding } : {},
|
|
99
|
+
result: {
|
|
100
|
+
kind: binding ? "recognized" : "unconfigured",
|
|
101
|
+
...binding ? { principal_id: binding.principalId, principal_kind: binding.principalKind ?? "buyer_agent" } : {},
|
|
102
|
+
...application ? { relationship: application.relationship } : {}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async bindPrincipal(input) {
|
|
107
|
+
if (input.principalKind !== void 0 && !["buyer_agent", "operator"].includes(input.principalKind) || input.sharedOrigin || input.existingRfcPrincipal && input.migrationApproved !== true)
|
|
108
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
109
|
+
const origin = (0, import_canonicalize.canonicalAgentOrigin)(input.origin);
|
|
110
|
+
const legacy = await this.options.lookupLegacyPrincipals?.(origin);
|
|
111
|
+
if (legacy && (legacy.length > 1 || legacy.length === 1 && (legacy[0] !== input.principalId || !input.migrationApproved)))
|
|
112
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
113
|
+
const trust = await this.options.trust.match(origin, "adcp:buying");
|
|
114
|
+
const binding = {
|
|
115
|
+
origin,
|
|
116
|
+
operator: trust.operator,
|
|
117
|
+
principalId: input.principalId,
|
|
118
|
+
...input.principalKind && { principalKind: input.principalKind },
|
|
119
|
+
audit: {
|
|
120
|
+
approvedBy: input.approvedBy,
|
|
121
|
+
reason: input.reason,
|
|
122
|
+
approvedAt: new Date(this.now() * 1e3).toISOString(),
|
|
123
|
+
...input.migrationApproved ? { migrationApproved: true } : {}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
await this.options.store.bind(binding);
|
|
127
|
+
return binding;
|
|
128
|
+
}
|
|
129
|
+
/** Cryptographic verification does not call this. Authorization revalidates delisting. */
|
|
130
|
+
async authorizeBound(originUrl, access) {
|
|
131
|
+
const origin = (0, import_canonicalize.canonicalAgentOrigin)(originUrl);
|
|
132
|
+
const binding = await this.options.store.getBinding(origin);
|
|
133
|
+
if (!binding) throw new import_trust.IdentityAuthorizationError();
|
|
134
|
+
const trust = await this.options.trust.match(origin, "adcp:buying");
|
|
135
|
+
if (binding.operator !== trust.operator) throw new import_trust.IdentityAuthorizationError();
|
|
136
|
+
const relationship = (await this.options.store.getApplication(origin))?.relationship;
|
|
137
|
+
if (!access?.readOnly && relationship && (relationship.status !== "active" || relationship.expires_at && Date.parse(relationship.expires_at) <= this.now() * 1e3))
|
|
138
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
139
|
+
if (binding.openAccess && !access) throw new import_trust.IdentityAuthorizationError();
|
|
140
|
+
if (binding.openAccess && access && !access.readOnly && !access.identityConfiguration) {
|
|
141
|
+
if (access.sandbox) {
|
|
142
|
+
if (!binding.openAccess.sandbox) throw new import_trust.IdentityAuthorizationError();
|
|
143
|
+
} else {
|
|
144
|
+
if (!access.billing || access.billing === "agent" || !binding.openAccess.billing?.includes(access.billing))
|
|
145
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
146
|
+
const billedParty = access.billing === "operator" ? binding.operator : access.brandDomain && (0, import_etld.eTldPlusOne)(access.brandDomain);
|
|
147
|
+
if (!billedParty || !await this.options.hasBillingRelationship?.(billedParty, access.billing))
|
|
148
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return binding;
|
|
152
|
+
}
|
|
153
|
+
/** Called by explicit sync_principal only; allocates new identities, never migrates existing ones. */
|
|
154
|
+
async syncOpen(originUrl, options) {
|
|
155
|
+
const origin = (0, import_canonicalize.canonicalAgentOrigin)(originUrl);
|
|
156
|
+
if (![this.options.onboarding?.sandbox, ...Object.values(this.options.onboarding?.billing ?? {})].some(
|
|
157
|
+
(tier) => tier?.mode === "open"
|
|
158
|
+
))
|
|
159
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
160
|
+
if (await this.options.store.getBinding(origin)) throw new import_trust.IdentityAuthorizationError();
|
|
161
|
+
if (!this.options.lookupLegacyPrincipals || (await this.options.lookupLegacyPrincipals(origin)).length)
|
|
162
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
163
|
+
const relationship = (await this.options.store.getApplication(origin))?.relationship;
|
|
164
|
+
if (relationship && (["blocked", "suspended"].includes(relationship.status) || relationship.expires_at && Date.parse(relationship.expires_at) <= this.now() * 1e3))
|
|
165
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
166
|
+
const trust = await this.options.trust.match(origin, "adcp:buying");
|
|
167
|
+
const privateSuffix = (0, import_tldts.parse)(new URL(origin).hostname, { allowPrivateDomains: true }).isPrivate;
|
|
168
|
+
const access = {};
|
|
169
|
+
const eligible = async (tier) => tier?.mode === "open" && (await evaluateOnboardingRequirements(
|
|
170
|
+
tier.requirements ?? [],
|
|
171
|
+
"seller",
|
|
172
|
+
(req) => this.options.checkRequirement?.(origin, req) ?? Promise.resolve(false)
|
|
173
|
+
)).satisfied;
|
|
174
|
+
if (await eligible(this.options.onboarding?.sandbox)) access.sandbox = true;
|
|
175
|
+
if (!privateSuffix) {
|
|
176
|
+
for (const billing of ["operator", "advertiser"])
|
|
177
|
+
if (await eligible(this.options.onboarding?.billing?.[billing])) (access.billing ??= []).push(billing);
|
|
178
|
+
}
|
|
179
|
+
if (!access.sandbox && !access.billing?.length) throw new import_trust.IdentityAuthorizationError();
|
|
180
|
+
const binding = {
|
|
181
|
+
origin,
|
|
182
|
+
operator: trust.operator,
|
|
183
|
+
principalId: (0, import_crypto.randomUUID)(),
|
|
184
|
+
openAccess: access,
|
|
185
|
+
audit: {
|
|
186
|
+
approvedBy: "open-onboarding-policy",
|
|
187
|
+
reason: "new principal for declared open tiers",
|
|
188
|
+
approvedAt: new Date(this.now() * 1e3).toISOString()
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
if (options?.dryRun) return binding;
|
|
192
|
+
return this.options.store.bindOpen(binding, this.options.maxOpenPrincipalsPerOperator ?? 10);
|
|
193
|
+
}
|
|
194
|
+
async setRelationship(originUrl, relationship) {
|
|
195
|
+
if (!(0, import_trust.validateIdentity33Schema)("core/principal-relationship", relationship))
|
|
196
|
+
throw new TypeError("Invalid relationship");
|
|
197
|
+
const origin = (0, import_canonicalize.canonicalAgentOrigin)(originUrl);
|
|
198
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
199
|
+
const prior = await this.options.store.getApplication(origin);
|
|
200
|
+
if (prior && JSON.stringify(prior.relationship) === JSON.stringify(relationship)) {
|
|
201
|
+
await this.flushRelationshipNotifications(origin);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (await this.options.store.compareAndSetApplication(origin, prior?.revision, {
|
|
205
|
+
relationship: structuredClone(relationship),
|
|
206
|
+
revision: (prior?.revision ?? 0) + 1,
|
|
207
|
+
...prior?.relationship.expires_at === relationship.expires_at && prior?.expiryNotified ? { expiryNotified: prior.expiryNotified } : {},
|
|
208
|
+
pendingNotifications: [
|
|
209
|
+
...prior?.pendingNotifications ?? [],
|
|
210
|
+
{ id: (0, import_crypto.randomUUID)(), reason: "relationship_changed" }
|
|
211
|
+
]
|
|
212
|
+
})) {
|
|
213
|
+
await this.flushRelationshipNotifications(origin);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
throw new import_trust.IdentityAuthorizationError();
|
|
218
|
+
}
|
|
219
|
+
async notifyRelationshipExpiring(originUrl, leadSeconds) {
|
|
220
|
+
if (!Number.isFinite(leadSeconds) || leadSeconds < 0) throw new TypeError("Invalid expiry lead time");
|
|
221
|
+
const origin = (0, import_canonicalize.canonicalAgentOrigin)(originUrl);
|
|
222
|
+
await this.flushRelationshipNotifications(origin);
|
|
223
|
+
const prior = await this.options.store.getApplication(origin);
|
|
224
|
+
const expires = prior?.relationship.expires_at;
|
|
225
|
+
if (!prior || !expires || prior.expiryNotified === expires || Date.parse(expires) / 1e3 - this.now() > leadSeconds || Date.parse(expires) / 1e3 <= this.now())
|
|
226
|
+
return false;
|
|
227
|
+
if (!await this.options.store.compareAndSetApplication(origin, prior.revision, {
|
|
228
|
+
...prior,
|
|
229
|
+
revision: prior.revision + 1,
|
|
230
|
+
expiryNotified: expires,
|
|
231
|
+
pendingNotifications: [
|
|
232
|
+
...prior.pendingNotifications ?? [],
|
|
233
|
+
{ id: (0, import_crypto.randomUUID)(), reason: "relationship_expiring" }
|
|
234
|
+
]
|
|
235
|
+
}))
|
|
236
|
+
return false;
|
|
237
|
+
await this.flushRelationshipNotifications(origin);
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
async flushRelationshipNotifications(originUrl) {
|
|
241
|
+
if (!this.options.notify) return;
|
|
242
|
+
const origin = (0, import_canonicalize.canonicalAgentOrigin)(originUrl);
|
|
243
|
+
for (let attempt = 0; attempt < 100; attempt++) {
|
|
244
|
+
const prior = await this.options.store.getApplication(origin), notification = prior?.pendingNotifications?.[0];
|
|
245
|
+
if (!prior || !notification) return;
|
|
246
|
+
await this.options.notify(origin, notification.reason, notification.id);
|
|
247
|
+
await this.options.store.compareAndSetApplication(origin, prior.revision, {
|
|
248
|
+
...prior,
|
|
249
|
+
revision: prior.revision + 1,
|
|
250
|
+
pendingNotifications: prior.pendingNotifications.slice(1)
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async assertLegacyAllowed(agentUrl) {
|
|
255
|
+
if (await this.options.store.getBinding((0, import_canonicalize.canonicalAgentOrigin)(agentUrl))) throw new import_trust.IdentityAuthorizationError();
|
|
256
|
+
}
|
|
257
|
+
now() {
|
|
258
|
+
return (this.options.now ?? (() => Date.now() / 1e3))();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
262
|
+
0 && (module.exports = {
|
|
263
|
+
InMemoryOriginIdentityStore,
|
|
264
|
+
OriginIdentityLifecycle,
|
|
265
|
+
evaluateOnboardingRequirements,
|
|
266
|
+
validateAgentOnboarding
|
|
267
|
+
});
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import { parse as parseTld } from "tldts";
|
|
3
|
+
import { canonicalAgentOrigin } from "../signing/agent-resolver/canonicalize.mjs";
|
|
4
|
+
import { eTldPlusOne } from "../signing/agent-resolver/etld.mjs";
|
|
5
|
+
import { IdentityAuthorizationError, validateIdentity33Schema } from "./trust.mjs";
|
|
6
|
+
class InMemoryOriginIdentityStore {
|
|
7
|
+
durability = "process-local";
|
|
8
|
+
bindings = /* @__PURE__ */ new Map();
|
|
9
|
+
applications = /* @__PURE__ */ new Map();
|
|
10
|
+
async getBinding(origin) {
|
|
11
|
+
const value = this.bindings.get(canonicalAgentOrigin(origin));
|
|
12
|
+
return value && structuredClone(value);
|
|
13
|
+
}
|
|
14
|
+
async bind(binding) {
|
|
15
|
+
const origin = canonicalAgentOrigin(binding.origin);
|
|
16
|
+
if (origin !== binding.origin || !binding.principalId || !binding.audit.approvedBy || !binding.audit.reason || !Number.isFinite(Date.parse(binding.audit.approvedAt)))
|
|
17
|
+
throw new TypeError("Explicit bindings require canonical origin and audit evidence");
|
|
18
|
+
const existing = this.bindings.get(origin);
|
|
19
|
+
if (existing && JSON.stringify(existing) !== JSON.stringify(binding)) throw new IdentityAuthorizationError();
|
|
20
|
+
this.bindings.set(origin, structuredClone(binding));
|
|
21
|
+
}
|
|
22
|
+
async bindOpen(binding, maxPerOperator) {
|
|
23
|
+
const existing = this.bindings.get(binding.origin);
|
|
24
|
+
if (existing) throw new IdentityAuthorizationError();
|
|
25
|
+
if (!binding.openAccess || !Number.isInteger(maxPerOperator) || maxPerOperator < 1 || [...this.bindings.values()].filter((b) => b.operator === binding.operator && b.openAccess).length >= maxPerOperator)
|
|
26
|
+
throw new IdentityAuthorizationError();
|
|
27
|
+
await this.bind(binding);
|
|
28
|
+
return structuredClone(binding);
|
|
29
|
+
}
|
|
30
|
+
async getApplication(origin) {
|
|
31
|
+
const value = this.applications.get(canonicalAgentOrigin(origin));
|
|
32
|
+
return value && structuredClone(value);
|
|
33
|
+
}
|
|
34
|
+
async compareAndSetApplication(origin, expectedRevision, application) {
|
|
35
|
+
origin = canonicalAgentOrigin(origin);
|
|
36
|
+
if (this.applications.get(origin)?.revision !== expectedRevision || application.revision !== (expectedRevision ?? 0) + 1)
|
|
37
|
+
return false;
|
|
38
|
+
this.applications.set(origin, structuredClone(application));
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const BUYER_GATES = /* @__PURE__ */ new Set(["aao_verified", "storyboard", "sandbox", "experimental_feature"]);
|
|
43
|
+
const SELLER_GATES = /* @__PURE__ */ new Set(["agent_identity", "grant", "billing_entity", "contract", "credit_application"]);
|
|
44
|
+
async function evaluateOnboardingRequirements(requirements, direction, check) {
|
|
45
|
+
const relevant = direction === "seller" ? SELLER_GATES : BUYER_GATES;
|
|
46
|
+
const wrong = direction === "seller" ? BUYER_GATES : SELLER_GATES;
|
|
47
|
+
const unsatisfied = [];
|
|
48
|
+
for (const requirement of requirements) {
|
|
49
|
+
if (wrong.has(requirement.kind)) continue;
|
|
50
|
+
const wellFormed = requirement.kind !== "aao_verified" || !!requirement.role && !!requirement.verification_modes?.length && !!requirement.specialisms?.length && !!requirement.adcp_version;
|
|
51
|
+
const hasId = !["storyboard", "experimental_feature"].includes(requirement.kind) || !!requirement.id;
|
|
52
|
+
if (!relevant.has(requirement.kind) || !wellFormed || !hasId || !await check(requirement))
|
|
53
|
+
unsatisfied.push(requirement);
|
|
54
|
+
}
|
|
55
|
+
return { satisfied: !unsatisfied.length, unsatisfied };
|
|
56
|
+
}
|
|
57
|
+
function validateAgentOnboarding(posture, account, experimentalFeatures) {
|
|
58
|
+
if (!validateIdentity33Schema("core/agent-onboarding", posture) || !experimentalFeatures.includes("account.agent_onboarding") || posture.sandbox && account.sandbox !== true || Object.keys(posture.billing ?? {}).some((k) => !account.supported_billing?.includes(k)))
|
|
59
|
+
throw new TypeError("Invalid experimental agent onboarding posture");
|
|
60
|
+
}
|
|
61
|
+
class OriginIdentityLifecycle {
|
|
62
|
+
constructor(options) {
|
|
63
|
+
this.options = options;
|
|
64
|
+
}
|
|
65
|
+
options;
|
|
66
|
+
/** Identity-established origins get no durable identifier. Reads never create. */
|
|
67
|
+
async getPrincipal(originUrl) {
|
|
68
|
+
const origin = canonicalAgentOrigin(originUrl);
|
|
69
|
+
const binding = await this.options.store.getBinding(origin);
|
|
70
|
+
const application = await this.options.store.getApplication(origin);
|
|
71
|
+
return {
|
|
72
|
+
...binding ? { binding } : {},
|
|
73
|
+
result: {
|
|
74
|
+
kind: binding ? "recognized" : "unconfigured",
|
|
75
|
+
...binding ? { principal_id: binding.principalId, principal_kind: binding.principalKind ?? "buyer_agent" } : {},
|
|
76
|
+
...application ? { relationship: application.relationship } : {}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async bindPrincipal(input) {
|
|
81
|
+
if (input.principalKind !== void 0 && !["buyer_agent", "operator"].includes(input.principalKind) || input.sharedOrigin || input.existingRfcPrincipal && input.migrationApproved !== true)
|
|
82
|
+
throw new IdentityAuthorizationError();
|
|
83
|
+
const origin = canonicalAgentOrigin(input.origin);
|
|
84
|
+
const legacy = await this.options.lookupLegacyPrincipals?.(origin);
|
|
85
|
+
if (legacy && (legacy.length > 1 || legacy.length === 1 && (legacy[0] !== input.principalId || !input.migrationApproved)))
|
|
86
|
+
throw new IdentityAuthorizationError();
|
|
87
|
+
const trust = await this.options.trust.match(origin, "adcp:buying");
|
|
88
|
+
const binding = {
|
|
89
|
+
origin,
|
|
90
|
+
operator: trust.operator,
|
|
91
|
+
principalId: input.principalId,
|
|
92
|
+
...input.principalKind && { principalKind: input.principalKind },
|
|
93
|
+
audit: {
|
|
94
|
+
approvedBy: input.approvedBy,
|
|
95
|
+
reason: input.reason,
|
|
96
|
+
approvedAt: new Date(this.now() * 1e3).toISOString(),
|
|
97
|
+
...input.migrationApproved ? { migrationApproved: true } : {}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
await this.options.store.bind(binding);
|
|
101
|
+
return binding;
|
|
102
|
+
}
|
|
103
|
+
/** Cryptographic verification does not call this. Authorization revalidates delisting. */
|
|
104
|
+
async authorizeBound(originUrl, access) {
|
|
105
|
+
const origin = canonicalAgentOrigin(originUrl);
|
|
106
|
+
const binding = await this.options.store.getBinding(origin);
|
|
107
|
+
if (!binding) throw new IdentityAuthorizationError();
|
|
108
|
+
const trust = await this.options.trust.match(origin, "adcp:buying");
|
|
109
|
+
if (binding.operator !== trust.operator) throw new IdentityAuthorizationError();
|
|
110
|
+
const relationship = (await this.options.store.getApplication(origin))?.relationship;
|
|
111
|
+
if (!access?.readOnly && relationship && (relationship.status !== "active" || relationship.expires_at && Date.parse(relationship.expires_at) <= this.now() * 1e3))
|
|
112
|
+
throw new IdentityAuthorizationError();
|
|
113
|
+
if (binding.openAccess && !access) throw new IdentityAuthorizationError();
|
|
114
|
+
if (binding.openAccess && access && !access.readOnly && !access.identityConfiguration) {
|
|
115
|
+
if (access.sandbox) {
|
|
116
|
+
if (!binding.openAccess.sandbox) throw new IdentityAuthorizationError();
|
|
117
|
+
} else {
|
|
118
|
+
if (!access.billing || access.billing === "agent" || !binding.openAccess.billing?.includes(access.billing))
|
|
119
|
+
throw new IdentityAuthorizationError();
|
|
120
|
+
const billedParty = access.billing === "operator" ? binding.operator : access.brandDomain && eTldPlusOne(access.brandDomain);
|
|
121
|
+
if (!billedParty || !await this.options.hasBillingRelationship?.(billedParty, access.billing))
|
|
122
|
+
throw new IdentityAuthorizationError();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return binding;
|
|
126
|
+
}
|
|
127
|
+
/** Called by explicit sync_principal only; allocates new identities, never migrates existing ones. */
|
|
128
|
+
async syncOpen(originUrl, options) {
|
|
129
|
+
const origin = canonicalAgentOrigin(originUrl);
|
|
130
|
+
if (![this.options.onboarding?.sandbox, ...Object.values(this.options.onboarding?.billing ?? {})].some(
|
|
131
|
+
(tier) => tier?.mode === "open"
|
|
132
|
+
))
|
|
133
|
+
throw new IdentityAuthorizationError();
|
|
134
|
+
if (await this.options.store.getBinding(origin)) throw new IdentityAuthorizationError();
|
|
135
|
+
if (!this.options.lookupLegacyPrincipals || (await this.options.lookupLegacyPrincipals(origin)).length)
|
|
136
|
+
throw new IdentityAuthorizationError();
|
|
137
|
+
const relationship = (await this.options.store.getApplication(origin))?.relationship;
|
|
138
|
+
if (relationship && (["blocked", "suspended"].includes(relationship.status) || relationship.expires_at && Date.parse(relationship.expires_at) <= this.now() * 1e3))
|
|
139
|
+
throw new IdentityAuthorizationError();
|
|
140
|
+
const trust = await this.options.trust.match(origin, "adcp:buying");
|
|
141
|
+
const privateSuffix = parseTld(new URL(origin).hostname, { allowPrivateDomains: true }).isPrivate;
|
|
142
|
+
const access = {};
|
|
143
|
+
const eligible = async (tier) => tier?.mode === "open" && (await evaluateOnboardingRequirements(
|
|
144
|
+
tier.requirements ?? [],
|
|
145
|
+
"seller",
|
|
146
|
+
(req) => this.options.checkRequirement?.(origin, req) ?? Promise.resolve(false)
|
|
147
|
+
)).satisfied;
|
|
148
|
+
if (await eligible(this.options.onboarding?.sandbox)) access.sandbox = true;
|
|
149
|
+
if (!privateSuffix) {
|
|
150
|
+
for (const billing of ["operator", "advertiser"])
|
|
151
|
+
if (await eligible(this.options.onboarding?.billing?.[billing])) (access.billing ??= []).push(billing);
|
|
152
|
+
}
|
|
153
|
+
if (!access.sandbox && !access.billing?.length) throw new IdentityAuthorizationError();
|
|
154
|
+
const binding = {
|
|
155
|
+
origin,
|
|
156
|
+
operator: trust.operator,
|
|
157
|
+
principalId: randomUUID(),
|
|
158
|
+
openAccess: access,
|
|
159
|
+
audit: {
|
|
160
|
+
approvedBy: "open-onboarding-policy",
|
|
161
|
+
reason: "new principal for declared open tiers",
|
|
162
|
+
approvedAt: new Date(this.now() * 1e3).toISOString()
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
if (options?.dryRun) return binding;
|
|
166
|
+
return this.options.store.bindOpen(binding, this.options.maxOpenPrincipalsPerOperator ?? 10);
|
|
167
|
+
}
|
|
168
|
+
async setRelationship(originUrl, relationship) {
|
|
169
|
+
if (!validateIdentity33Schema("core/principal-relationship", relationship))
|
|
170
|
+
throw new TypeError("Invalid relationship");
|
|
171
|
+
const origin = canonicalAgentOrigin(originUrl);
|
|
172
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
173
|
+
const prior = await this.options.store.getApplication(origin);
|
|
174
|
+
if (prior && JSON.stringify(prior.relationship) === JSON.stringify(relationship)) {
|
|
175
|
+
await this.flushRelationshipNotifications(origin);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (await this.options.store.compareAndSetApplication(origin, prior?.revision, {
|
|
179
|
+
relationship: structuredClone(relationship),
|
|
180
|
+
revision: (prior?.revision ?? 0) + 1,
|
|
181
|
+
...prior?.relationship.expires_at === relationship.expires_at && prior?.expiryNotified ? { expiryNotified: prior.expiryNotified } : {},
|
|
182
|
+
pendingNotifications: [
|
|
183
|
+
...prior?.pendingNotifications ?? [],
|
|
184
|
+
{ id: randomUUID(), reason: "relationship_changed" }
|
|
185
|
+
]
|
|
186
|
+
})) {
|
|
187
|
+
await this.flushRelationshipNotifications(origin);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
throw new IdentityAuthorizationError();
|
|
192
|
+
}
|
|
193
|
+
async notifyRelationshipExpiring(originUrl, leadSeconds) {
|
|
194
|
+
if (!Number.isFinite(leadSeconds) || leadSeconds < 0) throw new TypeError("Invalid expiry lead time");
|
|
195
|
+
const origin = canonicalAgentOrigin(originUrl);
|
|
196
|
+
await this.flushRelationshipNotifications(origin);
|
|
197
|
+
const prior = await this.options.store.getApplication(origin);
|
|
198
|
+
const expires = prior?.relationship.expires_at;
|
|
199
|
+
if (!prior || !expires || prior.expiryNotified === expires || Date.parse(expires) / 1e3 - this.now() > leadSeconds || Date.parse(expires) / 1e3 <= this.now())
|
|
200
|
+
return false;
|
|
201
|
+
if (!await this.options.store.compareAndSetApplication(origin, prior.revision, {
|
|
202
|
+
...prior,
|
|
203
|
+
revision: prior.revision + 1,
|
|
204
|
+
expiryNotified: expires,
|
|
205
|
+
pendingNotifications: [
|
|
206
|
+
...prior.pendingNotifications ?? [],
|
|
207
|
+
{ id: randomUUID(), reason: "relationship_expiring" }
|
|
208
|
+
]
|
|
209
|
+
}))
|
|
210
|
+
return false;
|
|
211
|
+
await this.flushRelationshipNotifications(origin);
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
async flushRelationshipNotifications(originUrl) {
|
|
215
|
+
if (!this.options.notify) return;
|
|
216
|
+
const origin = canonicalAgentOrigin(originUrl);
|
|
217
|
+
for (let attempt = 0; attempt < 100; attempt++) {
|
|
218
|
+
const prior = await this.options.store.getApplication(origin), notification = prior?.pendingNotifications?.[0];
|
|
219
|
+
if (!prior || !notification) return;
|
|
220
|
+
await this.options.notify(origin, notification.reason, notification.id);
|
|
221
|
+
await this.options.store.compareAndSetApplication(origin, prior.revision, {
|
|
222
|
+
...prior,
|
|
223
|
+
revision: prior.revision + 1,
|
|
224
|
+
pendingNotifications: prior.pendingNotifications.slice(1)
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async assertLegacyAllowed(agentUrl) {
|
|
229
|
+
if (await this.options.store.getBinding(canonicalAgentOrigin(agentUrl))) throw new IdentityAuthorizationError();
|
|
230
|
+
}
|
|
231
|
+
now() {
|
|
232
|
+
return (this.options.now ?? (() => Date.now() / 1e3))();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
export {
|
|
236
|
+
InMemoryOriginIdentityStore,
|
|
237
|
+
OriginIdentityLifecycle,
|
|
238
|
+
evaluateOnboardingRequirements,
|
|
239
|
+
validateAgentOnboarding
|
|
240
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type JWK } from 'jose';
|
|
2
|
+
import { type SsrfFetchOptions } from '../net/index.mjs';
|
|
3
|
+
import type { RevocationDetail } from './types.mjs';
|
|
4
|
+
export interface OriginRevocationSnapshot {
|
|
5
|
+
issuer: string;
|
|
6
|
+
updated: string;
|
|
7
|
+
next_update: string;
|
|
8
|
+
revoked_kids: string[];
|
|
9
|
+
revoked_jtis?: string[];
|
|
10
|
+
revocation_details?: Record<string, RevocationDetail>;
|
|
11
|
+
}
|
|
12
|
+
export interface MonotonicOriginRevocationStore {
|
|
13
|
+
/** Merge atomically and persist forever. Never replace with a new snapshot. */
|
|
14
|
+
merge(origin: string, snapshot: OriginRevocationSnapshot): Promise<void>;
|
|
15
|
+
get(origin: string, keyid: string): Promise<RevocationDetail | undefined>;
|
|
16
|
+
}
|
|
17
|
+
export declare class InMemoryOriginRevocationStore implements MonotonicOriginRevocationStore {
|
|
18
|
+
private readonly limits;
|
|
19
|
+
readonly durability: "process-local";
|
|
20
|
+
private readonly revoked;
|
|
21
|
+
constructor(limits?: {
|
|
22
|
+
perOrigin: number;
|
|
23
|
+
total: number;
|
|
24
|
+
});
|
|
25
|
+
merge(origin: string, snapshot: OriginRevocationSnapshot): Promise<void>;
|
|
26
|
+
get(origin: string, keyid: string): Promise<RevocationDetail | undefined>;
|
|
27
|
+
}
|
|
28
|
+
export declare class OriginRevocationResolver {
|
|
29
|
+
private readonly options;
|
|
30
|
+
private readonly freshness;
|
|
31
|
+
private readonly updated;
|
|
32
|
+
private readonly graceUntil;
|
|
33
|
+
private readonly pending;
|
|
34
|
+
private readonly failures;
|
|
35
|
+
private readonly persistenceFailures;
|
|
36
|
+
constructor(options: {
|
|
37
|
+
directory: import('../signing/web-bot-auth.mjs').SignatureDirectoryResolver;
|
|
38
|
+
store: MonotonicOriginRevocationStore;
|
|
39
|
+
pollingIntervalSeconds?: number;
|
|
40
|
+
now?: () => number;
|
|
41
|
+
fetchOptions?: Pick<SsrfFetchOptions, 'lookup' | 'trustedFetchFn'>;
|
|
42
|
+
maxOrigins?: number;
|
|
43
|
+
});
|
|
44
|
+
isRevoked(originUrl: string, keyid: string): Promise<boolean>;
|
|
45
|
+
private readStored;
|
|
46
|
+
private refresh;
|
|
47
|
+
private now;
|
|
48
|
+
}
|
|
49
|
+
/** Publish a signed list even when there are no revoked keys; refresh before next_update. */
|
|
50
|
+
export declare function createSignedOriginRevocationList(snapshot: OriginRevocationSnapshot, privateKey: JWK): Promise<string>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type JWK } from 'jose';
|
|
2
|
+
import { type SsrfFetchOptions } from '../net';
|
|
3
|
+
import type { RevocationDetail } from './types';
|
|
4
|
+
export interface OriginRevocationSnapshot {
|
|
5
|
+
issuer: string;
|
|
6
|
+
updated: string;
|
|
7
|
+
next_update: string;
|
|
8
|
+
revoked_kids: string[];
|
|
9
|
+
revoked_jtis?: string[];
|
|
10
|
+
revocation_details?: Record<string, RevocationDetail>;
|
|
11
|
+
}
|
|
12
|
+
export interface MonotonicOriginRevocationStore {
|
|
13
|
+
/** Merge atomically and persist forever. Never replace with a new snapshot. */
|
|
14
|
+
merge(origin: string, snapshot: OriginRevocationSnapshot): Promise<void>;
|
|
15
|
+
get(origin: string, keyid: string): Promise<RevocationDetail | undefined>;
|
|
16
|
+
}
|
|
17
|
+
export declare class InMemoryOriginRevocationStore implements MonotonicOriginRevocationStore {
|
|
18
|
+
private readonly limits;
|
|
19
|
+
readonly durability: "process-local";
|
|
20
|
+
private readonly revoked;
|
|
21
|
+
constructor(limits?: {
|
|
22
|
+
perOrigin: number;
|
|
23
|
+
total: number;
|
|
24
|
+
});
|
|
25
|
+
merge(origin: string, snapshot: OriginRevocationSnapshot): Promise<void>;
|
|
26
|
+
get(origin: string, keyid: string): Promise<RevocationDetail | undefined>;
|
|
27
|
+
}
|
|
28
|
+
export declare class OriginRevocationResolver {
|
|
29
|
+
private readonly options;
|
|
30
|
+
private readonly freshness;
|
|
31
|
+
private readonly updated;
|
|
32
|
+
private readonly graceUntil;
|
|
33
|
+
private readonly pending;
|
|
34
|
+
private readonly failures;
|
|
35
|
+
private readonly persistenceFailures;
|
|
36
|
+
constructor(options: {
|
|
37
|
+
directory: import('../signing/web-bot-auth').SignatureDirectoryResolver;
|
|
38
|
+
store: MonotonicOriginRevocationStore;
|
|
39
|
+
pollingIntervalSeconds?: number;
|
|
40
|
+
now?: () => number;
|
|
41
|
+
fetchOptions?: Pick<SsrfFetchOptions, 'lookup' | 'trustedFetchFn'>;
|
|
42
|
+
maxOrigins?: number;
|
|
43
|
+
});
|
|
44
|
+
isRevoked(originUrl: string, keyid: string): Promise<boolean>;
|
|
45
|
+
private readStored;
|
|
46
|
+
private refresh;
|
|
47
|
+
private now;
|
|
48
|
+
}
|
|
49
|
+
/** Publish a signed list even when there are no revoked keys; refresh before next_update. */
|
|
50
|
+
export declare function createSignedOriginRevocationList(snapshot: OriginRevocationSnapshot, privateKey: JWK): Promise<string>;
|