@adcp/sdk 16.0.0-beta.7 → 16.0.0-beta.8
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 +17 -0
- package/dist/lib/conformance/index.d.mts +2 -0
- package/dist/lib/conformance/index.d.ts +2 -0
- package/dist/lib/conformance/index.js +3 -0
- package/dist/lib/conformance/index.mjs +2 -0
- package/dist/lib/conformance/property-lists.d.mts +14 -0
- package/dist/lib/conformance/property-lists.d.ts +14 -0
- package/dist/lib/conformance/property-lists.js +45 -0
- package/dist/lib/conformance/property-lists.mjs +21 -0
- package/dist/lib/conformance/runConformance.js +20 -1
- package/dist/lib/conformance/runConformance.mjs +20 -1
- package/dist/lib/conformance/types.d.mts +3 -0
- package/dist/lib/conformance/types.d.ts +3 -0
- package/dist/lib/core/SingleAgentClient.d.mts +13 -3
- package/dist/lib/core/SingleAgentClient.d.ts +13 -3
- package/dist/lib/core/SingleAgentClient.js +109 -21
- package/dist/lib/core/SingleAgentClient.mjs +112 -22
- package/dist/lib/identifiers.d.mts +53 -0
- package/dist/lib/identifiers.d.ts +53 -0
- package/dist/lib/identifiers.js +212 -0
- package/dist/lib/identifiers.mjs +163 -0
- package/dist/lib/index.d.mts +3 -1
- package/dist/lib/index.d.ts +3 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.mjs +1 -0
- package/dist/lib/media-buy/index.d.mts +1 -1
- package/dist/lib/media-buy/index.d.ts +1 -1
- package/dist/lib/media-buy/property-policy.d.mts +15 -1
- package/dist/lib/media-buy/property-policy.d.ts +15 -1
- package/dist/lib/media-buy/property-policy.js +135 -3
- package/dist/lib/media-buy/property-policy.mjs +134 -3
- package/dist/lib/registry/index.d.mts +12 -0
- package/dist/lib/registry/index.d.ts +12 -0
- package/dist/lib/registry/index.js +159 -5
- package/dist/lib/registry/index.mjs +156 -4
- package/dist/lib/registry/types.d.mts +23 -0
- package/dist/lib/registry/types.d.ts +23 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/decisioning/specialisms/lists.d.mts +4 -4
- package/dist/lib/server/decisioning/specialisms/lists.d.ts +4 -4
- package/dist/lib/server/index.d.mts +3 -0
- package/dist/lib/server/index.d.ts +3 -0
- package/dist/lib/server/index.js +8 -1
- package/dist/lib/server/index.mjs +4 -0
- package/dist/lib/server/property-lists.d.mts +36 -0
- package/dist/lib/server/property-lists.d.ts +36 -0
- package/dist/lib/server/property-lists.js +154 -0
- package/dist/lib/server/property-lists.mjs +129 -0
- package/dist/lib/server/targeting-helpers.d.mts +2 -0
- package/dist/lib/server/targeting-helpers.d.ts +2 -0
- package/dist/lib/server/targeting-helpers.js +28 -1
- package/dist/lib/server/targeting-helpers.mjs +18 -1
- package/dist/lib/signing/parser.js +2 -2
- package/dist/lib/signing/parser.mjs +2 -2
- package/dist/lib/signing/server.d.mts +1 -1
- package/dist/lib/signing/server.d.ts +1 -1
- package/dist/lib/signing/server.mjs +5 -1
- package/dist/lib/signing/webhook-verifier.d.mts +11 -0
- package/dist/lib/signing/webhook-verifier.d.ts +11 -0
- package/dist/lib/signing/webhook-verifier.js +11 -3
- package/dist/lib/signing/webhook-verifier.mjs +11 -3
- package/dist/lib/supply-path/verify.js +12 -2
- package/dist/lib/supply-path/verify.mjs +2 -2
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/PROPERTY-LISTS.md +264 -0
- package/docs/guides/SIGNING-GUIDE.md +25 -0
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,154 @@
|
|
|
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 property_lists_exports = {};
|
|
20
|
+
__export(property_lists_exports, {
|
|
21
|
+
registerPropertyListTool: () => registerPropertyListTool,
|
|
22
|
+
sendPropertyListChanged: () => sendPropertyListChanged
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(property_lists_exports);
|
|
25
|
+
var import_zod = require("zod");
|
|
26
|
+
var import_schemas = require('../types/schemas.generated.js');
|
|
27
|
+
var import_wire_shape = require('./ctx-metadata/wire-shape.js');
|
|
28
|
+
function registerPropertyListTool(server, options) {
|
|
29
|
+
return server.registerTool(
|
|
30
|
+
"get_property_list",
|
|
31
|
+
{
|
|
32
|
+
description: "Retrieve an authorized property list and a page of resolved identifiers.",
|
|
33
|
+
inputSchema: import_schemas.GetPropertyListRequestSchema,
|
|
34
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true }
|
|
35
|
+
},
|
|
36
|
+
async (request, extra) => {
|
|
37
|
+
const denied = () => toolError("PERMISSION_DENIED", "Property list access denied.", request.context);
|
|
38
|
+
const headers = extra.requestInfo?.headers ?? {};
|
|
39
|
+
for (const name of ["authorization", "x-adcp-auth"]) {
|
|
40
|
+
const values = Object.entries(headers).filter(([key]) => key.toLowerCase() === name);
|
|
41
|
+
if (values.length > 1 || values.length === 1 && typeof values[0][1] !== "string") return denied();
|
|
42
|
+
}
|
|
43
|
+
const readHeader = (name) => {
|
|
44
|
+
const values = Object.entries(headers).filter(([key]) => key.toLowerCase() === name);
|
|
45
|
+
if (values.length !== 1 || typeof values[0][1] !== "string") return void 0;
|
|
46
|
+
return values[0][1];
|
|
47
|
+
};
|
|
48
|
+
const authorization = readHeader("authorization");
|
|
49
|
+
const bearer = authorization?.match(/^Bearer ([^\s]+)$/i)?.[1];
|
|
50
|
+
const adcpToken = readHeader("x-adcp-auth");
|
|
51
|
+
const authenticatedToken = extra.authInfo?.token;
|
|
52
|
+
const tokens = [bearer, adcpToken, authenticatedToken].filter((token) => token !== void 0);
|
|
53
|
+
if (!tokens.length || tokens.some((token) => !token || token !== tokens[0]) || authorization !== void 0 && !bearer)
|
|
54
|
+
return denied();
|
|
55
|
+
let principal;
|
|
56
|
+
try {
|
|
57
|
+
principal = await options.verifyToken({ listId: request.list_id, token: tokens[0] });
|
|
58
|
+
} catch {
|
|
59
|
+
return denied();
|
|
60
|
+
}
|
|
61
|
+
if (principal === null || principal === false || principal === void 0) return denied();
|
|
62
|
+
try {
|
|
63
|
+
const page = await options.loadPage(request, principal);
|
|
64
|
+
if (page.list.list_id !== request.list_id) throw new Error("Invalid list identity");
|
|
65
|
+
if (request.resolve !== false && !Array.isArray(page.identifiers))
|
|
66
|
+
throw new Error("Missing resolved identifiers");
|
|
67
|
+
const limit = request.pagination?.max_results ?? 1e3;
|
|
68
|
+
if (request.resolve !== false && (page.identifiers?.length ?? 0) > limit) throw new Error("Invalid page size");
|
|
69
|
+
if (page.pagination?.has_more && !page.pagination.cursor) throw new Error("Missing continuation cursor");
|
|
70
|
+
if (!page.pagination?.has_more && page.pagination?.cursor) throw new Error("Unexpected continuation cursor");
|
|
71
|
+
const payload = import_schemas.GetPropertyListResponseSchema.parse({
|
|
72
|
+
list: Object.fromEntries(
|
|
73
|
+
[
|
|
74
|
+
"list_id",
|
|
75
|
+
"name",
|
|
76
|
+
"description",
|
|
77
|
+
"account",
|
|
78
|
+
"base_properties",
|
|
79
|
+
"filters",
|
|
80
|
+
"brand",
|
|
81
|
+
"webhook_url",
|
|
82
|
+
"cache_duration_hours",
|
|
83
|
+
"created_at",
|
|
84
|
+
"updated_at",
|
|
85
|
+
"property_count",
|
|
86
|
+
"pricing_options"
|
|
87
|
+
].filter((key) => Object.hasOwn(page.list, key)).map((key) => [key, page.list[key]])
|
|
88
|
+
),
|
|
89
|
+
...page.identifiers !== void 0 ? { identifiers: page.identifiers.map((identifier) => ({ type: identifier.type, value: identifier.value })) } : {},
|
|
90
|
+
...page.pagination !== void 0 ? {
|
|
91
|
+
pagination: {
|
|
92
|
+
has_more: page.pagination.has_more,
|
|
93
|
+
cursor: page.pagination.cursor,
|
|
94
|
+
total_count: page.pagination.total_count
|
|
95
|
+
}
|
|
96
|
+
} : {},
|
|
97
|
+
...page.resolved_at !== void 0 ? { resolved_at: page.resolved_at } : {},
|
|
98
|
+
...page.cache_valid_until !== void 0 ? { cache_valid_until: page.cache_valid_until } : {},
|
|
99
|
+
...page.coverage_gaps !== void 0 ? { coverage_gaps: page.coverage_gaps } : {},
|
|
100
|
+
status: "completed",
|
|
101
|
+
...request.resolve === false ? { identifiers: void 0, pagination: void 0 } : {},
|
|
102
|
+
...request.context ? { context: request.context } : {}
|
|
103
|
+
});
|
|
104
|
+
(0, import_wire_shape.stripCtxMetadata)({ property_list: payload.list });
|
|
105
|
+
return { content: [{ type: "text", text: JSON.stringify(payload) }], structuredContent: payload };
|
|
106
|
+
} catch {
|
|
107
|
+
return toolError("INTERNAL_ERROR", "Property list could not be loaded.", request.context);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
function toolError(code, message, context) {
|
|
113
|
+
const payload = { status: "failed", errors: [{ code, message }], ...context !== void 0 ? { context } : {} };
|
|
114
|
+
return {
|
|
115
|
+
isError: true,
|
|
116
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
117
|
+
structuredContent: payload
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function sendPropertyListChanged(emitter, options) {
|
|
121
|
+
const { notification, ...delivery } = options;
|
|
122
|
+
const dateTime = import_zod.z.string().datetime({ offset: true });
|
|
123
|
+
if (!notification.list_id || !dateTime.safeParse(notification.resolved_at).success || notification.cache_valid_until !== void 0 && !dateTime.safeParse(notification.cache_valid_until).success) {
|
|
124
|
+
throw new TypeError("Property-list notifications require a list_id and valid timestamps");
|
|
125
|
+
}
|
|
126
|
+
const summary = notification.change_summary === void 0 ? void 0 : Object.fromEntries(
|
|
127
|
+
["properties_added", "properties_removed", "total_properties"].filter(
|
|
128
|
+
(key) => Object.hasOwn(notification.change_summary, key) && notification.change_summary[key] !== void 0
|
|
129
|
+
).map((key) => [key, notification.change_summary[key]])
|
|
130
|
+
);
|
|
131
|
+
for (const count of Object.values(summary ?? {})) {
|
|
132
|
+
if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0)
|
|
133
|
+
throw new TypeError("Property-list change counts must be nonnegative integers");
|
|
134
|
+
}
|
|
135
|
+
return emitter.emit({
|
|
136
|
+
...delivery,
|
|
137
|
+
authentication: null,
|
|
138
|
+
signingProfile: "adcp/webhook-signing/v1",
|
|
139
|
+
payload: {
|
|
140
|
+
event: "property_list_changed",
|
|
141
|
+
list_id: notification.list_id,
|
|
142
|
+
resolved_at: notification.resolved_at,
|
|
143
|
+
...notification.list_name !== void 0 ? { list_name: notification.list_name } : {},
|
|
144
|
+
...notification.cache_valid_until !== void 0 ? { cache_valid_until: notification.cache_valid_until } : {},
|
|
145
|
+
...summary !== void 0 ? { change_summary: summary } : {},
|
|
146
|
+
signature: "rfc9421"
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
151
|
+
0 && (module.exports = {
|
|
152
|
+
registerPropertyListTool,
|
|
153
|
+
sendPropertyListChanged
|
|
154
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { GetPropertyListRequestSchema, GetPropertyListResponseSchema } from "../types/schemas.generated.mjs";
|
|
3
|
+
import { stripCtxMetadata } from "./ctx-metadata/wire-shape.mjs";
|
|
4
|
+
function registerPropertyListTool(server, options) {
|
|
5
|
+
return server.registerTool(
|
|
6
|
+
"get_property_list",
|
|
7
|
+
{
|
|
8
|
+
description: "Retrieve an authorized property list and a page of resolved identifiers.",
|
|
9
|
+
inputSchema: GetPropertyListRequestSchema,
|
|
10
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true }
|
|
11
|
+
},
|
|
12
|
+
async (request, extra) => {
|
|
13
|
+
const denied = () => toolError("PERMISSION_DENIED", "Property list access denied.", request.context);
|
|
14
|
+
const headers = extra.requestInfo?.headers ?? {};
|
|
15
|
+
for (const name of ["authorization", "x-adcp-auth"]) {
|
|
16
|
+
const values = Object.entries(headers).filter(([key]) => key.toLowerCase() === name);
|
|
17
|
+
if (values.length > 1 || values.length === 1 && typeof values[0][1] !== "string") return denied();
|
|
18
|
+
}
|
|
19
|
+
const readHeader = (name) => {
|
|
20
|
+
const values = Object.entries(headers).filter(([key]) => key.toLowerCase() === name);
|
|
21
|
+
if (values.length !== 1 || typeof values[0][1] !== "string") return void 0;
|
|
22
|
+
return values[0][1];
|
|
23
|
+
};
|
|
24
|
+
const authorization = readHeader("authorization");
|
|
25
|
+
const bearer = authorization?.match(/^Bearer ([^\s]+)$/i)?.[1];
|
|
26
|
+
const adcpToken = readHeader("x-adcp-auth");
|
|
27
|
+
const authenticatedToken = extra.authInfo?.token;
|
|
28
|
+
const tokens = [bearer, adcpToken, authenticatedToken].filter((token) => token !== void 0);
|
|
29
|
+
if (!tokens.length || tokens.some((token) => !token || token !== tokens[0]) || authorization !== void 0 && !bearer)
|
|
30
|
+
return denied();
|
|
31
|
+
let principal;
|
|
32
|
+
try {
|
|
33
|
+
principal = await options.verifyToken({ listId: request.list_id, token: tokens[0] });
|
|
34
|
+
} catch {
|
|
35
|
+
return denied();
|
|
36
|
+
}
|
|
37
|
+
if (principal === null || principal === false || principal === void 0) return denied();
|
|
38
|
+
try {
|
|
39
|
+
const page = await options.loadPage(request, principal);
|
|
40
|
+
if (page.list.list_id !== request.list_id) throw new Error("Invalid list identity");
|
|
41
|
+
if (request.resolve !== false && !Array.isArray(page.identifiers))
|
|
42
|
+
throw new Error("Missing resolved identifiers");
|
|
43
|
+
const limit = request.pagination?.max_results ?? 1e3;
|
|
44
|
+
if (request.resolve !== false && (page.identifiers?.length ?? 0) > limit) throw new Error("Invalid page size");
|
|
45
|
+
if (page.pagination?.has_more && !page.pagination.cursor) throw new Error("Missing continuation cursor");
|
|
46
|
+
if (!page.pagination?.has_more && page.pagination?.cursor) throw new Error("Unexpected continuation cursor");
|
|
47
|
+
const payload = GetPropertyListResponseSchema.parse({
|
|
48
|
+
list: Object.fromEntries(
|
|
49
|
+
[
|
|
50
|
+
"list_id",
|
|
51
|
+
"name",
|
|
52
|
+
"description",
|
|
53
|
+
"account",
|
|
54
|
+
"base_properties",
|
|
55
|
+
"filters",
|
|
56
|
+
"brand",
|
|
57
|
+
"webhook_url",
|
|
58
|
+
"cache_duration_hours",
|
|
59
|
+
"created_at",
|
|
60
|
+
"updated_at",
|
|
61
|
+
"property_count",
|
|
62
|
+
"pricing_options"
|
|
63
|
+
].filter((key) => Object.hasOwn(page.list, key)).map((key) => [key, page.list[key]])
|
|
64
|
+
),
|
|
65
|
+
...page.identifiers !== void 0 ? { identifiers: page.identifiers.map((identifier) => ({ type: identifier.type, value: identifier.value })) } : {},
|
|
66
|
+
...page.pagination !== void 0 ? {
|
|
67
|
+
pagination: {
|
|
68
|
+
has_more: page.pagination.has_more,
|
|
69
|
+
cursor: page.pagination.cursor,
|
|
70
|
+
total_count: page.pagination.total_count
|
|
71
|
+
}
|
|
72
|
+
} : {},
|
|
73
|
+
...page.resolved_at !== void 0 ? { resolved_at: page.resolved_at } : {},
|
|
74
|
+
...page.cache_valid_until !== void 0 ? { cache_valid_until: page.cache_valid_until } : {},
|
|
75
|
+
...page.coverage_gaps !== void 0 ? { coverage_gaps: page.coverage_gaps } : {},
|
|
76
|
+
status: "completed",
|
|
77
|
+
...request.resolve === false ? { identifiers: void 0, pagination: void 0 } : {},
|
|
78
|
+
...request.context ? { context: request.context } : {}
|
|
79
|
+
});
|
|
80
|
+
stripCtxMetadata({ property_list: payload.list });
|
|
81
|
+
return { content: [{ type: "text", text: JSON.stringify(payload) }], structuredContent: payload };
|
|
82
|
+
} catch {
|
|
83
|
+
return toolError("INTERNAL_ERROR", "Property list could not be loaded.", request.context);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
function toolError(code, message, context) {
|
|
89
|
+
const payload = { status: "failed", errors: [{ code, message }], ...context !== void 0 ? { context } : {} };
|
|
90
|
+
return {
|
|
91
|
+
isError: true,
|
|
92
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
93
|
+
structuredContent: payload
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function sendPropertyListChanged(emitter, options) {
|
|
97
|
+
const { notification, ...delivery } = options;
|
|
98
|
+
const dateTime = z.string().datetime({ offset: true });
|
|
99
|
+
if (!notification.list_id || !dateTime.safeParse(notification.resolved_at).success || notification.cache_valid_until !== void 0 && !dateTime.safeParse(notification.cache_valid_until).success) {
|
|
100
|
+
throw new TypeError("Property-list notifications require a list_id and valid timestamps");
|
|
101
|
+
}
|
|
102
|
+
const summary = notification.change_summary === void 0 ? void 0 : Object.fromEntries(
|
|
103
|
+
["properties_added", "properties_removed", "total_properties"].filter(
|
|
104
|
+
(key) => Object.hasOwn(notification.change_summary, key) && notification.change_summary[key] !== void 0
|
|
105
|
+
).map((key) => [key, notification.change_summary[key]])
|
|
106
|
+
);
|
|
107
|
+
for (const count of Object.values(summary ?? {})) {
|
|
108
|
+
if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0)
|
|
109
|
+
throw new TypeError("Property-list change counts must be nonnegative integers");
|
|
110
|
+
}
|
|
111
|
+
return emitter.emit({
|
|
112
|
+
...delivery,
|
|
113
|
+
authentication: null,
|
|
114
|
+
signingProfile: "adcp/webhook-signing/v1",
|
|
115
|
+
payload: {
|
|
116
|
+
event: "property_list_changed",
|
|
117
|
+
list_id: notification.list_id,
|
|
118
|
+
resolved_at: notification.resolved_at,
|
|
119
|
+
...notification.list_name !== void 0 ? { list_name: notification.list_name } : {},
|
|
120
|
+
...notification.cache_valid_until !== void 0 ? { cache_valid_until: notification.cache_valid_until } : {},
|
|
121
|
+
...summary !== void 0 ? { change_summary: summary } : {},
|
|
122
|
+
signature: "rfc9421"
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
export {
|
|
127
|
+
registerPropertyListTool,
|
|
128
|
+
sendPropertyListChanged
|
|
129
|
+
};
|
|
@@ -56,6 +56,8 @@ export declare const defaultResolvedListCache: ResolvedListCache;
|
|
|
56
56
|
export declare function clearDefaultResolvedListCache(): void;
|
|
57
57
|
export type ResolveListCallTool = (agentUrl: string, toolName: 'get_property_list' | 'get_collection_list', args: Record<string, unknown>, authToken?: string) => Promise<unknown>;
|
|
58
58
|
export interface ResolveListOptions {
|
|
59
|
+
/** Require schema-valid property-list pages with identifiers when resolving. Used for certification. */
|
|
60
|
+
strictResponseValidation?: boolean;
|
|
59
61
|
/** Maximum page size when calling get_property_list / get_collection_list. Defaults to 1000. */
|
|
60
62
|
pageSize?: number;
|
|
61
63
|
/** Maximum number of pages to walk before treating pagination as unsafe. Defaults to 100. */
|
|
@@ -56,6 +56,8 @@ export declare const defaultResolvedListCache: ResolvedListCache;
|
|
|
56
56
|
export declare function clearDefaultResolvedListCache(): void;
|
|
57
57
|
export type ResolveListCallTool = (agentUrl: string, toolName: 'get_property_list' | 'get_collection_list', args: Record<string, unknown>, authToken?: string) => Promise<unknown>;
|
|
58
58
|
export interface ResolveListOptions {
|
|
59
|
+
/** Require schema-valid property-list pages with identifiers when resolving. Used for certification. */
|
|
60
|
+
strictResponseValidation?: boolean;
|
|
59
61
|
/** Maximum page size when calling get_property_list / get_collection_list. Defaults to 1000. */
|
|
60
62
|
pageSize?: number;
|
|
61
63
|
/** Maximum number of pages to walk before treating pagination as unsafe. Defaults to 100. */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var targeting_helpers_exports = {};
|
|
20
30
|
__export(targeting_helpers_exports, {
|
|
@@ -75,7 +85,7 @@ async function resolvePropertyList(ref, options = {}) {
|
|
|
75
85
|
const cache = cacheForOptions(options);
|
|
76
86
|
const nowMs = nowMsForOptions(options);
|
|
77
87
|
const cacheKey = resolvedListCacheKey("property", structurallyNormalizedRef, options);
|
|
78
|
-
const cached = cacheKey ? cache?.get(cacheKey, nowMs) : void 0;
|
|
88
|
+
const cached = cacheKey && !options.strictResponseValidation ? cache?.get(cacheKey, nowMs) : void 0;
|
|
79
89
|
if (cached) return cached;
|
|
80
90
|
const normalizedRef = options.callTool ? structurallyNormalizedRef : await normalizePropertyListReference(structurallyNormalizedRef, { resolveDns: false });
|
|
81
91
|
const result = await fetchResolvedPropertyList(normalizedRef, options);
|
|
@@ -89,6 +99,7 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
89
99
|
let cacheValidUntil;
|
|
90
100
|
let missingCacheValidUntil = false;
|
|
91
101
|
let cursor;
|
|
102
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
92
103
|
for (let pageIndex = 0; pageIndex < maxPagesForOptions(options); pageIndex += 1) {
|
|
93
104
|
const args = buildResolveListArgs(ref.list_id, pageSizeForOptions(options), cursor);
|
|
94
105
|
const raw = await callTool(ref.agent_url, "get_property_list", args, ref.auth_token);
|
|
@@ -96,6 +107,20 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
96
107
|
throw new Error("property_list_invalid_response");
|
|
97
108
|
}
|
|
98
109
|
const response = raw;
|
|
110
|
+
if (response.status !== void 0 && response.status !== "completed" || raw.errors !== void 0 && (!Array.isArray(raw.errors) || raw.errors.some((error) => !error || typeof error !== "object" || error.severity !== "warning")) || raw.adcp_error !== void 0 || !Array.isArray(response.identifiers)) {
|
|
111
|
+
throw new Error("property_list_invalid_response");
|
|
112
|
+
}
|
|
113
|
+
if (options.strictResponseValidation) {
|
|
114
|
+
const { GetPropertyListResponseSchema } = await import("../types/schemas.generated.js");
|
|
115
|
+
if (!GetPropertyListResponseSchema.safeParse(raw).success || response.status !== "completed" || response.identifiers.length > pageSizeForOptions(options)) {
|
|
116
|
+
throw new Error("property_list_invalid_response");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!response.list || response.list.list_id !== ref.list_id || response.identifiers !== void 0 && (!Array.isArray(response.identifiers) || response.identifiers.some(
|
|
120
|
+
(identifier) => !identifier || typeof identifier !== "object" || typeof identifier.type !== "string" || typeof identifier.value !== "string"
|
|
121
|
+
))) {
|
|
122
|
+
throw new Error("property_list_invalid_response");
|
|
123
|
+
}
|
|
99
124
|
listId = response.list.list_id;
|
|
100
125
|
identifiers.push(...response.identifiers ?? []);
|
|
101
126
|
if (typeof response.cache_valid_until === "string") {
|
|
@@ -118,6 +143,8 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
118
143
|
if (!pagination.cursor) {
|
|
119
144
|
throw new Error("property_list_invalid_pagination");
|
|
120
145
|
}
|
|
146
|
+
if (seenCursors.has(pagination.cursor)) throw new Error("property_list_invalid_pagination");
|
|
147
|
+
seenCursors.add(pagination.cursor);
|
|
121
148
|
cursor = pagination.cursor;
|
|
122
149
|
}
|
|
123
150
|
throw new Error("property_list_pagination_limit_exceeded");
|
|
@@ -44,7 +44,7 @@ async function resolvePropertyList(ref, options = {}) {
|
|
|
44
44
|
const cache = cacheForOptions(options);
|
|
45
45
|
const nowMs = nowMsForOptions(options);
|
|
46
46
|
const cacheKey = resolvedListCacheKey("property", structurallyNormalizedRef, options);
|
|
47
|
-
const cached = cacheKey ? cache?.get(cacheKey, nowMs) : void 0;
|
|
47
|
+
const cached = cacheKey && !options.strictResponseValidation ? cache?.get(cacheKey, nowMs) : void 0;
|
|
48
48
|
if (cached) return cached;
|
|
49
49
|
const normalizedRef = options.callTool ? structurallyNormalizedRef : await normalizePropertyListReference(structurallyNormalizedRef, { resolveDns: false });
|
|
50
50
|
const result = await fetchResolvedPropertyList(normalizedRef, options);
|
|
@@ -58,6 +58,7 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
58
58
|
let cacheValidUntil;
|
|
59
59
|
let missingCacheValidUntil = false;
|
|
60
60
|
let cursor;
|
|
61
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
61
62
|
for (let pageIndex = 0; pageIndex < maxPagesForOptions(options); pageIndex += 1) {
|
|
62
63
|
const args = buildResolveListArgs(ref.list_id, pageSizeForOptions(options), cursor);
|
|
63
64
|
const raw = await callTool(ref.agent_url, "get_property_list", args, ref.auth_token);
|
|
@@ -65,6 +66,20 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
65
66
|
throw new Error("property_list_invalid_response");
|
|
66
67
|
}
|
|
67
68
|
const response = raw;
|
|
69
|
+
if (response.status !== void 0 && response.status !== "completed" || raw.errors !== void 0 && (!Array.isArray(raw.errors) || raw.errors.some((error) => !error || typeof error !== "object" || error.severity !== "warning")) || raw.adcp_error !== void 0 || !Array.isArray(response.identifiers)) {
|
|
70
|
+
throw new Error("property_list_invalid_response");
|
|
71
|
+
}
|
|
72
|
+
if (options.strictResponseValidation) {
|
|
73
|
+
const { GetPropertyListResponseSchema } = await import("../types/schemas.generated.mjs");
|
|
74
|
+
if (!GetPropertyListResponseSchema.safeParse(raw).success || response.status !== "completed" || response.identifiers.length > pageSizeForOptions(options)) {
|
|
75
|
+
throw new Error("property_list_invalid_response");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!response.list || response.list.list_id !== ref.list_id || response.identifiers !== void 0 && (!Array.isArray(response.identifiers) || response.identifiers.some(
|
|
79
|
+
(identifier) => !identifier || typeof identifier !== "object" || typeof identifier.type !== "string" || typeof identifier.value !== "string"
|
|
80
|
+
))) {
|
|
81
|
+
throw new Error("property_list_invalid_response");
|
|
82
|
+
}
|
|
68
83
|
listId = response.list.list_id;
|
|
69
84
|
identifiers.push(...response.identifiers ?? []);
|
|
70
85
|
if (typeof response.cache_valid_until === "string") {
|
|
@@ -87,6 +102,8 @@ async function fetchResolvedPropertyList(ref, options) {
|
|
|
87
102
|
if (!pagination.cursor) {
|
|
88
103
|
throw new Error("property_list_invalid_pagination");
|
|
89
104
|
}
|
|
105
|
+
if (seenCursors.has(pagination.cursor)) throw new Error("property_list_invalid_pagination");
|
|
106
|
+
seenCursors.add(pagination.cursor);
|
|
90
107
|
cursor = pagination.cursor;
|
|
91
108
|
}
|
|
92
109
|
throw new Error("property_list_pagination_limit_exceeded");
|
|
@@ -86,10 +86,10 @@ function parseSignature(headerValue, expectedLabel, encoding = "legacy-base64url
|
|
|
86
86
|
if (!rawBytes) malformed(`Signature header does not contain a byte sequence for label "${expectedLabel}"`);
|
|
87
87
|
if (encoding === "rfc8941-base64") {
|
|
88
88
|
if (!(0, import_content_digest.isPaddedStandardBase64)(rawBytes)) {
|
|
89
|
-
malformed("Signature value must use padded standard Base64 for
|
|
89
|
+
malformed("Signature value must use padded standard Base64 for the selected signing profile");
|
|
90
90
|
}
|
|
91
91
|
} else if (!/^[A-Za-z0-9_-]+$/.test(rawBytes)) {
|
|
92
|
-
malformed("Signature value must use unpadded Base64URL for
|
|
92
|
+
malformed("Signature value must use unpadded Base64URL for the selected signing profile");
|
|
93
93
|
}
|
|
94
94
|
let dict;
|
|
95
95
|
try {
|
|
@@ -60,10 +60,10 @@ function parseSignature(headerValue, expectedLabel, encoding = "legacy-base64url
|
|
|
60
60
|
if (!rawBytes) malformed(`Signature header does not contain a byte sequence for label "${expectedLabel}"`);
|
|
61
61
|
if (encoding === "rfc8941-base64") {
|
|
62
62
|
if (!isPaddedStandardBase64(rawBytes)) {
|
|
63
|
-
malformed("Signature value must use padded standard Base64 for
|
|
63
|
+
malformed("Signature value must use padded standard Base64 for the selected signing profile");
|
|
64
64
|
}
|
|
65
65
|
} else if (!/^[A-Za-z0-9_-]+$/.test(rawBytes)) {
|
|
66
|
-
malformed("Signature value must use unpadded Base64URL for
|
|
66
|
+
malformed("Signature value must use unpadded Base64URL for the selected signing profile");
|
|
67
67
|
}
|
|
68
68
|
let dict;
|
|
69
69
|
try {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export type { SsrfDnsLookup } from '../net/index.mjs';
|
|
12
12
|
export { buildResponseSignatureBase, buildSignatureBase, canonicalAuthority, canonicalMethod, canonicalTargetUri, formatSignatureParams, getHeaderValue, type RequestLike, type RequestCanonicalizationProfile, type ResponseLike, type SignatureParams, } from './canonicalize.mjs';
|
|
13
|
-
export { computeContentDigest, contentDigestMatches, parseContentDigest } from './content-digest.mjs';
|
|
13
|
+
export { computeContentDigest, contentDigestMatches, parseContentDigest, type SfBinaryEncoding, } from './content-digest.mjs';
|
|
14
14
|
export { requestContextFromExpress, requestContextFromFetch, requestContextFromLambda, type ExpressRequestLike, type FetchRequestLike, type LambdaRequestEvent, type RequestContextFromExpressOptions, type RequestContextFromLambdaOptions, } from './request-context.mjs';
|
|
15
15
|
export { jwkToPublicKey, verifySignature, verifySignatureAsync } from './crypto.mjs';
|
|
16
16
|
export { RequestSignatureError, RequestSigningErrorCodeMetadata, type RequestSignatureErrorCode, ResponseSignatureError, type ResponseSignatureErrorCode, WebhookSignatureError, type WebhookSignatureErrorCode, } from './errors.mjs';
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
export type { SsrfDnsLookup } from '../net';
|
|
12
12
|
export { buildResponseSignatureBase, buildSignatureBase, canonicalAuthority, canonicalMethod, canonicalTargetUri, formatSignatureParams, getHeaderValue, type RequestLike, type RequestCanonicalizationProfile, type ResponseLike, type SignatureParams, } from './canonicalize';
|
|
13
|
-
export { computeContentDigest, contentDigestMatches, parseContentDigest } from './content-digest';
|
|
13
|
+
export { computeContentDigest, contentDigestMatches, parseContentDigest, type SfBinaryEncoding, } from './content-digest';
|
|
14
14
|
export { requestContextFromExpress, requestContextFromFetch, requestContextFromLambda, type ExpressRequestLike, type FetchRequestLike, type LambdaRequestEvent, type RequestContextFromExpressOptions, type RequestContextFromLambdaOptions, } from './request-context';
|
|
15
15
|
export { jwkToPublicKey, verifySignature, verifySignatureAsync } from './crypto';
|
|
16
16
|
export { RequestSignatureError, RequestSigningErrorCodeMetadata, type RequestSignatureErrorCode, ResponseSignatureError, type ResponseSignatureErrorCode, WebhookSignatureError, type WebhookSignatureErrorCode, } from './errors';
|
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
formatSignatureParams,
|
|
8
8
|
getHeaderValue
|
|
9
9
|
} from "./canonicalize.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
computeContentDigest,
|
|
12
|
+
contentDigestMatches,
|
|
13
|
+
parseContentDigest
|
|
14
|
+
} from "./content-digest.mjs";
|
|
11
15
|
import {
|
|
12
16
|
requestContextFromExpress,
|
|
13
17
|
requestContextFromFetch,
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* so failures can point at a specific spec clause. Numbers are 1-based to
|
|
23
23
|
* match the security doc.
|
|
24
24
|
*/
|
|
25
|
+
import { type SfBinaryEncoding } from './content-digest.mjs';
|
|
25
26
|
import type { JwksResolver } from './jwks.mjs';
|
|
26
27
|
import { type PublisherSigningKeyPin } from './publisher-pins.mjs';
|
|
27
28
|
import { type ReplayStore } from './replay.mjs';
|
|
@@ -43,6 +44,16 @@ export interface WebhookRequestLike {
|
|
|
43
44
|
export declare const WEBHOOK_MANDATORY_COMPONENTS: ReadonlyArray<string>;
|
|
44
45
|
export interface VerifyWebhookOptions {
|
|
45
46
|
jwks: JwksResolver;
|
|
47
|
+
/**
|
|
48
|
+
* Trusted receiver configuration for the Signature byte sequence.
|
|
49
|
+
* Defaults to `legacy-base64url`, as the AdCP webhook-v1 profile requires
|
|
50
|
+
* throughout 3.x. Set `rfc8941-base64` only for an explicitly configured
|
|
51
|
+
* peer emitting standard padded Base64 (for example, a generic RFC 9421
|
|
52
|
+
* request signer with the webhook tag). There is no encoding fallback.
|
|
53
|
+
* URL canonicalization remains AdCP 3.2 in either mode; Signature encoding
|
|
54
|
+
* does not identify a webhook's AdCP version.
|
|
55
|
+
*/
|
|
56
|
+
signatureEncoding?: SfBinaryEncoding;
|
|
46
57
|
/** Applicable publishers from the verifier's own media-buy record. */
|
|
47
58
|
publisherPins?: readonly PublisherSigningKeyPin[];
|
|
48
59
|
/** Log the underlying request_signature_* discovery cause locally. */
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* so failures can point at a specific spec clause. Numbers are 1-based to
|
|
23
23
|
* match the security doc.
|
|
24
24
|
*/
|
|
25
|
+
import { type SfBinaryEncoding } from './content-digest';
|
|
25
26
|
import type { JwksResolver } from './jwks';
|
|
26
27
|
import { type PublisherSigningKeyPin } from './publisher-pins';
|
|
27
28
|
import { type ReplayStore } from './replay';
|
|
@@ -43,6 +44,16 @@ export interface WebhookRequestLike {
|
|
|
43
44
|
export declare const WEBHOOK_MANDATORY_COMPONENTS: ReadonlyArray<string>;
|
|
44
45
|
export interface VerifyWebhookOptions {
|
|
45
46
|
jwks: JwksResolver;
|
|
47
|
+
/**
|
|
48
|
+
* Trusted receiver configuration for the Signature byte sequence.
|
|
49
|
+
* Defaults to `legacy-base64url`, as the AdCP webhook-v1 profile requires
|
|
50
|
+
* throughout 3.x. Set `rfc8941-base64` only for an explicitly configured
|
|
51
|
+
* peer emitting standard padded Base64 (for example, a generic RFC 9421
|
|
52
|
+
* request signer with the webhook tag). There is no encoding fallback.
|
|
53
|
+
* URL canonicalization remains AdCP 3.2 in either mode; Signature encoding
|
|
54
|
+
* does not identify a webhook's AdCP version.
|
|
55
|
+
*/
|
|
56
|
+
signatureEncoding?: SfBinaryEncoding;
|
|
46
57
|
/** Applicable publishers from the verifier's own media-buy record. */
|
|
47
58
|
publisherPins?: readonly PublisherSigningKeyPin[];
|
|
48
59
|
/** Log the underlying request_signature_* discovery cause locally. */
|
|
@@ -50,6 +50,7 @@ const WEBHOOK_MANDATORY_COMPONENTS = [
|
|
|
50
50
|
"content-digest"
|
|
51
51
|
];
|
|
52
52
|
async function verifyWebhookSignature(request, options) {
|
|
53
|
+
const signatureEncoding = resolveSignatureEncoding(options.signatureEncoding);
|
|
53
54
|
const currentTime = options.now ?? (() => Date.now() / 1e3);
|
|
54
55
|
const now = currentTime();
|
|
55
56
|
const requiredTag = options.requiredTag ?? WEBHOOK_SIGNING_TAG;
|
|
@@ -66,12 +67,12 @@ async function verifyWebhookSignature(request, options) {
|
|
|
66
67
|
let parsedSig;
|
|
67
68
|
try {
|
|
68
69
|
parsedInput = (0, import_parser.parseSignatureInput)(sigInputHeader);
|
|
69
|
-
parsedSig = (0, import_parser.parseSignature)(sigHeader, parsedInput.label);
|
|
70
|
+
parsedSig = (0, import_parser.parseSignature)(sigHeader, parsedInput.label, signatureEncoding);
|
|
70
71
|
} catch (err) {
|
|
71
72
|
throw new import_errors.WebhookSignatureError(
|
|
72
73
|
"webhook_signature_header_malformed",
|
|
73
74
|
1,
|
|
74
|
-
err instanceof Error ? err.message : String(err)
|
|
75
|
+
`${err instanceof Error ? err.message : String(err)} (webhook signatureEncoding="${signatureEncoding}").`
|
|
75
76
|
);
|
|
76
77
|
}
|
|
77
78
|
requireParams(parsedInput);
|
|
@@ -239,6 +240,12 @@ async function verifyWebhookSignature(request, options) {
|
|
|
239
240
|
verified_at: Math.floor(now)
|
|
240
241
|
};
|
|
241
242
|
}
|
|
243
|
+
function resolveSignatureEncoding(encoding = "legacy-base64url") {
|
|
244
|
+
if (encoding !== "legacy-base64url" && encoding !== "rfc8941-base64") {
|
|
245
|
+
throw new TypeError('signatureEncoding must be "legacy-base64url" or "rfc8941-base64".');
|
|
246
|
+
}
|
|
247
|
+
return encoding;
|
|
248
|
+
}
|
|
242
249
|
function assertDelegatedOperatorAuthorizationActive(validUntil, now) {
|
|
243
250
|
if (validUntil !== void 0 && (!Number.isFinite(validUntil) || now >= validUntil)) {
|
|
244
251
|
throw new import_errors.WebhookSignatureError(
|
|
@@ -345,9 +352,10 @@ function isWebhookLoopbackHost(hostname) {
|
|
|
345
352
|
return LOOPBACK_IPV4.test(normalized);
|
|
346
353
|
}
|
|
347
354
|
function createWebhookVerifier(options) {
|
|
355
|
+
const signatureEncoding = resolveSignatureEncoding(options.signatureEncoding);
|
|
348
356
|
const replayStore = options.replayStore ?? new import_replay.InMemoryReplayStore();
|
|
349
357
|
const revocationStore = options.revocationStore ?? new import_revocation.InMemoryRevocationStore();
|
|
350
|
-
return (request) => verifyWebhookSignature(request, { ...options, replayStore, revocationStore });
|
|
358
|
+
return (request) => verifyWebhookSignature(request, { ...options, signatureEncoding, replayStore, revocationStore });
|
|
351
359
|
}
|
|
352
360
|
// Annotate the CommonJS export names for ESM import in node:
|
|
353
361
|
0 && (module.exports = {
|
|
@@ -23,6 +23,7 @@ const WEBHOOK_MANDATORY_COMPONENTS = [
|
|
|
23
23
|
"content-digest"
|
|
24
24
|
];
|
|
25
25
|
async function verifyWebhookSignature(request, options) {
|
|
26
|
+
const signatureEncoding = resolveSignatureEncoding(options.signatureEncoding);
|
|
26
27
|
const currentTime = options.now ?? (() => Date.now() / 1e3);
|
|
27
28
|
const now = currentTime();
|
|
28
29
|
const requiredTag = options.requiredTag ?? WEBHOOK_SIGNING_TAG;
|
|
@@ -39,12 +40,12 @@ async function verifyWebhookSignature(request, options) {
|
|
|
39
40
|
let parsedSig;
|
|
40
41
|
try {
|
|
41
42
|
parsedInput = parseSignatureInput(sigInputHeader);
|
|
42
|
-
parsedSig = parseSignature(sigHeader, parsedInput.label);
|
|
43
|
+
parsedSig = parseSignature(sigHeader, parsedInput.label, signatureEncoding);
|
|
43
44
|
} catch (err) {
|
|
44
45
|
throw new WebhookSignatureError(
|
|
45
46
|
"webhook_signature_header_malformed",
|
|
46
47
|
1,
|
|
47
|
-
err instanceof Error ? err.message : String(err)
|
|
48
|
+
`${err instanceof Error ? err.message : String(err)} (webhook signatureEncoding="${signatureEncoding}").`
|
|
48
49
|
);
|
|
49
50
|
}
|
|
50
51
|
requireParams(parsedInput);
|
|
@@ -212,6 +213,12 @@ async function verifyWebhookSignature(request, options) {
|
|
|
212
213
|
verified_at: Math.floor(now)
|
|
213
214
|
};
|
|
214
215
|
}
|
|
216
|
+
function resolveSignatureEncoding(encoding = "legacy-base64url") {
|
|
217
|
+
if (encoding !== "legacy-base64url" && encoding !== "rfc8941-base64") {
|
|
218
|
+
throw new TypeError('signatureEncoding must be "legacy-base64url" or "rfc8941-base64".');
|
|
219
|
+
}
|
|
220
|
+
return encoding;
|
|
221
|
+
}
|
|
215
222
|
function assertDelegatedOperatorAuthorizationActive(validUntil, now) {
|
|
216
223
|
if (validUntil !== void 0 && (!Number.isFinite(validUntil) || now >= validUntil)) {
|
|
217
224
|
throw new WebhookSignatureError(
|
|
@@ -318,9 +325,10 @@ function isWebhookLoopbackHost(hostname) {
|
|
|
318
325
|
return LOOPBACK_IPV4.test(normalized);
|
|
319
326
|
}
|
|
320
327
|
function createWebhookVerifier(options) {
|
|
328
|
+
const signatureEncoding = resolveSignatureEncoding(options.signatureEncoding);
|
|
321
329
|
const replayStore = options.replayStore ?? new InMemoryReplayStore();
|
|
322
330
|
const revocationStore = options.revocationStore ?? new InMemoryRevocationStore();
|
|
323
|
-
return (request) => verifyWebhookSignature(request, { ...options, replayStore, revocationStore });
|
|
331
|
+
return (request) => verifyWebhookSignature(request, { ...options, signatureEncoding, replayStore, revocationStore });
|
|
324
332
|
}
|
|
325
333
|
export {
|
|
326
334
|
WEBHOOK_MANDATORY_COMPONENTS,
|