@adcp/sdk 16.0.0-beta.1 → 16.0.0-beta.3
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 +54 -0
- package/dist/lib/core/ConversationTypes.d.mts +8 -3
- package/dist/lib/core/ConversationTypes.d.ts +8 -3
- package/dist/lib/core/SingleAgentClient.d.mts +15 -4
- package/dist/lib/core/SingleAgentClient.d.ts +15 -4
- package/dist/lib/core/SingleAgentClient.js +29 -8
- package/dist/lib/core/SingleAgentClient.mjs +29 -8
- package/dist/lib/core/TaskExecutor.js +5 -1
- package/dist/lib/core/TaskExecutor.mjs +5 -1
- package/dist/lib/errors/index.d.mts +9 -4
- package/dist/lib/errors/index.d.ts +9 -4
- package/dist/lib/identity-3.3/generated-compat.d.mts +34 -0
- package/dist/lib/identity-3.3/generated-compat.d.ts +34 -0
- package/dist/lib/identity-3.3/generated-compat.js +16 -0
- package/dist/lib/identity-3.3/generated-compat.mjs +0 -0
- package/dist/lib/identity-3.3/index.d.mts +2 -2
- package/dist/lib/identity-3.3/index.d.ts +2 -2
- package/dist/lib/identity-3.3/index.js +4 -0
- package/dist/lib/identity-3.3/index.mjs +5 -1
- package/dist/lib/identity-3.3/lifecycle.d.mts +17 -5
- package/dist/lib/identity-3.3/lifecycle.d.ts +17 -5
- package/dist/lib/identity-3.3/lifecycle.js +32 -5
- package/dist/lib/identity-3.3/lifecycle.mjs +38 -6
- package/dist/lib/identity-3.3/revocation.d.mts +39 -3
- package/dist/lib/identity-3.3/revocation.d.ts +39 -3
- package/dist/lib/identity-3.3/revocation.js +88 -18
- package/dist/lib/identity-3.3/revocation.mjs +89 -19
- package/dist/lib/identity-3.3/server.d.mts +12 -0
- package/dist/lib/identity-3.3/server.d.ts +12 -0
- package/dist/lib/identity-3.3/server.js +103 -43
- package/dist/lib/identity-3.3/server.mjs +111 -45
- package/dist/lib/identity-3.3/trust.d.mts +62 -1
- package/dist/lib/identity-3.3/trust.d.ts +62 -1
- package/dist/lib/identity-3.3/trust.js +126 -21
- package/dist/lib/identity-3.3/trust.mjs +124 -21
- package/dist/lib/identity-3.3/types.d.mts +39 -11
- package/dist/lib/identity-3.3/types.d.ts +39 -11
- package/dist/lib/index.d.mts +3 -3
- package/dist/lib/index.d.ts +3 -3
- package/dist/lib/index.js +8 -0
- package/dist/lib/index.mjs +9 -1
- package/dist/lib/negotiation/types.d.mts +20 -39
- package/dist/lib/negotiation/types.d.ts +20 -39
- package/dist/lib/protocols/index.d.mts +61 -25
- package/dist/lib/protocols/index.d.ts +61 -25
- package/dist/lib/protocols/index.js +11 -6
- package/dist/lib/protocols/index.mjs +5 -2
- package/dist/lib/protocols/mcp-modern.js +1 -0
- package/dist/lib/protocols/mcp-modern.mjs +2 -1
- package/dist/lib/protocols/mcp.js +1 -0
- package/dist/lib/protocols/mcp.mjs +2 -1
- package/dist/lib/protocols/responseSizeLimit.d.mts +91 -5
- package/dist/lib/protocols/responseSizeLimit.d.ts +91 -5
- package/dist/lib/protocols/responseSizeLimit.js +195 -31
- package/dist/lib/protocols/responseSizeLimit.mjs +192 -31
- package/dist/lib/reporting/bigquery/index.js +8 -0
- package/dist/lib/reporting/bigquery/index.mjs +8 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/auth-signature.d.mts +6 -1
- package/dist/lib/server/auth-signature.d.ts +6 -1
- package/dist/lib/server/auth-signature.js +24 -13
- package/dist/lib/server/auth-signature.mjs +29 -13
- package/dist/lib/server/auth.d.mts +2 -2
- package/dist/lib/server/auth.d.ts +2 -2
- package/dist/lib/server/create-adcp-server.js +31 -10
- package/dist/lib/server/create-adcp-server.mjs +37 -11
- package/dist/lib/signing/crypto.d.mts +15 -0
- package/dist/lib/signing/crypto.d.ts +15 -0
- package/dist/lib/signing/crypto.js +83 -3
- package/dist/lib/signing/crypto.mjs +86 -3
- package/dist/lib/signing/fetch-async.js +1 -1
- package/dist/lib/signing/fetch-async.mjs +1 -1
- package/dist/lib/signing/fetch.js +1 -1
- package/dist/lib/signing/fetch.mjs +1 -1
- package/dist/lib/signing/middleware.js +9 -0
- package/dist/lib/signing/middleware.mjs +14 -0
- package/dist/lib/signing/parser.d.mts +8 -5
- package/dist/lib/signing/parser.d.ts +8 -5
- package/dist/lib/signing/parser.js +77 -61
- package/dist/lib/signing/parser.mjs +77 -61
- package/dist/lib/signing/revocation.js +3 -0
- package/dist/lib/signing/revocation.mjs +3 -0
- package/dist/lib/signing/server.d.mts +1 -1
- package/dist/lib/signing/server.d.ts +1 -1
- package/dist/lib/signing/server.js +2 -0
- package/dist/lib/signing/server.mjs +2 -1
- package/dist/lib/signing/signer.js +2 -8
- package/dist/lib/signing/signer.mjs +3 -9
- package/dist/lib/signing/testing.js +2 -6
- package/dist/lib/signing/testing.mjs +3 -7
- package/dist/lib/signing/verifier.js +3 -3
- package/dist/lib/signing/verifier.mjs +4 -4
- package/dist/lib/signing/web-bot-auth.d.mts +84 -10
- package/dist/lib/signing/web-bot-auth.d.ts +84 -10
- package/dist/lib/signing/web-bot-auth.js +278 -88
- package/dist/lib/signing/web-bot-auth.mjs +279 -94
- package/dist/lib/signing/webhook-verifier.js +3 -3
- package/dist/lib/signing/webhook-verifier.mjs +4 -4
- package/dist/lib/substitution/compile.js +2 -1
- package/dist/lib/substitution/compile.mjs +2 -1
- package/dist/lib/substitution/consent-macros.d.mts +4 -0
- package/dist/lib/substitution/consent-macros.d.ts +4 -0
- package/dist/lib/substitution/consent-macros.js +45 -0
- package/dist/lib/substitution/consent-macros.mjs +20 -0
- package/dist/lib/substitution/index.d.mts +1 -1
- package/dist/lib/substitution/index.d.ts +1 -1
- package/dist/lib/substitution/index.js +2 -0
- package/dist/lib/substitution/index.mjs +2 -1
- package/dist/lib/substitution/translate.d.mts +15 -2
- package/dist/lib/substitution/translate.d.ts +15 -2
- package/dist/lib/substitution/translate.js +148 -26
- package/dist/lib/substitution/translate.mjs +147 -26
- package/dist/lib/testing/client.js +2 -1
- package/dist/lib/testing/client.mjs +2 -1
- package/dist/lib/testing/scenarios/capabilities.js +1 -1
- package/dist/lib/testing/scenarios/capabilities.mjs +1 -1
- package/dist/lib/testing/storyboard/request-signing/builder.js +2 -5
- package/dist/lib/testing/storyboard/request-signing/builder.mjs +3 -6
- package/dist/lib/testing/storyboard/signer-grader/grader.js +2 -7
- package/dist/lib/testing/storyboard/signer-grader/grader.mjs +2 -7
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/types/enums.generated.d.mts +3 -0
- package/dist/lib/types/enums.generated.d.ts +3 -0
- package/dist/lib/types/enums.generated.js +9 -0
- package/dist/lib/types/enums.generated.mjs +6 -0
- package/dist/lib/v2/projection/catalog-snapshot.js +3 -1
- package/dist/lib/v2/projection/catalog-snapshot.mjs +3 -1
- package/dist/lib/v2/projection/creative-delivery.d.mts +31 -9
- package/dist/lib/v2/projection/creative-delivery.d.ts +31 -9
- 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/index.js +2 -0
- package/dist/lib/v2/projection/index.mjs +2 -0
- package/dist/lib/v2/projection/legacy-routes.d.mts +10 -0
- package/dist/lib/v2/projection/legacy-routes.d.ts +10 -0
- package/dist/lib/v2/projection/legacy-routes.js +7 -0
- package/dist/lib/v2/projection/legacy-routes.mjs +6 -0
- package/dist/lib/validation/schema-loader.js +25 -0
- package/dist/lib/validation/schema-loader.mjs +24 -0
- 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 +7 -2
- package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +3 -2
- package/docs/guides/REPORTING-LEDGER.md +15 -5
- package/docs/guides/REPORTING-OPERATIONS.md +17 -11
- package/docs/guides/UNIVERSAL-MACRO-COMPILATION.md +38 -0
- package/docs/guides/VALIDATE-YOUR-AGENT.md +12 -0
- package/docs/llms.txt +2 -2
- package/docs/migration-12-to-13.md +8 -0
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-agent-identity-3.3.md +150 -11
- package/package.json +4 -1
|
@@ -18,6 +18,9 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var responseSizeLimit_exports = {};
|
|
20
20
|
__export(responseSizeLimit_exports, {
|
|
21
|
+
DEFAULT_MAX_RESPONSE_BYTES: () => DEFAULT_MAX_RESPONSE_BYTES,
|
|
22
|
+
SSE_CUMULATIVE_BUDGET_MULTIPLIER: () => SSE_CUMULATIVE_BUDGET_MULTIPLIER,
|
|
23
|
+
responseSizeCapCacheKey: () => responseSizeCapCacheKey,
|
|
21
24
|
responseSizeLimitStorage: () => responseSizeLimitStorage,
|
|
22
25
|
withResponseSizeLimit: () => withResponseSizeLimit,
|
|
23
26
|
wrapFetchWithSizeLimit: () => wrapFetchWithSizeLimit
|
|
@@ -25,52 +28,116 @@ __export(responseSizeLimit_exports, {
|
|
|
25
28
|
module.exports = __toCommonJS(responseSizeLimit_exports);
|
|
26
29
|
var import_global_async_local_storage = require('../utils/global-async-local-storage.js');
|
|
27
30
|
var import_errors = require('../errors/index.js');
|
|
31
|
+
var import_transportDiagnostics = require('./transportDiagnostics.js');
|
|
32
|
+
const DEFAULT_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
33
|
+
const SSE_CUMULATIVE_BUDGET_MULTIPLIER = 2;
|
|
28
34
|
const responseSizeLimitStorage = (0, import_global_async_local_storage.globalAsyncLocalStorage)("responseSizeLimit");
|
|
35
|
+
function resolveResponseSizeCap(maxResponseBytes) {
|
|
36
|
+
if (maxResponseBytes === void 0) return DEFAULT_MAX_RESPONSE_BYTES;
|
|
37
|
+
if (maxResponseBytes === 0) return null;
|
|
38
|
+
if (!Number.isFinite(maxResponseBytes) || maxResponseBytes < 0) return DEFAULT_MAX_RESPONSE_BYTES;
|
|
39
|
+
return maxResponseBytes;
|
|
40
|
+
}
|
|
41
|
+
function newSlot(maxResponseBytes) {
|
|
42
|
+
const resolved = resolveResponseSizeCap(maxResponseBytes);
|
|
43
|
+
if (resolved === null) return { maxResponseBytes: null };
|
|
44
|
+
const enclosing = responseSizeLimitStorage.getStore();
|
|
45
|
+
const limit = sseBudgetFor(resolved);
|
|
46
|
+
return {
|
|
47
|
+
// Nesting narrows both numbers. `?? resolved` deliberately also covers an
|
|
48
|
+
// enclosing opt-out (`null`): an inner scope that asks for a cap is the
|
|
49
|
+
// more specific instruction, so it still gets one.
|
|
50
|
+
maxResponseBytes: Math.min(resolved, enclosing?.maxResponseBytes ?? resolved),
|
|
51
|
+
streamLimit: Math.min(limit, enclosing?.streamLimit ?? limit),
|
|
52
|
+
streamMeter: enclosing?.streamMeter ?? { consumed: 0 }
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function sseBudgetFor(maxResponseBytes) {
|
|
56
|
+
return Math.min(maxResponseBytes * SSE_CUMULATIVE_BUDGET_MULTIPLIER, Number.MAX_SAFE_INTEGER);
|
|
57
|
+
}
|
|
58
|
+
function responseSizeCapCacheKey() {
|
|
59
|
+
const slot = responseSizeLimitStorage.getStore();
|
|
60
|
+
const cap = slot ? slot.maxResponseBytes : DEFAULT_MAX_RESPONSE_BYTES;
|
|
61
|
+
return `max-response-bytes:${cap === null ? "off" : cap}`;
|
|
62
|
+
}
|
|
29
63
|
function withResponseSizeLimit(maxResponseBytes, fn) {
|
|
30
|
-
if (
|
|
64
|
+
if (maxResponseBytes === void 0 && responseSizeLimitStorage.getStore()) {
|
|
31
65
|
return fn();
|
|
32
66
|
}
|
|
33
|
-
|
|
67
|
+
const slot = newSlot(maxResponseBytes);
|
|
68
|
+
return responseSizeLimitStorage.run(slot, () => rethrowRecordedViolation(slot, fn));
|
|
69
|
+
}
|
|
70
|
+
async function rethrowRecordedViolation(slot, fn) {
|
|
71
|
+
try {
|
|
72
|
+
return await fn();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
const violation = slot.violation;
|
|
75
|
+
if (!violation || error instanceof import_errors.ResponseTooLargeError) throw error;
|
|
76
|
+
const surfaced = new import_errors.ResponseTooLargeError(
|
|
77
|
+
violation.limit,
|
|
78
|
+
violation.bytesRead,
|
|
79
|
+
violation.url,
|
|
80
|
+
violation.contentLengthHeader
|
|
81
|
+
);
|
|
82
|
+
Object.defineProperty(surfaced, "cause", { value: error, configurable: true });
|
|
83
|
+
throw surfaced;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function recordViolation(slot, error) {
|
|
87
|
+
if (slot && !slot.violation) slot.violation = error;
|
|
88
|
+
return error;
|
|
34
89
|
}
|
|
35
90
|
function urlOfInput(input) {
|
|
36
91
|
if (typeof input === "string") return input;
|
|
37
92
|
if (input instanceof URL) return input.toString();
|
|
38
93
|
return input.url;
|
|
39
94
|
}
|
|
40
|
-
function redactUrlForError(url) {
|
|
41
|
-
try {
|
|
42
|
-
const parsed = new URL(url);
|
|
43
|
-
parsed.search = "";
|
|
44
|
-
return parsed.toString();
|
|
45
|
-
} catch {
|
|
46
|
-
return url;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function withIdentityEncoding(init) {
|
|
50
|
-
const headers = new Headers(init?.headers);
|
|
51
|
-
if (!headers.has("accept-encoding")) {
|
|
52
|
-
headers.set("accept-encoding", "identity");
|
|
53
|
-
}
|
|
54
|
-
return { ...init ?? {}, headers };
|
|
55
|
-
}
|
|
56
95
|
function wrapFetchWithSizeLimit(upstream) {
|
|
57
96
|
const wrapped = async (input, init) => {
|
|
58
97
|
const slot = responseSizeLimitStorage.getStore();
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
98
|
+
const maxBytes = slot ? slot.maxResponseBytes : DEFAULT_MAX_RESPONSE_BYTES;
|
|
99
|
+
if (maxBytes === null) return upstream(input, init);
|
|
100
|
+
const response = await upstream(input, init);
|
|
101
|
+
if (NULL_BODY_STATUSES.has(response.status)) return response;
|
|
102
|
+
const skipDeclaredLength = methodOf(input, init) === "HEAD";
|
|
103
|
+
const url = (0, import_transportDiagnostics.sanitizeTransportUrl)(urlOfInput(input));
|
|
104
|
+
if (isEventStream(response)) {
|
|
105
|
+
const connectionScoped = methodOf(input, init) === "GET";
|
|
106
|
+
const { limit, meter } = streamBudgetFor(connectionScoped, slot, maxBytes);
|
|
107
|
+
return enforceEventStreamLimit(
|
|
108
|
+
response,
|
|
109
|
+
maxBytes,
|
|
110
|
+
limit,
|
|
111
|
+
meter,
|
|
112
|
+
url,
|
|
113
|
+
connectionScoped ? void 0 : slot,
|
|
114
|
+
skipDeclaredLength
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return enforceSizeLimit(response, maxBytes, url, slot, skipDeclaredLength);
|
|
62
118
|
};
|
|
63
119
|
return wrapped;
|
|
64
120
|
}
|
|
65
|
-
function
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
121
|
+
function streamBudgetFor(connectionScoped, slot, maxBytes) {
|
|
122
|
+
if (connectionScoped) return { limit: sseBudgetFor(maxBytes), meter: { consumed: 0 } };
|
|
123
|
+
return {
|
|
124
|
+
limit: slot?.streamLimit ?? sseBudgetFor(maxBytes),
|
|
125
|
+
meter: slot?.streamMeter ?? { consumed: 0 }
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function methodOf(input, init) {
|
|
129
|
+
const method = init?.method ?? (typeof Request !== "undefined" && input instanceof Request ? input.method : "GET");
|
|
130
|
+
return method.toUpperCase();
|
|
131
|
+
}
|
|
132
|
+
const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
|
|
133
|
+
function isEventStream(response) {
|
|
134
|
+
return response.headers.get("content-type")?.toLowerCase().startsWith("text/event-stream") === true;
|
|
135
|
+
}
|
|
136
|
+
function enforceSizeLimit(response, maxBytes, url, slot, skipDeclaredLength = false) {
|
|
137
|
+
const declared = skipDeclaredLength ? void 0 : parseContentLength(response.headers.get("content-length"));
|
|
70
138
|
if (declared !== void 0 && declared > maxBytes) {
|
|
71
|
-
response
|
|
72
|
-
|
|
73
|
-
throw new import_errors.ResponseTooLargeError(maxBytes, 0, url, declared);
|
|
139
|
+
cancelBody(response);
|
|
140
|
+
throw recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, 0, url, declared));
|
|
74
141
|
}
|
|
75
142
|
if (!response.body) return response;
|
|
76
143
|
let bytesRead = 0;
|
|
@@ -78,13 +145,107 @@ function enforceSizeLimit(response, maxBytes, url) {
|
|
|
78
145
|
transform(chunk, controller) {
|
|
79
146
|
bytesRead += chunk.byteLength;
|
|
80
147
|
if (bytesRead > maxBytes) {
|
|
81
|
-
controller.error(new import_errors.ResponseTooLargeError(maxBytes, bytesRead, url));
|
|
148
|
+
controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, bytesRead, url)));
|
|
82
149
|
return;
|
|
83
150
|
}
|
|
84
151
|
controller.enqueue(chunk);
|
|
85
152
|
}
|
|
86
153
|
});
|
|
87
|
-
return
|
|
154
|
+
return respondWith(response, response.body.pipeThrough(counter));
|
|
155
|
+
}
|
|
156
|
+
const CR = 13;
|
|
157
|
+
const LF = 10;
|
|
158
|
+
function enforceEventStreamLimit(response, maxBytes, streamLimit, meter, url, slot, skipDeclaredLength = false) {
|
|
159
|
+
const remaining = streamLimit - meter.consumed;
|
|
160
|
+
const declared = skipDeclaredLength ? void 0 : parseContentLength(response.headers.get("content-length"));
|
|
161
|
+
if (declared !== void 0 && declared > remaining) {
|
|
162
|
+
cancelBody(response);
|
|
163
|
+
throw recordViolation(slot, new import_errors.ResponseTooLargeError(streamLimit, meter.consumed, url, declared));
|
|
164
|
+
}
|
|
165
|
+
if (!response.body) return response;
|
|
166
|
+
let bytesInEvent = 0;
|
|
167
|
+
let lineEndings = 0;
|
|
168
|
+
let pendingCR = false;
|
|
169
|
+
let separatorTail = false;
|
|
170
|
+
let pendingReset = false;
|
|
171
|
+
const counter = new TransformStream({
|
|
172
|
+
transform(chunk, controller) {
|
|
173
|
+
meter.consumed += chunk.byteLength;
|
|
174
|
+
if (meter.consumed > streamLimit) {
|
|
175
|
+
controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(streamLimit, meter.consumed, url)));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (chunk.length === 0) {
|
|
179
|
+
controller.enqueue(chunk);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (chunk.indexOf(LF) === -1 && chunk.indexOf(CR) === -1) {
|
|
183
|
+
if (pendingReset) {
|
|
184
|
+
pendingReset = false;
|
|
185
|
+
separatorTail = false;
|
|
186
|
+
bytesInEvent = 0;
|
|
187
|
+
}
|
|
188
|
+
bytesInEvent += chunk.length;
|
|
189
|
+
lineEndings = 0;
|
|
190
|
+
pendingCR = false;
|
|
191
|
+
if (bytesInEvent > maxBytes) {
|
|
192
|
+
controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, bytesInEvent, url)));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
controller.enqueue(chunk);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
for (let i = 0; i < chunk.length; i += 1) {
|
|
199
|
+
const byte = chunk[i];
|
|
200
|
+
if (pendingReset) {
|
|
201
|
+
pendingReset = false;
|
|
202
|
+
if (separatorTail && byte === LF) {
|
|
203
|
+
separatorTail = false;
|
|
204
|
+
pendingCR = false;
|
|
205
|
+
bytesInEvent += 1;
|
|
206
|
+
if (bytesInEvent > maxBytes) {
|
|
207
|
+
controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, bytesInEvent, url)));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
bytesInEvent = 0;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
separatorTail = false;
|
|
214
|
+
bytesInEvent = 0;
|
|
215
|
+
}
|
|
216
|
+
bytesInEvent += 1;
|
|
217
|
+
if (byte === CR) {
|
|
218
|
+
lineEndings += 1;
|
|
219
|
+
pendingCR = true;
|
|
220
|
+
} else if (byte === LF) {
|
|
221
|
+
if (!pendingCR) lineEndings += 1;
|
|
222
|
+
pendingCR = false;
|
|
223
|
+
} else {
|
|
224
|
+
lineEndings = 0;
|
|
225
|
+
pendingCR = false;
|
|
226
|
+
}
|
|
227
|
+
if (bytesInEvent > maxBytes) {
|
|
228
|
+
controller.error(recordViolation(slot, new import_errors.ResponseTooLargeError(maxBytes, bytesInEvent, url)));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (lineEndings >= 2) {
|
|
232
|
+
lineEndings = 0;
|
|
233
|
+
pendingReset = true;
|
|
234
|
+
separatorTail = pendingCR;
|
|
235
|
+
pendingCR = false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
controller.enqueue(chunk);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
return respondWith(response, response.body.pipeThrough(counter));
|
|
242
|
+
}
|
|
243
|
+
function cancelBody(response) {
|
|
244
|
+
response.body?.cancel().catch(() => {
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function respondWith(response, body) {
|
|
248
|
+
return new Response(body, {
|
|
88
249
|
status: response.status,
|
|
89
250
|
statusText: response.statusText,
|
|
90
251
|
headers: response.headers
|
|
@@ -99,6 +260,9 @@ function parseContentLength(value) {
|
|
|
99
260
|
}
|
|
100
261
|
// Annotate the CommonJS export names for ESM import in node:
|
|
101
262
|
0 && (module.exports = {
|
|
263
|
+
DEFAULT_MAX_RESPONSE_BYTES,
|
|
264
|
+
SSE_CUMULATIVE_BUDGET_MULTIPLIER,
|
|
265
|
+
responseSizeCapCacheKey,
|
|
102
266
|
responseSizeLimitStorage,
|
|
103
267
|
withResponseSizeLimit,
|
|
104
268
|
wrapFetchWithSizeLimit
|
|
@@ -5,52 +5,116 @@ const __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));
|
|
|
5
5
|
const require2 = __adcpCreateRequire(import.meta.url);
|
|
6
6
|
import { globalAsyncLocalStorage } from "../utils/global-async-local-storage.mjs";
|
|
7
7
|
import { ResponseTooLargeError } from "../errors/index.mjs";
|
|
8
|
+
import { sanitizeTransportUrl } from "./transportDiagnostics.mjs";
|
|
9
|
+
const DEFAULT_MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
10
|
+
const SSE_CUMULATIVE_BUDGET_MULTIPLIER = 2;
|
|
8
11
|
const responseSizeLimitStorage = globalAsyncLocalStorage("responseSizeLimit");
|
|
12
|
+
function resolveResponseSizeCap(maxResponseBytes) {
|
|
13
|
+
if (maxResponseBytes === void 0) return DEFAULT_MAX_RESPONSE_BYTES;
|
|
14
|
+
if (maxResponseBytes === 0) return null;
|
|
15
|
+
if (!Number.isFinite(maxResponseBytes) || maxResponseBytes < 0) return DEFAULT_MAX_RESPONSE_BYTES;
|
|
16
|
+
return maxResponseBytes;
|
|
17
|
+
}
|
|
18
|
+
function newSlot(maxResponseBytes) {
|
|
19
|
+
const resolved = resolveResponseSizeCap(maxResponseBytes);
|
|
20
|
+
if (resolved === null) return { maxResponseBytes: null };
|
|
21
|
+
const enclosing = responseSizeLimitStorage.getStore();
|
|
22
|
+
const limit = sseBudgetFor(resolved);
|
|
23
|
+
return {
|
|
24
|
+
// Nesting narrows both numbers. `?? resolved` deliberately also covers an
|
|
25
|
+
// enclosing opt-out (`null`): an inner scope that asks for a cap is the
|
|
26
|
+
// more specific instruction, so it still gets one.
|
|
27
|
+
maxResponseBytes: Math.min(resolved, enclosing?.maxResponseBytes ?? resolved),
|
|
28
|
+
streamLimit: Math.min(limit, enclosing?.streamLimit ?? limit),
|
|
29
|
+
streamMeter: enclosing?.streamMeter ?? { consumed: 0 }
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function sseBudgetFor(maxResponseBytes) {
|
|
33
|
+
return Math.min(maxResponseBytes * SSE_CUMULATIVE_BUDGET_MULTIPLIER, Number.MAX_SAFE_INTEGER);
|
|
34
|
+
}
|
|
35
|
+
function responseSizeCapCacheKey() {
|
|
36
|
+
const slot = responseSizeLimitStorage.getStore();
|
|
37
|
+
const cap = slot ? slot.maxResponseBytes : DEFAULT_MAX_RESPONSE_BYTES;
|
|
38
|
+
return `max-response-bytes:${cap === null ? "off" : cap}`;
|
|
39
|
+
}
|
|
9
40
|
function withResponseSizeLimit(maxResponseBytes, fn) {
|
|
10
|
-
if (
|
|
41
|
+
if (maxResponseBytes === void 0 && responseSizeLimitStorage.getStore()) {
|
|
11
42
|
return fn();
|
|
12
43
|
}
|
|
13
|
-
|
|
44
|
+
const slot = newSlot(maxResponseBytes);
|
|
45
|
+
return responseSizeLimitStorage.run(slot, () => rethrowRecordedViolation(slot, fn));
|
|
46
|
+
}
|
|
47
|
+
async function rethrowRecordedViolation(slot, fn) {
|
|
48
|
+
try {
|
|
49
|
+
return await fn();
|
|
50
|
+
} catch (error) {
|
|
51
|
+
const violation = slot.violation;
|
|
52
|
+
if (!violation || error instanceof ResponseTooLargeError) throw error;
|
|
53
|
+
const surfaced = new ResponseTooLargeError(
|
|
54
|
+
violation.limit,
|
|
55
|
+
violation.bytesRead,
|
|
56
|
+
violation.url,
|
|
57
|
+
violation.contentLengthHeader
|
|
58
|
+
);
|
|
59
|
+
Object.defineProperty(surfaced, "cause", { value: error, configurable: true });
|
|
60
|
+
throw surfaced;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function recordViolation(slot, error) {
|
|
64
|
+
if (slot && !slot.violation) slot.violation = error;
|
|
65
|
+
return error;
|
|
14
66
|
}
|
|
15
67
|
function urlOfInput(input) {
|
|
16
68
|
if (typeof input === "string") return input;
|
|
17
69
|
if (input instanceof URL) return input.toString();
|
|
18
70
|
return input.url;
|
|
19
71
|
}
|
|
20
|
-
function redactUrlForError(url) {
|
|
21
|
-
try {
|
|
22
|
-
const parsed = new URL(url);
|
|
23
|
-
parsed.search = "";
|
|
24
|
-
return parsed.toString();
|
|
25
|
-
} catch {
|
|
26
|
-
return url;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function withIdentityEncoding(init) {
|
|
30
|
-
const headers = new Headers(init?.headers);
|
|
31
|
-
if (!headers.has("accept-encoding")) {
|
|
32
|
-
headers.set("accept-encoding", "identity");
|
|
33
|
-
}
|
|
34
|
-
return { ...init ?? {}, headers };
|
|
35
|
-
}
|
|
36
72
|
function wrapFetchWithSizeLimit(upstream) {
|
|
37
73
|
const wrapped = async (input, init) => {
|
|
38
74
|
const slot = responseSizeLimitStorage.getStore();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
75
|
+
const maxBytes = slot ? slot.maxResponseBytes : DEFAULT_MAX_RESPONSE_BYTES;
|
|
76
|
+
if (maxBytes === null) return upstream(input, init);
|
|
77
|
+
const response = await upstream(input, init);
|
|
78
|
+
if (NULL_BODY_STATUSES.has(response.status)) return response;
|
|
79
|
+
const skipDeclaredLength = methodOf(input, init) === "HEAD";
|
|
80
|
+
const url = sanitizeTransportUrl(urlOfInput(input));
|
|
81
|
+
if (isEventStream(response)) {
|
|
82
|
+
const connectionScoped = methodOf(input, init) === "GET";
|
|
83
|
+
const { limit, meter } = streamBudgetFor(connectionScoped, slot, maxBytes);
|
|
84
|
+
return enforceEventStreamLimit(
|
|
85
|
+
response,
|
|
86
|
+
maxBytes,
|
|
87
|
+
limit,
|
|
88
|
+
meter,
|
|
89
|
+
url,
|
|
90
|
+
connectionScoped ? void 0 : slot,
|
|
91
|
+
skipDeclaredLength
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return enforceSizeLimit(response, maxBytes, url, slot, skipDeclaredLength);
|
|
42
95
|
};
|
|
43
96
|
return wrapped;
|
|
44
97
|
}
|
|
45
|
-
function
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
98
|
+
function streamBudgetFor(connectionScoped, slot, maxBytes) {
|
|
99
|
+
if (connectionScoped) return { limit: sseBudgetFor(maxBytes), meter: { consumed: 0 } };
|
|
100
|
+
return {
|
|
101
|
+
limit: slot?.streamLimit ?? sseBudgetFor(maxBytes),
|
|
102
|
+
meter: slot?.streamMeter ?? { consumed: 0 }
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function methodOf(input, init) {
|
|
106
|
+
const method = init?.method ?? (typeof Request !== "undefined" && input instanceof Request ? input.method : "GET");
|
|
107
|
+
return method.toUpperCase();
|
|
108
|
+
}
|
|
109
|
+
const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
|
|
110
|
+
function isEventStream(response) {
|
|
111
|
+
return response.headers.get("content-type")?.toLowerCase().startsWith("text/event-stream") === true;
|
|
112
|
+
}
|
|
113
|
+
function enforceSizeLimit(response, maxBytes, url, slot, skipDeclaredLength = false) {
|
|
114
|
+
const declared = skipDeclaredLength ? void 0 : parseContentLength(response.headers.get("content-length"));
|
|
50
115
|
if (declared !== void 0 && declared > maxBytes) {
|
|
51
|
-
response
|
|
52
|
-
|
|
53
|
-
throw new ResponseTooLargeError(maxBytes, 0, url, declared);
|
|
116
|
+
cancelBody(response);
|
|
117
|
+
throw recordViolation(slot, new ResponseTooLargeError(maxBytes, 0, url, declared));
|
|
54
118
|
}
|
|
55
119
|
if (!response.body) return response;
|
|
56
120
|
let bytesRead = 0;
|
|
@@ -58,13 +122,107 @@ function enforceSizeLimit(response, maxBytes, url) {
|
|
|
58
122
|
transform(chunk, controller) {
|
|
59
123
|
bytesRead += chunk.byteLength;
|
|
60
124
|
if (bytesRead > maxBytes) {
|
|
61
|
-
controller.error(new ResponseTooLargeError(maxBytes, bytesRead, url));
|
|
125
|
+
controller.error(recordViolation(slot, new ResponseTooLargeError(maxBytes, bytesRead, url)));
|
|
62
126
|
return;
|
|
63
127
|
}
|
|
64
128
|
controller.enqueue(chunk);
|
|
65
129
|
}
|
|
66
130
|
});
|
|
67
|
-
return
|
|
131
|
+
return respondWith(response, response.body.pipeThrough(counter));
|
|
132
|
+
}
|
|
133
|
+
const CR = 13;
|
|
134
|
+
const LF = 10;
|
|
135
|
+
function enforceEventStreamLimit(response, maxBytes, streamLimit, meter, url, slot, skipDeclaredLength = false) {
|
|
136
|
+
const remaining = streamLimit - meter.consumed;
|
|
137
|
+
const declared = skipDeclaredLength ? void 0 : parseContentLength(response.headers.get("content-length"));
|
|
138
|
+
if (declared !== void 0 && declared > remaining) {
|
|
139
|
+
cancelBody(response);
|
|
140
|
+
throw recordViolation(slot, new ResponseTooLargeError(streamLimit, meter.consumed, url, declared));
|
|
141
|
+
}
|
|
142
|
+
if (!response.body) return response;
|
|
143
|
+
let bytesInEvent = 0;
|
|
144
|
+
let lineEndings = 0;
|
|
145
|
+
let pendingCR = false;
|
|
146
|
+
let separatorTail = false;
|
|
147
|
+
let pendingReset = false;
|
|
148
|
+
const counter = new TransformStream({
|
|
149
|
+
transform(chunk, controller) {
|
|
150
|
+
meter.consumed += chunk.byteLength;
|
|
151
|
+
if (meter.consumed > streamLimit) {
|
|
152
|
+
controller.error(recordViolation(slot, new ResponseTooLargeError(streamLimit, meter.consumed, url)));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (chunk.length === 0) {
|
|
156
|
+
controller.enqueue(chunk);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (chunk.indexOf(LF) === -1 && chunk.indexOf(CR) === -1) {
|
|
160
|
+
if (pendingReset) {
|
|
161
|
+
pendingReset = false;
|
|
162
|
+
separatorTail = false;
|
|
163
|
+
bytesInEvent = 0;
|
|
164
|
+
}
|
|
165
|
+
bytesInEvent += chunk.length;
|
|
166
|
+
lineEndings = 0;
|
|
167
|
+
pendingCR = false;
|
|
168
|
+
if (bytesInEvent > maxBytes) {
|
|
169
|
+
controller.error(recordViolation(slot, new ResponseTooLargeError(maxBytes, bytesInEvent, url)));
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
controller.enqueue(chunk);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
for (let i = 0; i < chunk.length; i += 1) {
|
|
176
|
+
const byte = chunk[i];
|
|
177
|
+
if (pendingReset) {
|
|
178
|
+
pendingReset = false;
|
|
179
|
+
if (separatorTail && byte === LF) {
|
|
180
|
+
separatorTail = false;
|
|
181
|
+
pendingCR = false;
|
|
182
|
+
bytesInEvent += 1;
|
|
183
|
+
if (bytesInEvent > maxBytes) {
|
|
184
|
+
controller.error(recordViolation(slot, new ResponseTooLargeError(maxBytes, bytesInEvent, url)));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
bytesInEvent = 0;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
separatorTail = false;
|
|
191
|
+
bytesInEvent = 0;
|
|
192
|
+
}
|
|
193
|
+
bytesInEvent += 1;
|
|
194
|
+
if (byte === CR) {
|
|
195
|
+
lineEndings += 1;
|
|
196
|
+
pendingCR = true;
|
|
197
|
+
} else if (byte === LF) {
|
|
198
|
+
if (!pendingCR) lineEndings += 1;
|
|
199
|
+
pendingCR = false;
|
|
200
|
+
} else {
|
|
201
|
+
lineEndings = 0;
|
|
202
|
+
pendingCR = false;
|
|
203
|
+
}
|
|
204
|
+
if (bytesInEvent > maxBytes) {
|
|
205
|
+
controller.error(recordViolation(slot, new ResponseTooLargeError(maxBytes, bytesInEvent, url)));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (lineEndings >= 2) {
|
|
209
|
+
lineEndings = 0;
|
|
210
|
+
pendingReset = true;
|
|
211
|
+
separatorTail = pendingCR;
|
|
212
|
+
pendingCR = false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
controller.enqueue(chunk);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return respondWith(response, response.body.pipeThrough(counter));
|
|
219
|
+
}
|
|
220
|
+
function cancelBody(response) {
|
|
221
|
+
response.body?.cancel().catch(() => {
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function respondWith(response, body) {
|
|
225
|
+
return new Response(body, {
|
|
68
226
|
status: response.status,
|
|
69
227
|
statusText: response.statusText,
|
|
70
228
|
headers: response.headers
|
|
@@ -78,6 +236,9 @@ function parseContentLength(value) {
|
|
|
78
236
|
return Number.isFinite(parsed) ? parsed : void 0;
|
|
79
237
|
}
|
|
80
238
|
export {
|
|
239
|
+
DEFAULT_MAX_RESPONSE_BYTES,
|
|
240
|
+
SSE_CUMULATIVE_BUDGET_MULTIPLIER,
|
|
241
|
+
responseSizeCapCacheKey,
|
|
81
242
|
responseSizeLimitStorage,
|
|
82
243
|
withResponseSizeLimit,
|
|
83
244
|
wrapFetchWithSizeLimit
|
|
@@ -67,6 +67,7 @@ ALTER TABLE adcp_reporting_warehouse_sinks
|
|
|
67
67
|
const MAX_LOAD_TIMEOUT = 6 * 36e5;
|
|
68
68
|
const MAX_TIMEOUT_DOUBLINGS = 16;
|
|
69
69
|
let warnedLabelsIgnored = false;
|
|
70
|
+
let warnedLocationUnset = false;
|
|
70
71
|
const PROJECT = /^[a-z][a-z0-9-]{4,61}[a-z0-9]$/;
|
|
71
72
|
const DATASET_OR_TABLE = /^[A-Za-z_][A-Za-z0-9_]{0,1023}$/;
|
|
72
73
|
const NAME = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
@@ -97,6 +98,13 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
97
98
|
{ code: "ADCP_BIGQUERY_SINK_LABELS_IGNORED", type: "DeprecationWarning" }
|
|
98
99
|
);
|
|
99
100
|
}
|
|
101
|
+
if (!options.location && !warnedLocationUnset) {
|
|
102
|
+
warnedLocationUnset = true;
|
|
103
|
+
process.emitWarning(
|
|
104
|
+
'BigQuery warehouse sink option `location` is not set. Replay lookups of load jobs need it for datasets outside the US and EU multi-regions: without it BigQuery answers 404, the sink uploads again, gets a 409, and then fails with a "check projectId and location" error.',
|
|
105
|
+
{ code: "ADCP_BIGQUERY_SINK_LOCATION_UNSET" }
|
|
106
|
+
);
|
|
107
|
+
}
|
|
100
108
|
const tables = {
|
|
101
109
|
projectId: options.projectId,
|
|
102
110
|
datasetId: options.datasetId,
|
|
@@ -29,6 +29,7 @@ ALTER TABLE adcp_reporting_warehouse_sinks
|
|
|
29
29
|
const MAX_LOAD_TIMEOUT = 6 * 36e5;
|
|
30
30
|
const MAX_TIMEOUT_DOUBLINGS = 16;
|
|
31
31
|
let warnedLabelsIgnored = false;
|
|
32
|
+
let warnedLocationUnset = false;
|
|
32
33
|
const PROJECT = /^[a-z][a-z0-9-]{4,61}[a-z0-9]$/;
|
|
33
34
|
const DATASET_OR_TABLE = /^[A-Za-z_][A-Za-z0-9_]{0,1023}$/;
|
|
34
35
|
const NAME = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
@@ -59,6 +60,13 @@ function createBigQueryReportingWarehouseSinkV1(options) {
|
|
|
59
60
|
{ code: "ADCP_BIGQUERY_SINK_LABELS_IGNORED", type: "DeprecationWarning" }
|
|
60
61
|
);
|
|
61
62
|
}
|
|
63
|
+
if (!options.location && !warnedLocationUnset) {
|
|
64
|
+
warnedLocationUnset = true;
|
|
65
|
+
process.emitWarning(
|
|
66
|
+
'BigQuery warehouse sink option `location` is not set. Replay lookups of load jobs need it for datasets outside the US and EU multi-regions: without it BigQuery answers 404, the sink uploads again, gets a 409, and then fails with a "check projectId and location" error.',
|
|
67
|
+
{ code: "ADCP_BIGQUERY_SINK_LOCATION_UNSET" }
|
|
68
|
+
);
|
|
69
|
+
}
|
|
62
70
|
const tables = {
|
|
63
71
|
projectId: options.projectId,
|
|
64
72
|
datasetId: options.datasetId,
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
"source_sha": "4e553ad955f83b49c7d221ab5c3ff78237ad02e3",
|
|
5
5
|
"source_tarball_sha256": "580656d6466ef9f0d1119985e6726c2efea718dc671e2ad30957fcb2fd54af0f",
|
|
6
6
|
"upstream_adcp_version": "2.5.3",
|
|
7
|
-
"synced_at": "2026-10-
|
|
7
|
+
"synced_at": "2026-10-15T19:30:04.842Z"
|
|
8
8
|
}
|
|
@@ -49,7 +49,12 @@ export interface VerifySignatureAsAuthenticatorOptions {
|
|
|
49
49
|
/** Explicit experimental profile. Verification never creates a principal or fetches trust.json. */
|
|
50
50
|
webBotAuth?: {
|
|
51
51
|
directory: import('../signing/web-bot-auth.mjs').SignatureDirectoryResolver;
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated Revocation belongs to the identity layer: use
|
|
54
|
+
* `createIdentity33PrincipalResolver({ revocation })`. Required only when
|
|
55
|
+
* `resolvePrincipal` does not check revocation itself.
|
|
56
|
+
*/
|
|
57
|
+
isRevoked?: (origin: string, keyid: string) => Promise<boolean>;
|
|
53
58
|
/** Resolve only an existing audited binding; handle identity-established callers with anonymous scope. */
|
|
54
59
|
resolvePrincipal: (signers: readonly VerifiedWebBotSigner[], operation: ResolvedOperation) => Promise<AuthPrincipal>;
|
|
55
60
|
};
|
|
@@ -49,7 +49,12 @@ export interface VerifySignatureAsAuthenticatorOptions {
|
|
|
49
49
|
/** Explicit experimental profile. Verification never creates a principal or fetches trust.json. */
|
|
50
50
|
webBotAuth?: {
|
|
51
51
|
directory: import('../signing/web-bot-auth').SignatureDirectoryResolver;
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated Revocation belongs to the identity layer: use
|
|
54
|
+
* `createIdentity33PrincipalResolver({ revocation })`. Required only when
|
|
55
|
+
* `resolvePrincipal` does not check revocation itself.
|
|
56
|
+
*/
|
|
57
|
+
isRevoked?: (origin: string, keyid: string) => Promise<boolean>;
|
|
53
58
|
/** Resolve only an existing audited binding; handle identity-established callers with anonymous scope. */
|
|
54
59
|
resolvePrincipal: (signers: readonly VerifiedWebBotSigner[], operation: ResolvedOperation) => Promise<AuthPrincipal>;
|
|
55
60
|
};
|