@tansr/serve 0.6.0 → 0.6.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/dist/index.d.ts +100 -2
- package/dist/index.js +1229 -354
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -227,9 +227,9 @@ var require_timers = __commonJS({
|
|
|
227
227
|
* before the specified function or code is executed.
|
|
228
228
|
* @param {*} arg
|
|
229
229
|
*/
|
|
230
|
-
constructor(callback,
|
|
230
|
+
constructor(callback, delay2, arg) {
|
|
231
231
|
this._onTimeout = callback;
|
|
232
|
-
this._idleTimeout =
|
|
232
|
+
this._idleTimeout = delay2;
|
|
233
233
|
this._timerArg = arg;
|
|
234
234
|
this.refresh();
|
|
235
235
|
}
|
|
@@ -274,8 +274,8 @@ var require_timers = __commonJS({
|
|
|
274
274
|
* when the timer expires.
|
|
275
275
|
* @returns {NodeJS.Timeout|FastTimer}
|
|
276
276
|
*/
|
|
277
|
-
setTimeout(callback,
|
|
278
|
-
return
|
|
277
|
+
setTimeout(callback, delay2, arg) {
|
|
278
|
+
return delay2 <= RESOLUTION_MS ? setTimeout(callback, delay2, arg) : new FastTimer(callback, delay2, arg);
|
|
279
279
|
},
|
|
280
280
|
/**
|
|
281
281
|
* The clearTimeout method cancels an instantiated Timer previously created
|
|
@@ -301,8 +301,8 @@ var require_timers = __commonJS({
|
|
|
301
301
|
* when the timer expires.
|
|
302
302
|
* @returns {FastTimer}
|
|
303
303
|
*/
|
|
304
|
-
setFastTimeout(callback,
|
|
305
|
-
return new FastTimer(callback,
|
|
304
|
+
setFastTimeout(callback, delay2, arg) {
|
|
305
|
+
return new FastTimer(callback, delay2, arg);
|
|
306
306
|
},
|
|
307
307
|
/**
|
|
308
308
|
* The clearTimeout method cancels an instantiated FastTimer previously
|
|
@@ -328,8 +328,8 @@ var require_timers = __commonJS({
|
|
|
328
328
|
* @deprecated
|
|
329
329
|
* @param {number} [delay=0] The delay in milliseconds to add to the now value.
|
|
330
330
|
*/
|
|
331
|
-
tick(
|
|
332
|
-
fastNow +=
|
|
331
|
+
tick(delay2 = 0) {
|
|
332
|
+
fastNow += delay2 - RESOLUTION_MS + 1;
|
|
333
333
|
onTick();
|
|
334
334
|
onTick();
|
|
335
335
|
},
|
|
@@ -1151,14 +1151,14 @@ var require_util = __commonJS({
|
|
|
1151
1151
|
}
|
|
1152
1152
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
1153
1153
|
let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
|
|
1154
|
-
let
|
|
1154
|
+
let path18 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
1155
1155
|
if (origin[origin.length - 1] === "/") {
|
|
1156
1156
|
origin = origin.slice(0, origin.length - 1);
|
|
1157
1157
|
}
|
|
1158
|
-
if (
|
|
1159
|
-
|
|
1158
|
+
if (path18 && path18[0] !== "/") {
|
|
1159
|
+
path18 = `/${path18}`;
|
|
1160
1160
|
}
|
|
1161
|
-
return new URL(`${origin}${
|
|
1161
|
+
return new URL(`${origin}${path18}`);
|
|
1162
1162
|
}
|
|
1163
1163
|
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
|
|
1164
1164
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -2029,9 +2029,9 @@ var require_diagnostics = __commonJS({
|
|
|
2029
2029
|
"undici:client:sendHeaders",
|
|
2030
2030
|
(evt) => {
|
|
2031
2031
|
const {
|
|
2032
|
-
request: { method, path:
|
|
2032
|
+
request: { method, path: path18, origin }
|
|
2033
2033
|
} = evt;
|
|
2034
|
-
debugLog("sending request to %s %s%s", method, origin,
|
|
2034
|
+
debugLog("sending request to %s %s%s", method, origin, path18);
|
|
2035
2035
|
}
|
|
2036
2036
|
);
|
|
2037
2037
|
}
|
|
@@ -2049,14 +2049,14 @@ var require_diagnostics = __commonJS({
|
|
|
2049
2049
|
"undici:request:headers",
|
|
2050
2050
|
(evt) => {
|
|
2051
2051
|
const {
|
|
2052
|
-
request: { method, path:
|
|
2052
|
+
request: { method, path: path18, origin },
|
|
2053
2053
|
response: { statusCode }
|
|
2054
2054
|
} = evt;
|
|
2055
2055
|
debugLog(
|
|
2056
2056
|
"received response to %s %s%s - HTTP %d",
|
|
2057
2057
|
method,
|
|
2058
2058
|
origin,
|
|
2059
|
-
|
|
2059
|
+
path18,
|
|
2060
2060
|
statusCode
|
|
2061
2061
|
);
|
|
2062
2062
|
}
|
|
@@ -2065,23 +2065,23 @@ var require_diagnostics = __commonJS({
|
|
|
2065
2065
|
"undici:request:trailers",
|
|
2066
2066
|
(evt) => {
|
|
2067
2067
|
const {
|
|
2068
|
-
request: { method, path:
|
|
2068
|
+
request: { method, path: path18, origin }
|
|
2069
2069
|
} = evt;
|
|
2070
|
-
debugLog("trailers received from %s %s%s", method, origin,
|
|
2070
|
+
debugLog("trailers received from %s %s%s", method, origin, path18);
|
|
2071
2071
|
}
|
|
2072
2072
|
);
|
|
2073
2073
|
diagnosticsChannel.subscribe(
|
|
2074
2074
|
"undici:request:error",
|
|
2075
2075
|
(evt) => {
|
|
2076
2076
|
const {
|
|
2077
|
-
request: { method, path:
|
|
2077
|
+
request: { method, path: path18, origin },
|
|
2078
2078
|
error
|
|
2079
2079
|
} = evt;
|
|
2080
2080
|
debugLog(
|
|
2081
2081
|
"request to %s %s%s errored - %s",
|
|
2082
2082
|
method,
|
|
2083
2083
|
origin,
|
|
2084
|
-
|
|
2084
|
+
path18,
|
|
2085
2085
|
error.message
|
|
2086
2086
|
);
|
|
2087
2087
|
}
|
|
@@ -2236,7 +2236,7 @@ var require_request = __commonJS({
|
|
|
2236
2236
|
};
|
|
2237
2237
|
var Request2 = class {
|
|
2238
2238
|
constructor(origin, {
|
|
2239
|
-
path:
|
|
2239
|
+
path: path18,
|
|
2240
2240
|
method,
|
|
2241
2241
|
body,
|
|
2242
2242
|
headers,
|
|
@@ -2253,11 +2253,11 @@ var require_request = __commonJS({
|
|
|
2253
2253
|
maxRedirections,
|
|
2254
2254
|
typeOfService
|
|
2255
2255
|
}, handler) {
|
|
2256
|
-
if (typeof
|
|
2256
|
+
if (typeof path18 !== "string") {
|
|
2257
2257
|
throw new InvalidArgumentError("path must be a string");
|
|
2258
|
-
} else if (
|
|
2258
|
+
} else if (path18[0] !== "/" && !(path18.startsWith("http://") || path18.startsWith("https://")) && method !== "CONNECT") {
|
|
2259
2259
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
2260
|
-
} else if (invalidPathRegex.test(
|
|
2260
|
+
} else if (invalidPathRegex.test(path18)) {
|
|
2261
2261
|
throw new InvalidArgumentError("invalid request path");
|
|
2262
2262
|
}
|
|
2263
2263
|
if (typeof method !== "string") {
|
|
@@ -2332,7 +2332,7 @@ var require_request = __commonJS({
|
|
|
2332
2332
|
this.completed = false;
|
|
2333
2333
|
this.aborted = false;
|
|
2334
2334
|
this.upgrade = upgrade || null;
|
|
2335
|
-
this.path = query2 ? serializePathWithQuery(
|
|
2335
|
+
this.path = query2 ? serializePathWithQuery(path18, query2) : path18;
|
|
2336
2336
|
this.origin = origin;
|
|
2337
2337
|
this.protocol = getProtocolFromUrlString(origin);
|
|
2338
2338
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" || method === "QUERY" : idempotent;
|
|
@@ -4886,7 +4886,7 @@ var require_webidl = __commonJS({
|
|
|
4886
4886
|
var require_util2 = __commonJS({
|
|
4887
4887
|
"../../node_modules/.pnpm/undici@8.10.0/node_modules/undici/lib/web/fetch/util.js"(exports, module) {
|
|
4888
4888
|
"use strict";
|
|
4889
|
-
var { Transform:
|
|
4889
|
+
var { Transform: Transform3 } = __require("node:stream");
|
|
4890
4890
|
var zlib2 = __require("node:zlib");
|
|
4891
4891
|
var { redirectStatusSet, referrerPolicyTokens, badPortsSet } = require_constants3();
|
|
4892
4892
|
var { getGlobalOrigin } = require_global();
|
|
@@ -5477,7 +5477,7 @@ var require_util2 = __commonJS({
|
|
|
5477
5477
|
contentRange += isomorphicEncode(`${fullLength}`);
|
|
5478
5478
|
return contentRange;
|
|
5479
5479
|
}
|
|
5480
|
-
var InflateStream = class extends
|
|
5480
|
+
var InflateStream = class extends Transform3 {
|
|
5481
5481
|
#zlibOptions;
|
|
5482
5482
|
/** @param {zlib.ZlibOptions} [zlibOptions] */
|
|
5483
5483
|
constructor(zlibOptions) {
|
|
@@ -6741,21 +6741,21 @@ var require_client_h1 = __commonJS({
|
|
|
6741
6741
|
this.connectionKeepAlive = false;
|
|
6742
6742
|
this.maxResponseSize = client[kMaxResponseSize];
|
|
6743
6743
|
}
|
|
6744
|
-
setTimeout(
|
|
6745
|
-
if (
|
|
6744
|
+
setTimeout(delay2, type) {
|
|
6745
|
+
if (delay2 !== this.timeoutValue || type & USE_FAST_TIMER ^ this.timeoutType & USE_FAST_TIMER) {
|
|
6746
6746
|
if (this.timeout) {
|
|
6747
6747
|
timers.clearTimeout(this.timeout);
|
|
6748
6748
|
this.timeout = null;
|
|
6749
6749
|
}
|
|
6750
|
-
if (
|
|
6750
|
+
if (delay2) {
|
|
6751
6751
|
if (type & USE_FAST_TIMER) {
|
|
6752
|
-
this.timeout = timers.setFastTimeout(onParserTimeout,
|
|
6752
|
+
this.timeout = timers.setFastTimeout(onParserTimeout, delay2, this.timeoutWeakRef);
|
|
6753
6753
|
} else {
|
|
6754
|
-
this.timeout = setTimeout(onParserTimeout,
|
|
6754
|
+
this.timeout = setTimeout(onParserTimeout, delay2, this.timeoutWeakRef);
|
|
6755
6755
|
this.timeout?.unref();
|
|
6756
6756
|
}
|
|
6757
6757
|
}
|
|
6758
|
-
this.timeoutValue =
|
|
6758
|
+
this.timeoutValue = delay2;
|
|
6759
6759
|
} else if (this.timeout) {
|
|
6760
6760
|
if (this.timeout.refresh) {
|
|
6761
6761
|
this.timeout.refresh();
|
|
@@ -7418,7 +7418,7 @@ var require_client_h1 = __commonJS({
|
|
|
7418
7418
|
}
|
|
7419
7419
|
}
|
|
7420
7420
|
function writeH1(client, request) {
|
|
7421
|
-
const { method, path:
|
|
7421
|
+
const { method, path: path18, host, upgrade, blocking, reset } = request;
|
|
7422
7422
|
let { body, headers, contentLength } = request;
|
|
7423
7423
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
7424
7424
|
if (util.isFormDataLike(body)) {
|
|
@@ -7494,7 +7494,7 @@ var require_client_h1 = __commonJS({
|
|
|
7494
7494
|
socket[kBlocking] = true;
|
|
7495
7495
|
}
|
|
7496
7496
|
setTypeOfService(socket, request);
|
|
7497
|
-
let header = `${method} ${
|
|
7497
|
+
let header = `${method} ${path18} HTTP/1.1\r
|
|
7498
7498
|
`;
|
|
7499
7499
|
if (typeof host === "string") {
|
|
7500
7500
|
header += `host: ${host}\r
|
|
@@ -7844,7 +7844,7 @@ var require_client_h2 = __commonJS({
|
|
|
7844
7844
|
"../../node_modules/.pnpm/undici@8.10.0/node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) {
|
|
7845
7845
|
"use strict";
|
|
7846
7846
|
var assert = __require("node:assert");
|
|
7847
|
-
var { pipeline:
|
|
7847
|
+
var { pipeline: pipeline3 } = __require("node:stream");
|
|
7848
7848
|
var util = require_util();
|
|
7849
7849
|
var {
|
|
7850
7850
|
RequestContentLengthMismatchError,
|
|
@@ -8575,7 +8575,7 @@ var require_client_h2 = __commonJS({
|
|
|
8575
8575
|
const headersTimeout = request.headersTimeout ?? client[kHeadersTimeout];
|
|
8576
8576
|
const bodyTimeout = request.bodyTimeout ?? client[kBodyTimeout];
|
|
8577
8577
|
const session = client[kHTTP2Session];
|
|
8578
|
-
const { method, path:
|
|
8578
|
+
const { method, path: path18, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
|
|
8579
8579
|
if (upgrade != null && upgrade !== "websocket") {
|
|
8580
8580
|
util.errorRequest(client, request, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
8581
8581
|
return false;
|
|
@@ -8638,7 +8638,7 @@ var require_client_h2 = __commonJS({
|
|
|
8638
8638
|
}
|
|
8639
8639
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
8640
8640
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
8641
|
-
headers[HTTP2_HEADER_PATH] =
|
|
8641
|
+
headers[HTTP2_HEADER_PATH] = path18;
|
|
8642
8642
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
8643
8643
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
8644
8644
|
} else {
|
|
@@ -8660,7 +8660,7 @@ var require_client_h2 = __commonJS({
|
|
|
8660
8660
|
setupUpgradeStream(stream, state);
|
|
8661
8661
|
return true;
|
|
8662
8662
|
}
|
|
8663
|
-
headers[HTTP2_HEADER_PATH] =
|
|
8663
|
+
headers[HTTP2_HEADER_PATH] = path18;
|
|
8664
8664
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
8665
8665
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
8666
8666
|
let body = state.body;
|
|
@@ -8991,7 +8991,7 @@ var require_client_h2 = __commonJS({
|
|
|
8991
8991
|
}
|
|
8992
8992
|
function writeStream(abort, socket, expectsPayload, h2stream, body, client, request, contentLength) {
|
|
8993
8993
|
assert(contentLength !== 0 || client[kRunning] === 0, "stream body cannot be pipelined");
|
|
8994
|
-
const pipe =
|
|
8994
|
+
const pipe = pipeline3(
|
|
8995
8995
|
body,
|
|
8996
8996
|
h2stream,
|
|
8997
8997
|
(err) => {
|
|
@@ -11330,10 +11330,10 @@ var require_proxy_agent = __commonJS({
|
|
|
11330
11330
|
};
|
|
11331
11331
|
const {
|
|
11332
11332
|
origin,
|
|
11333
|
-
path:
|
|
11333
|
+
path: path18 = "/",
|
|
11334
11334
|
headers = {}
|
|
11335
11335
|
} = opts;
|
|
11336
|
-
opts.path = origin +
|
|
11336
|
+
opts.path = origin + path18;
|
|
11337
11337
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
11338
11338
|
const { host } = new URL(origin);
|
|
11339
11339
|
headers.host = host;
|
|
@@ -13210,7 +13210,7 @@ var require_api_pipeline = __commonJS({
|
|
|
13210
13210
|
util.destroy(ret, err);
|
|
13211
13211
|
}
|
|
13212
13212
|
};
|
|
13213
|
-
function
|
|
13213
|
+
function pipeline3(opts, handler) {
|
|
13214
13214
|
try {
|
|
13215
13215
|
const pipelineHandler = new PipelineHandler(opts, handler);
|
|
13216
13216
|
this.dispatch({ ...opts, body: pipelineHandler.req }, pipelineHandler);
|
|
@@ -13219,7 +13219,7 @@ var require_api_pipeline = __commonJS({
|
|
|
13219
13219
|
return new PassThrough().destroy(err);
|
|
13220
13220
|
}
|
|
13221
13221
|
}
|
|
13222
|
-
module.exports =
|
|
13222
|
+
module.exports = pipeline3;
|
|
13223
13223
|
}
|
|
13224
13224
|
});
|
|
13225
13225
|
|
|
@@ -13598,20 +13598,20 @@ var require_mock_utils = __commonJS({
|
|
|
13598
13598
|
}
|
|
13599
13599
|
return normalizedQp;
|
|
13600
13600
|
}
|
|
13601
|
-
function safeUrl(
|
|
13602
|
-
if (typeof
|
|
13603
|
-
return
|
|
13601
|
+
function safeUrl(path18) {
|
|
13602
|
+
if (typeof path18 !== "string") {
|
|
13603
|
+
return path18;
|
|
13604
13604
|
}
|
|
13605
|
-
const pathSegments =
|
|
13605
|
+
const pathSegments = path18.split("?", 3);
|
|
13606
13606
|
if (pathSegments.length !== 2) {
|
|
13607
|
-
return
|
|
13607
|
+
return path18;
|
|
13608
13608
|
}
|
|
13609
13609
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
13610
13610
|
qp.sort();
|
|
13611
13611
|
return [...pathSegments, qp.toString()].join("?");
|
|
13612
13612
|
}
|
|
13613
|
-
function matchKey(mockDispatch2, { path:
|
|
13614
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
13613
|
+
function matchKey(mockDispatch2, { path: path18, method, body, headers }) {
|
|
13614
|
+
const pathMatch = matchValue(mockDispatch2.path, path18);
|
|
13615
13615
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
13616
13616
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
13617
13617
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -13638,8 +13638,8 @@ var require_mock_utils = __commonJS({
|
|
|
13638
13638
|
const basePath = key2.query ? serializePathWithQuery(key2.path, key2.query) : key2.path;
|
|
13639
13639
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
13640
13640
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
13641
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
13642
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
13641
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path18, ignoreTrailingSlash }) => {
|
|
13642
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path18)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path18), resolvedPath);
|
|
13643
13643
|
});
|
|
13644
13644
|
if (matchedMockDispatches.length === 0) {
|
|
13645
13645
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -13678,22 +13678,22 @@ var require_mock_utils = __commonJS({
|
|
|
13678
13678
|
mockDispatches.splice(index, 1);
|
|
13679
13679
|
}
|
|
13680
13680
|
}
|
|
13681
|
-
function removeTrailingSlash(
|
|
13682
|
-
if (typeof
|
|
13683
|
-
return
|
|
13681
|
+
function removeTrailingSlash(path18) {
|
|
13682
|
+
if (typeof path18 !== "string") {
|
|
13683
|
+
return path18;
|
|
13684
13684
|
}
|
|
13685
|
-
while (
|
|
13686
|
-
|
|
13685
|
+
while (path18.endsWith("/")) {
|
|
13686
|
+
path18 = path18.slice(0, -1);
|
|
13687
13687
|
}
|
|
13688
|
-
if (
|
|
13689
|
-
|
|
13688
|
+
if (path18.length === 0) {
|
|
13689
|
+
path18 = "/";
|
|
13690
13690
|
}
|
|
13691
|
-
return
|
|
13691
|
+
return path18;
|
|
13692
13692
|
}
|
|
13693
13693
|
function buildKey(opts) {
|
|
13694
|
-
const { path:
|
|
13694
|
+
const { path: path18, method, body, headers, query: query2 } = opts;
|
|
13695
13695
|
return {
|
|
13696
|
-
path:
|
|
13696
|
+
path: path18,
|
|
13697
13697
|
method,
|
|
13698
13698
|
body,
|
|
13699
13699
|
headers,
|
|
@@ -13763,7 +13763,7 @@ var require_mock_utils = __commonJS({
|
|
|
13763
13763
|
return dispatchMockReply(mockDispatches, mockDispatch2, key2, opts, handler);
|
|
13764
13764
|
}
|
|
13765
13765
|
function dispatchMockReply(mockDispatches, mockDispatch2, key2, opts, handler) {
|
|
13766
|
-
const { data: response, delay } = mockDispatch2;
|
|
13766
|
+
const { data: response, delay: delay2 } = mockDispatch2;
|
|
13767
13767
|
if (response.error !== null) {
|
|
13768
13768
|
deleteMockDispatch(mockDispatches, key2);
|
|
13769
13769
|
handler.onResponseError(null, response.error);
|
|
@@ -13853,11 +13853,11 @@ var require_mock_utils = __commonJS({
|
|
|
13853
13853
|
handleReply(dispatches, mockDispatch2.data);
|
|
13854
13854
|
return;
|
|
13855
13855
|
}
|
|
13856
|
-
if (typeof
|
|
13856
|
+
if (typeof delay2 === "number" && delay2 > 0) {
|
|
13857
13857
|
timer = setTimeout(() => {
|
|
13858
13858
|
timer = null;
|
|
13859
13859
|
handleReply(dispatches);
|
|
13860
|
-
},
|
|
13860
|
+
}, delay2);
|
|
13861
13861
|
} else {
|
|
13862
13862
|
handleReply(dispatches);
|
|
13863
13863
|
}
|
|
@@ -14544,13 +14544,13 @@ var require_mock_pool = __commonJS({
|
|
|
14544
14544
|
var require_pending_interceptors_formatter = __commonJS({
|
|
14545
14545
|
"../../node_modules/.pnpm/undici@8.10.0/node_modules/undici/lib/mock/pending-interceptors-formatter.js"(exports, module) {
|
|
14546
14546
|
"use strict";
|
|
14547
|
-
var { Transform:
|
|
14547
|
+
var { Transform: Transform3 } = __require("node:stream");
|
|
14548
14548
|
var { Console } = __require("node:console");
|
|
14549
14549
|
var PERSISTENT = process.versions.icu ? "✅" : "Y ";
|
|
14550
14550
|
var NOT_PERSISTENT = process.versions.icu ? "❌" : "N ";
|
|
14551
14551
|
module.exports = class PendingInterceptorsFormatter {
|
|
14552
14552
|
constructor({ disableColors } = {}) {
|
|
14553
|
-
this.transform = new
|
|
14553
|
+
this.transform = new Transform3({
|
|
14554
14554
|
transform(chunk, _enc, cb) {
|
|
14555
14555
|
cb(null, chunk);
|
|
14556
14556
|
}
|
|
@@ -14564,10 +14564,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
14564
14564
|
}
|
|
14565
14565
|
format(pendingInterceptors) {
|
|
14566
14566
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
14567
|
-
({ method, path:
|
|
14567
|
+
({ method, path: path18, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
14568
14568
|
Method: method,
|
|
14569
14569
|
Origin: origin,
|
|
14570
|
-
Path:
|
|
14570
|
+
Path: path18,
|
|
14571
14571
|
"Status code": statusCode,
|
|
14572
14572
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
14573
14573
|
Invocations: timesInvoked,
|
|
@@ -14649,9 +14649,9 @@ var require_mock_agent = __commonJS({
|
|
|
14649
14649
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
14650
14650
|
const dispatchOpts = { ...opts };
|
|
14651
14651
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
14652
|
-
const [
|
|
14652
|
+
const [path18, searchParams] = dispatchOpts.path.split("?");
|
|
14653
14653
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
14654
|
-
dispatchOpts.path = `${
|
|
14654
|
+
dispatchOpts.path = `${path18}?${normalizedSearchParams}`;
|
|
14655
14655
|
}
|
|
14656
14656
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
14657
14657
|
}
|
|
@@ -14855,7 +14855,7 @@ var require_snapshot_utils = __commonJS({
|
|
|
14855
14855
|
var require_snapshot_recorder = __commonJS({
|
|
14856
14856
|
"../../node_modules/.pnpm/undici@8.10.0/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
|
|
14857
14857
|
"use strict";
|
|
14858
|
-
var { writeFile, readFile:
|
|
14858
|
+
var { writeFile, readFile: readFile12, mkdir: mkdir10 } = __require("node:fs/promises");
|
|
14859
14859
|
var { dirname, resolve } = __require("node:path");
|
|
14860
14860
|
var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
|
|
14861
14861
|
var { InvalidArgumentError, UndiciError } = require_errors();
|
|
@@ -15067,12 +15067,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
15067
15067
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
15068
15068
|
*/
|
|
15069
15069
|
async loadSnapshots(filePath) {
|
|
15070
|
-
const
|
|
15071
|
-
if (!
|
|
15070
|
+
const path18 = filePath || this.#snapshotPath;
|
|
15071
|
+
if (!path18) {
|
|
15072
15072
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
15073
15073
|
}
|
|
15074
15074
|
try {
|
|
15075
|
-
const data = await
|
|
15075
|
+
const data = await readFile12(resolve(path18), "utf8");
|
|
15076
15076
|
const parsed = JSON.parse(data);
|
|
15077
15077
|
if (Array.isArray(parsed)) {
|
|
15078
15078
|
this.#snapshots.clear();
|
|
@@ -15086,7 +15086,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
15086
15086
|
if (error.code === "ENOENT") {
|
|
15087
15087
|
this.#snapshots.clear();
|
|
15088
15088
|
} else {
|
|
15089
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
15089
|
+
throw new UndiciError(`Failed to load snapshots from ${path18}`, { cause: error });
|
|
15090
15090
|
}
|
|
15091
15091
|
}
|
|
15092
15092
|
}
|
|
@@ -15097,12 +15097,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
15097
15097
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
15098
15098
|
*/
|
|
15099
15099
|
async saveSnapshots(filePath) {
|
|
15100
|
-
const
|
|
15101
|
-
if (!
|
|
15100
|
+
const path18 = filePath || this.#snapshotPath;
|
|
15101
|
+
if (!path18) {
|
|
15102
15102
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
15103
15103
|
}
|
|
15104
|
-
const resolvedPath = resolve(
|
|
15105
|
-
await
|
|
15104
|
+
const resolvedPath = resolve(path18);
|
|
15105
|
+
await mkdir10(dirname(resolvedPath), { recursive: true });
|
|
15106
15106
|
const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
15107
15107
|
hash,
|
|
15108
15108
|
snapshot
|
|
@@ -15738,15 +15738,15 @@ var require_redirect_handler = __commonJS({
|
|
|
15738
15738
|
return;
|
|
15739
15739
|
}
|
|
15740
15740
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
15741
|
-
const
|
|
15742
|
-
const redirectUrlString = `${origin}${
|
|
15741
|
+
const path18 = search ? `${pathname}${search}` : pathname;
|
|
15742
|
+
const redirectUrlString = `${origin}${path18}`;
|
|
15743
15743
|
for (const historyUrl of this.history) {
|
|
15744
15744
|
if (historyUrl.toString() === redirectUrlString) {
|
|
15745
15745
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
15746
15746
|
}
|
|
15747
15747
|
}
|
|
15748
15748
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, this.opts.origin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect);
|
|
15749
|
-
this.opts.path =
|
|
15749
|
+
this.opts.path = path18;
|
|
15750
15750
|
this.opts.origin = origin;
|
|
15751
15751
|
this.opts.query = null;
|
|
15752
15752
|
}
|
|
@@ -17574,10 +17574,10 @@ var require_cache_handler = __commonJS({
|
|
|
17574
17574
|
}
|
|
17575
17575
|
return locationUrl.pathname + locationUrl.search;
|
|
17576
17576
|
}
|
|
17577
|
-
function deleteCachedUri(store, cacheKey,
|
|
17577
|
+
function deleteCachedUri(store, cacheKey, path18) {
|
|
17578
17578
|
deleteCachedValue(store, {
|
|
17579
17579
|
...cacheKey,
|
|
17580
|
-
path:
|
|
17580
|
+
path: path18
|
|
17581
17581
|
});
|
|
17582
17582
|
for (let i = 0; i < util.safeHTTPMethods.length; i++) {
|
|
17583
17583
|
const method = util.safeHTTPMethods[i];
|
|
@@ -17585,7 +17585,7 @@ var require_cache_handler = __commonJS({
|
|
|
17585
17585
|
deleteCachedValue(store, {
|
|
17586
17586
|
...cacheKey,
|
|
17587
17587
|
method,
|
|
17588
|
-
path:
|
|
17588
|
+
path: path18
|
|
17589
17589
|
});
|
|
17590
17590
|
}
|
|
17591
17591
|
}
|
|
@@ -17596,9 +17596,9 @@ var require_cache_handler = __commonJS({
|
|
|
17596
17596
|
}
|
|
17597
17597
|
const values = Array.isArray(headerValue) ? headerValue : [headerValue];
|
|
17598
17598
|
for (let i = 0; i < values.length; i++) {
|
|
17599
|
-
const
|
|
17600
|
-
if (
|
|
17601
|
-
deleteCachedUri(store, cacheKey,
|
|
17599
|
+
const path18 = getSameOriginPath(cacheKey, values[i]);
|
|
17600
|
+
if (path18 !== void 0) {
|
|
17601
|
+
deleteCachedUri(store, cacheKey, path18);
|
|
17602
17602
|
}
|
|
17603
17603
|
}
|
|
17604
17604
|
}
|
|
@@ -18758,7 +18758,7 @@ var require_decompress = __commonJS({
|
|
|
18758
18758
|
"../../node_modules/.pnpm/undici@8.10.0/node_modules/undici/lib/interceptor/decompress.js"(exports, module) {
|
|
18759
18759
|
"use strict";
|
|
18760
18760
|
var { createInflate, createGunzip: createGunzip2, createBrotliDecompress, createZstdDecompress } = __require("node:zlib");
|
|
18761
|
-
var { pipeline:
|
|
18761
|
+
var { pipeline: pipeline3 } = __require("node:stream");
|
|
18762
18762
|
var DecoratorHandler = require_decorator_handler();
|
|
18763
18763
|
var supportedEncodings = {
|
|
18764
18764
|
gzip: createGunzip2,
|
|
@@ -18868,7 +18868,7 @@ var require_decompress = __commonJS({
|
|
|
18868
18868
|
#setupMultipleDecompressors(controller) {
|
|
18869
18869
|
const lastDecompressor = this.#decompressors[this.#decompressors.length - 1];
|
|
18870
18870
|
this.#setupDecompressorEvents(lastDecompressor, controller);
|
|
18871
|
-
|
|
18871
|
+
pipeline3(this.#decompressors, (err) => {
|
|
18872
18872
|
if (err) {
|
|
18873
18873
|
super.onResponseError(controller, err);
|
|
18874
18874
|
return;
|
|
@@ -19765,17 +19765,17 @@ var require_sqlite_cache_store = __commonJS({
|
|
|
19765
19765
|
if (now >= value.deleteAt && !canBeExpired) {
|
|
19766
19766
|
continue;
|
|
19767
19767
|
}
|
|
19768
|
-
let
|
|
19768
|
+
let matches2 = true;
|
|
19769
19769
|
if (value.vary) {
|
|
19770
19770
|
const vary = JSON.parse(value.vary);
|
|
19771
19771
|
for (const header in vary) {
|
|
19772
19772
|
if (!headerValueEquals(headers[header], vary[header])) {
|
|
19773
|
-
|
|
19773
|
+
matches2 = false;
|
|
19774
19774
|
break;
|
|
19775
19775
|
}
|
|
19776
19776
|
}
|
|
19777
19777
|
}
|
|
19778
|
-
if (
|
|
19778
|
+
if (matches2) {
|
|
19779
19779
|
return value;
|
|
19780
19780
|
}
|
|
19781
19781
|
}
|
|
@@ -19940,12 +19940,12 @@ var require_headers = __commonJS({
|
|
|
19940
19940
|
append(name, value, isLowerCase) {
|
|
19941
19941
|
this.sortedMap = null;
|
|
19942
19942
|
const lowercaseName = isLowerCase ? name : name.toLowerCase();
|
|
19943
|
-
const
|
|
19944
|
-
if (
|
|
19943
|
+
const exists2 = this.headersMap.get(lowercaseName);
|
|
19944
|
+
if (exists2) {
|
|
19945
19945
|
const delimiter = lowercaseName === "cookie" ? "; " : ", ";
|
|
19946
19946
|
this.headersMap.set(lowercaseName, {
|
|
19947
|
-
name:
|
|
19948
|
-
value: `${
|
|
19947
|
+
name: exists2.name,
|
|
19948
|
+
value: `${exists2.value}${delimiter}${value}`
|
|
19949
19949
|
});
|
|
19950
19950
|
} else {
|
|
19951
19951
|
this.headersMap.set(lowercaseName, { name, value });
|
|
@@ -21662,7 +21662,7 @@ var require_fetch = __commonJS({
|
|
|
21662
21662
|
subresourceSet
|
|
21663
21663
|
} = require_constants3();
|
|
21664
21664
|
var EE = __require("node:events");
|
|
21665
|
-
var { Readable: Readable2, pipeline:
|
|
21665
|
+
var { Readable: Readable2, pipeline: pipeline3, finished, isErrored, isReadable } = __require("node:stream");
|
|
21666
21666
|
var { addAbortListener, bufferToLowerCasedHeaderName } = require_util();
|
|
21667
21667
|
var { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require_data_url();
|
|
21668
21668
|
var { getGlobalDispatcher } = require_global2();
|
|
@@ -22595,13 +22595,13 @@ var require_fetch = __commonJS({
|
|
|
22595
22595
|
function dispatch({ body }) {
|
|
22596
22596
|
const url = requestCurrentURL(request);
|
|
22597
22597
|
const agent = fetchParams.controller.dispatcher;
|
|
22598
|
-
const
|
|
22598
|
+
const path18 = url.pathname + url.search;
|
|
22599
22599
|
const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === "?";
|
|
22600
22600
|
return dispatchWithProtocolPreference(body);
|
|
22601
22601
|
function dispatchWithProtocolPreference(body2, allowH2) {
|
|
22602
22602
|
return new Promise((resolve, reject3) => agent.dispatch(
|
|
22603
22603
|
{
|
|
22604
|
-
path: hasTrailingQuestionMark ? `${
|
|
22604
|
+
path: hasTrailingQuestionMark ? `${path18}?` : path18,
|
|
22605
22605
|
origin: url.origin,
|
|
22606
22606
|
method: request.method,
|
|
22607
22607
|
body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body2,
|
|
@@ -22686,7 +22686,7 @@ var require_fetch = __commonJS({
|
|
|
22686
22686
|
status,
|
|
22687
22687
|
statusText,
|
|
22688
22688
|
headersList,
|
|
22689
|
-
body: decoders.length ?
|
|
22689
|
+
body: decoders.length ? pipeline3(this.body, ...decoders, (err) => {
|
|
22690
22690
|
if (err) {
|
|
22691
22691
|
this.onResponseError(controller, err);
|
|
22692
22692
|
}
|
|
@@ -23513,9 +23513,9 @@ var require_util4 = __commonJS({
|
|
|
23513
23513
|
}
|
|
23514
23514
|
}
|
|
23515
23515
|
}
|
|
23516
|
-
function validateCookiePath(
|
|
23517
|
-
for (let i = 0; i <
|
|
23518
|
-
const code =
|
|
23516
|
+
function validateCookiePath(path18) {
|
|
23517
|
+
for (let i = 0; i < path18.length; ++i) {
|
|
23518
|
+
const code = path18.charCodeAt(i);
|
|
23519
23519
|
if (code < 32 || // exclude CTLs (0-31)
|
|
23520
23520
|
code > 126 || // exclude non-ascii and DEL
|
|
23521
23521
|
code === 59) {
|
|
@@ -26157,7 +26157,7 @@ var require_util6 = __commonJS({
|
|
|
26157
26157
|
var require_eventsource_stream = __commonJS({
|
|
26158
26158
|
"../../node_modules/.pnpm/undici@8.10.0/node_modules/undici/lib/web/eventsource/eventsource-stream.js"(exports, module) {
|
|
26159
26159
|
"use strict";
|
|
26160
|
-
var { Transform:
|
|
26160
|
+
var { Transform: Transform3 } = __require("node:stream");
|
|
26161
26161
|
var { isASCIINumber, isValidLastEventId } = require_util6();
|
|
26162
26162
|
var BOM = [239, 187, 191];
|
|
26163
26163
|
var LF = 10;
|
|
@@ -26198,7 +26198,7 @@ var require_eventsource_stream = __commonJS({
|
|
|
26198
26198
|
}
|
|
26199
26199
|
return true;
|
|
26200
26200
|
}
|
|
26201
|
-
var EventSourceStream = class extends
|
|
26201
|
+
var EventSourceStream = class extends Transform3 {
|
|
26202
26202
|
/**
|
|
26203
26203
|
* @type {eventSourceSettings}
|
|
26204
26204
|
*/
|
|
@@ -26498,7 +26498,7 @@ ${value}`;
|
|
|
26498
26498
|
var require_eventsource = __commonJS({
|
|
26499
26499
|
"../../node_modules/.pnpm/undici@8.10.0/node_modules/undici/lib/web/eventsource/eventsource.js"(exports, module) {
|
|
26500
26500
|
"use strict";
|
|
26501
|
-
var { pipeline:
|
|
26501
|
+
var { pipeline: pipeline3 } = __require("node:stream");
|
|
26502
26502
|
var { fetching } = require_fetch();
|
|
26503
26503
|
var { webidl } = require_webidl();
|
|
26504
26504
|
var { EventSourceStream } = require_eventsource_stream();
|
|
@@ -26648,7 +26648,7 @@ var require_eventsource = __commonJS({
|
|
|
26648
26648
|
));
|
|
26649
26649
|
}
|
|
26650
26650
|
});
|
|
26651
|
-
|
|
26651
|
+
pipeline3(
|
|
26652
26652
|
response.body.stream,
|
|
26653
26653
|
eventSourceStream,
|
|
26654
26654
|
(error) => {
|
|
@@ -26887,11 +26887,11 @@ var require_undici = __commonJS({
|
|
|
26887
26887
|
if (typeof opts.path !== "string") {
|
|
26888
26888
|
throw new InvalidArgumentError("invalid opts.path");
|
|
26889
26889
|
}
|
|
26890
|
-
let
|
|
26890
|
+
let path18 = opts.path;
|
|
26891
26891
|
if (!opts.path.startsWith("/")) {
|
|
26892
|
-
|
|
26892
|
+
path18 = `/${path18}`;
|
|
26893
26893
|
}
|
|
26894
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
26894
|
+
url = new URL(util.parseOrigin(url).origin + path18);
|
|
26895
26895
|
} else {
|
|
26896
26896
|
if (!opts) {
|
|
26897
26897
|
opts = typeof url === "object" ? url : {};
|
|
@@ -39796,20 +39796,20 @@ import { monitorEventLoopDelay as monitorEventLoopDelay2 } from "node:perf_hooks
|
|
|
39796
39796
|
// ../kernel/src/world/default-fs.ts
|
|
39797
39797
|
import fs from "node:fs/promises";
|
|
39798
39798
|
var defaultFs = {
|
|
39799
|
-
stat(
|
|
39800
|
-
return fs.stat(
|
|
39799
|
+
stat(path18) {
|
|
39800
|
+
return fs.stat(path18);
|
|
39801
39801
|
},
|
|
39802
|
-
lstat(
|
|
39803
|
-
return fs.lstat(
|
|
39802
|
+
lstat(path18) {
|
|
39803
|
+
return fs.lstat(path18);
|
|
39804
39804
|
},
|
|
39805
|
-
realpath(
|
|
39806
|
-
return fs.realpath(
|
|
39805
|
+
realpath(path18) {
|
|
39806
|
+
return fs.realpath(path18);
|
|
39807
39807
|
},
|
|
39808
|
-
readFile(
|
|
39809
|
-
return fs.readFile(
|
|
39808
|
+
readFile(path18) {
|
|
39809
|
+
return fs.readFile(path18);
|
|
39810
39810
|
},
|
|
39811
|
-
async readFilePrefix(
|
|
39812
|
-
const handle = await fs.open(
|
|
39811
|
+
async readFilePrefix(path18, bytes) {
|
|
39812
|
+
const handle = await fs.open(path18, "r");
|
|
39813
39813
|
try {
|
|
39814
39814
|
const prefix = Buffer.alloc(bytes);
|
|
39815
39815
|
const { bytesRead } = await handle.read(prefix, 0, bytes, 0);
|
|
@@ -39818,17 +39818,17 @@ var defaultFs = {
|
|
|
39818
39818
|
await handle.close();
|
|
39819
39819
|
}
|
|
39820
39820
|
},
|
|
39821
|
-
async writeFile(
|
|
39822
|
-
await fs.writeFile(
|
|
39821
|
+
async writeFile(path18, data) {
|
|
39822
|
+
await fs.writeFile(path18, data);
|
|
39823
39823
|
},
|
|
39824
|
-
async appendFile(
|
|
39825
|
-
await fs.appendFile(
|
|
39824
|
+
async appendFile(path18, data) {
|
|
39825
|
+
await fs.appendFile(path18, data);
|
|
39826
39826
|
},
|
|
39827
|
-
async mkdir(
|
|
39828
|
-
await fs.mkdir(
|
|
39827
|
+
async mkdir(path18, opts) {
|
|
39828
|
+
await fs.mkdir(path18, opts);
|
|
39829
39829
|
},
|
|
39830
|
-
readdir(
|
|
39831
|
-
return fs.readdir(
|
|
39830
|
+
readdir(path18) {
|
|
39831
|
+
return fs.readdir(path18, { withFileTypes: true });
|
|
39832
39832
|
}
|
|
39833
39833
|
};
|
|
39834
39834
|
|
|
@@ -41157,29 +41157,29 @@ function buildSpillStubText(input) {
|
|
|
41157
41157
|
].join("\n");
|
|
41158
41158
|
}
|
|
41159
41159
|
function assertSpillStoreInvariants() {
|
|
41160
|
-
const
|
|
41160
|
+
const fail2 = (detail) => {
|
|
41161
41161
|
throw new Error(`spill-store 不变式违约(装载期 fail-fast):${detail}`);
|
|
41162
41162
|
};
|
|
41163
41163
|
const nameRe = /^[A-Za-z0-9._-]+$/;
|
|
41164
41164
|
if (!nameRe.test(SPILL_DIR_NAME)) {
|
|
41165
|
-
|
|
41165
|
+
fail2(`SPILL_DIR_NAME 必须为安全文件名词形,得到 ${JSON.stringify(SPILL_DIR_NAME)}`);
|
|
41166
41166
|
}
|
|
41167
41167
|
if (!nameRe.test(SPILL_PRUNE_FILE_PREFIX)) {
|
|
41168
|
-
|
|
41168
|
+
fail2(`SPILL_PRUNE_FILE_PREFIX 必须为安全文件名词形,得到 ${JSON.stringify(SPILL_PRUNE_FILE_PREFIX)}`);
|
|
41169
41169
|
}
|
|
41170
41170
|
if (!Number.isInteger(SPILL_HASH_HEX_CHARS) || SPILL_HASH_HEX_CHARS < 16 || SPILL_HASH_HEX_CHARS > 64) {
|
|
41171
|
-
|
|
41171
|
+
fail2(`SPILL_HASH_HEX_CHARS 必须在 [16, 64](sha256 hex 截断域),得到 ${SPILL_HASH_HEX_CHARS}`);
|
|
41172
41172
|
}
|
|
41173
41173
|
const emptyHash = hashSpillContent("");
|
|
41174
41174
|
if (emptyHash !== "e3b0c44298fc1c149afbf4c8996fb924".slice(0, SPILL_HASH_HEX_CHARS)) {
|
|
41175
|
-
|
|
41175
|
+
fail2(`hashSpillContent 算法漂移:sha256('') 截断应为公知值,得到 ${emptyHash}`);
|
|
41176
41176
|
}
|
|
41177
41177
|
if (spillFileName("content", emptyHash) === spillFileName("prune", emptyHash)) {
|
|
41178
|
-
|
|
41178
|
+
fail2("content 与 prune 命名空间的文件名必须互异");
|
|
41179
41179
|
}
|
|
41180
41180
|
const sample = buildSpillStubText({ path: "X:/s/spill/abc.txt", totalChars: 12345 });
|
|
41181
41181
|
if (!sample.includes("12345") || !sample.includes("X:/s/spill/abc.txt") || !sample.includes("Read")) {
|
|
41182
|
-
|
|
41182
|
+
fail2("buildSpillStubText 必须恒含原始规模、真实路径与 Read 指引");
|
|
41183
41183
|
}
|
|
41184
41184
|
}
|
|
41185
41185
|
assertSpillStoreInvariants();
|
|
@@ -42043,63 +42043,63 @@ var CONTEXT_BUDGET_REMINDER_CRITICAL_FRACTION = 0.1;
|
|
|
42043
42043
|
var CONTEXT_BUDGET_REMINDER_ROUND_TOKENS = 1e3;
|
|
42044
42044
|
var CONTEXT_BUDGET_REMINDER_MIN_BUDGET_TOKENS = 2e4;
|
|
42045
42045
|
function assertEntryBudgetInvariants() {
|
|
42046
|
-
const
|
|
42046
|
+
const fail2 = (detail) => {
|
|
42047
42047
|
throw new Error(`entry-budgets 不变式违约(装载期 fail-fast):${detail}`);
|
|
42048
42048
|
};
|
|
42049
42049
|
if (DEFAULT_TOOL_RESULT_BUDGET_CHARS !== 5e4) {
|
|
42050
|
-
|
|
42050
|
+
fail2(
|
|
42051
42051
|
`DEFAULT_TOOL_RESULT_BUDGET_CHARS 必须为 50000(用户拍板 2026-08-21 维持不动),得到 ${DEFAULT_TOOL_RESULT_BUDGET_CHARS}`
|
|
42052
42052
|
);
|
|
42053
42053
|
}
|
|
42054
42054
|
if (PERSISTED_PREVIEW_HEAD_CHARS + PERSISTED_PREVIEW_TAIL_CHARS >= DEFAULT_TOOL_RESULT_BUDGET_CHARS) {
|
|
42055
|
-
|
|
42055
|
+
fail2("clamp 存根预览(head+tail)必须严格小于工具结果预算");
|
|
42056
42056
|
}
|
|
42057
42057
|
for (const [name, value] of [
|
|
42058
42058
|
["READ_MAX_LINES", READ_MAX_LINES],
|
|
42059
42059
|
["READ_MAX_LINE_CHARS", READ_MAX_LINE_CHARS],
|
|
42060
42060
|
["READ_MAX_FULL_BYTES", READ_MAX_FULL_BYTES]
|
|
42061
42061
|
]) {
|
|
42062
|
-
if (!Number.isInteger(value) || value <= 0)
|
|
42062
|
+
if (!Number.isInteger(value) || value <= 0) fail2(`${name} 必须为正整数,得到 ${value}`);
|
|
42063
42063
|
}
|
|
42064
42064
|
if (!Number.isInteger(PRUNE_MIN_RESULT_CHARS) || !Number.isInteger(PRUNE_HEAD_CHARS) || !Number.isInteger(PRUNE_TAIL_CHARS) || PRUNE_HEAD_CHARS < 0 || PRUNE_TAIL_CHARS < 0 || PRUNE_MIN_RESULT_CHARS <= 0) {
|
|
42065
|
-
|
|
42065
|
+
fail2("剪枝常量必须为非负整数且门槛为正");
|
|
42066
42066
|
}
|
|
42067
42067
|
if (PRUNE_HEAD_CHARS + PRUNE_TAIL_CHARS + PRUNE_MARKER_MAX_CHARS >= PRUNE_MIN_RESULT_CHARS) {
|
|
42068
|
-
|
|
42068
|
+
fail2(
|
|
42069
42069
|
`剪后产物上界(head ${PRUNE_HEAD_CHARS} + tail ${PRUNE_TAIL_CHARS} + 标记 ≤${PRUNE_MARKER_MAX_CHARS})必须严格小于剪枝门槛 ${PRUNE_MIN_RESULT_CHARS}——否则剪后仍是候选,重复触发字节漂移`
|
|
42070
42070
|
);
|
|
42071
42071
|
}
|
|
42072
42072
|
if (PRUNE_MIN_RESULT_CHARS >= DEFAULT_TOOL_RESULT_BUDGET_CHARS) {
|
|
42073
|
-
|
|
42073
|
+
fail2("剪枝门槛必须低于工具结果 clamp 预算(50K 之上无剪枝对象)");
|
|
42074
42074
|
}
|
|
42075
42075
|
if (!Number.isInteger(SUBAGENT_SUMMARY_MAX_TOKENS) || SUBAGENT_SUMMARY_MAX_TOKENS <= 0) {
|
|
42076
|
-
|
|
42076
|
+
fail2(`SUBAGENT_SUMMARY_MAX_TOKENS 必须为正整数,得到 ${SUBAGENT_SUMMARY_MAX_TOKENS}`);
|
|
42077
42077
|
}
|
|
42078
42078
|
if (!Number.isInteger(DEFAULT_OUTPUT_CAP_TOKENS) || DEFAULT_OUTPUT_CAP_TOKENS < 1024) {
|
|
42079
|
-
|
|
42079
|
+
fail2(`DEFAULT_OUTPUT_CAP_TOKENS 必须为 ≥1024 的整数(输出预算地板),得到 ${DEFAULT_OUTPUT_CAP_TOKENS}`);
|
|
42080
42080
|
}
|
|
42081
42081
|
if (!Number.isInteger(OUTPUT_CAP_ESCALATION_TOKENS) || OUTPUT_CAP_ESCALATION_TOKENS <= DEFAULT_OUTPUT_CAP_TOKENS) {
|
|
42082
|
-
|
|
42082
|
+
fail2(
|
|
42083
42083
|
`OUTPUT_CAP_ESCALATION_TOKENS(${OUTPUT_CAP_ESCALATION_TOKENS})必须为严格大于缺省输出帽 ${DEFAULT_OUTPUT_CAP_TOKENS} 的整数——否则触帽升档恒无增益`
|
|
42084
42084
|
);
|
|
42085
42085
|
}
|
|
42086
42086
|
if (!(CONTEXT_BUDGET_REMINDER_CRITICAL_FRACTION > 0) || !(CONTEXT_BUDGET_REMINDER_CRITICAL_FRACTION < CONTEXT_BUDGET_REMINDER_LOW_FRACTION) || !(CONTEXT_BUDGET_REMINDER_LOW_FRACTION < 1)) {
|
|
42087
|
-
|
|
42087
|
+
fail2(
|
|
42088
42088
|
`预算提醒档位必须满足 0 < critical(${CONTEXT_BUDGET_REMINDER_CRITICAL_FRACTION}) < low(${CONTEXT_BUDGET_REMINDER_LOW_FRACTION}) < 1`
|
|
42089
42089
|
);
|
|
42090
42090
|
}
|
|
42091
42091
|
if (!Number.isInteger(CONTEXT_BUDGET_REMINDER_ROUND_TOKENS) || CONTEXT_BUDGET_REMINDER_ROUND_TOKENS <= 0) {
|
|
42092
|
-
|
|
42092
|
+
fail2(
|
|
42093
42093
|
`CONTEXT_BUDGET_REMINDER_ROUND_TOKENS 必须为正整数,得到 ${CONTEXT_BUDGET_REMINDER_ROUND_TOKENS}`
|
|
42094
42094
|
);
|
|
42095
42095
|
}
|
|
42096
42096
|
if (!Number.isInteger(CONTEXT_BUDGET_REMINDER_MIN_BUDGET_TOKENS) || CONTEXT_BUDGET_REMINDER_MIN_BUDGET_TOKENS < CONTEXT_BUDGET_REMINDER_ROUND_TOKENS) {
|
|
42097
|
-
|
|
42097
|
+
fail2(
|
|
42098
42098
|
`CONTEXT_BUDGET_REMINDER_MIN_BUDGET_TOKENS(${CONTEXT_BUDGET_REMINDER_MIN_BUDGET_TOKENS})必须为 ≥ 取整粒度 ${CONTEXT_BUDGET_REMINDER_ROUND_TOKENS} 的整数`
|
|
42099
42099
|
);
|
|
42100
42100
|
}
|
|
42101
42101
|
if (EMPTY_TOOL_RESULT_TEXT.length === 0 || EMPTY_TOOL_ERROR_TEXT.length === 0) {
|
|
42102
|
-
|
|
42102
|
+
fail2("空结果短桩短语不得为空串");
|
|
42103
42103
|
}
|
|
42104
42104
|
}
|
|
42105
42105
|
assertEntryBudgetInvariants();
|
|
@@ -42303,74 +42303,74 @@ var LIFECYCLE_REPLAY_ORDER = [
|
|
|
42303
42303
|
"evict"
|
|
42304
42304
|
];
|
|
42305
42305
|
function assertHistoryLifecycleInvariants() {
|
|
42306
|
-
const
|
|
42306
|
+
const fail2 = (detail) => {
|
|
42307
42307
|
throw new Error(`历史生命周期状态机不变式违约(装载期 fail-fast):${detail}`);
|
|
42308
42308
|
};
|
|
42309
42309
|
if (new Set(HISTORY_LIFECYCLE_STATES).size !== HISTORY_LIFECYCLE_STATES.length) {
|
|
42310
|
-
|
|
42310
|
+
fail2("态集成员必须互异");
|
|
42311
42311
|
}
|
|
42312
42312
|
if (!PRUNE_MARKER_PREFIX.startsWith("[") || PRUNE_MARKER_PREFIX.length < 8) {
|
|
42313
|
-
|
|
42313
|
+
fail2(`PRUNE_MARKER_PREFIX 词形异常(冻结字节被改动):${JSON.stringify(PRUNE_MARKER_PREFIX)}`);
|
|
42314
42314
|
}
|
|
42315
42315
|
const ids = /* @__PURE__ */ new Set();
|
|
42316
42316
|
let lastStage = -1;
|
|
42317
42317
|
const stateIndex = (s) => HISTORY_LIFECYCLE_STATES.indexOf(s);
|
|
42318
42318
|
for (const transition of LIFECYCLE_TRANSITIONS) {
|
|
42319
|
-
if (ids.has(transition.id))
|
|
42319
|
+
if (ids.has(transition.id)) fail2(`迁移 id 重复:${transition.id}`);
|
|
42320
42320
|
ids.add(transition.id);
|
|
42321
42321
|
if (transition.stage <= lastStage) {
|
|
42322
|
-
|
|
42322
|
+
fail2(`迁移 stage 必须严格递增(全序仲裁的根):${transition.id} stage=${transition.stage}`);
|
|
42323
42323
|
}
|
|
42324
42324
|
lastStage = transition.stage;
|
|
42325
42325
|
const toIndex = stateIndex(transition.to);
|
|
42326
|
-
if (toIndex < 0)
|
|
42326
|
+
if (toIndex < 0) fail2(`迁移 ${transition.id} 目标态不在态集:${transition.to}`);
|
|
42327
42327
|
if (transition.from !== "ingestion") {
|
|
42328
42328
|
for (const from of transition.from) {
|
|
42329
|
-
if (stateIndex(from) < 0)
|
|
42329
|
+
if (stateIndex(from) < 0) fail2(`迁移 ${transition.id} 源态不在态集:${from}`);
|
|
42330
42330
|
if (stateIndex(from) >= toIndex) {
|
|
42331
|
-
|
|
42331
|
+
fail2(`迁移 ${transition.id} 违反单向前进(${from} → ${transition.to}):恒无复活迁移`);
|
|
42332
42332
|
}
|
|
42333
42333
|
}
|
|
42334
42334
|
}
|
|
42335
42335
|
}
|
|
42336
42336
|
for (const id of [...LIFECYCLE_BARRIER_ORDER, ...LIFECYCLE_REPLAY_ORDER]) {
|
|
42337
|
-
if (!ids.has(id))
|
|
42337
|
+
if (!ids.has(id)) fail2(`仲裁/重演序引用未登记迁移:${id}`);
|
|
42338
42338
|
}
|
|
42339
42339
|
if (!Number.isInteger(DEFAULT_KEEP_RECENT_ROUNDS) || DEFAULT_KEEP_RECENT_ROUNDS < 1) {
|
|
42340
|
-
|
|
42340
|
+
fail2(`DEFAULT_KEEP_RECENT_ROUNDS 必须为 ≥1 整数,得到 ${DEFAULT_KEEP_RECENT_ROUNDS}`);
|
|
42341
42341
|
}
|
|
42342
42342
|
if (!Number.isInteger(DEFAULT_MICROCOMPACT_KEEP_RECENT_TOOL_RESULTS) || DEFAULT_MICROCOMPACT_KEEP_RECENT_TOOL_RESULTS < 1) {
|
|
42343
|
-
|
|
42343
|
+
fail2(
|
|
42344
42344
|
`DEFAULT_MICROCOMPACT_KEEP_RECENT_TOOL_RESULTS 必须为 ≥1 整数,得到 ${DEFAULT_MICROCOMPACT_KEEP_RECENT_TOOL_RESULTS}`
|
|
42345
42345
|
);
|
|
42346
42346
|
}
|
|
42347
42347
|
if (!Number.isInteger(DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS) || DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS <= 0) {
|
|
42348
|
-
|
|
42348
|
+
fail2(
|
|
42349
42349
|
`DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS 必须为正整数,得到 ${DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS}`
|
|
42350
42350
|
);
|
|
42351
42351
|
}
|
|
42352
42352
|
if (PRUNE_MIN_RESULT_CHARS <= DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS) {
|
|
42353
|
-
|
|
42353
|
+
fail2(
|
|
42354
42354
|
`剪枝门槛(${PRUNE_MIN_RESULT_CHARS})必须严格大于淘汰门槛(${DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS}):prune 是 evict 的前置温和档`
|
|
42355
42355
|
);
|
|
42356
42356
|
}
|
|
42357
42357
|
if (PRUNE_HEAD_CHARS + PRUNE_TAIL_CHARS < DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS) {
|
|
42358
|
-
|
|
42358
|
+
fail2(
|
|
42359
42359
|
`剪后产物下界(head ${PRUNE_HEAD_CHARS} + tail ${PRUNE_TAIL_CHARS})必须 ≥ 淘汰门槛 ${DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS}——否则 pruned 态脱离 evict 候选域,两档接力断链`
|
|
42360
42360
|
);
|
|
42361
42361
|
}
|
|
42362
42362
|
if (DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS >= DEFAULT_TOOL_RESULT_BUDGET_CHARS) {
|
|
42363
|
-
|
|
42363
|
+
fail2(
|
|
42364
42364
|
`淘汰门槛(${DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS})必须小于入史 clamp 预算(${DEFAULT_TOOL_RESULT_BUDGET_CHARS}):淘汰重演的文件在场性判据依赖两带不重叠`
|
|
42365
42365
|
);
|
|
42366
42366
|
}
|
|
42367
42367
|
if (DEGRADED_ESCALATED_KEEP_RECENT_TOOL_RESULTS > DEFAULT_MICROCOMPACT_KEEP_RECENT_TOOL_RESULTS) {
|
|
42368
|
-
|
|
42368
|
+
fail2(
|
|
42369
42369
|
`劣化升级保护窗(${DEGRADED_ESCALATED_KEEP_RECENT_TOOL_RESULTS})不得大于默认窗(${DEFAULT_MICROCOMPACT_KEEP_RECENT_TOOL_RESULTS}):升级恒收窄`
|
|
42370
42370
|
);
|
|
42371
42371
|
}
|
|
42372
42372
|
if (DEGRADED_ESCALATED_MIN_RESULT_CHARS > DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS) {
|
|
42373
|
-
|
|
42373
|
+
fail2(
|
|
42374
42374
|
`劣化升级淘汰门槛(${DEGRADED_ESCALATED_MIN_RESULT_CHARS})不得大于默认门槛(${DEFAULT_MICROCOMPACT_MIN_RESULT_CHARS}):升级恒收窄`
|
|
42375
42375
|
);
|
|
42376
42376
|
}
|
|
@@ -47485,18 +47485,18 @@ function postCompactReminderInvalidation(provider) {
|
|
|
47485
47485
|
if (typeof reset !== "function") return void 0;
|
|
47486
47486
|
return { id: "reminders.firstScreenBaselines", run: () => reset() };
|
|
47487
47487
|
}
|
|
47488
|
-
function defaultStatMtimeMs(
|
|
47488
|
+
function defaultStatMtimeMs(path18) {
|
|
47489
47489
|
try {
|
|
47490
|
-
return statSync(
|
|
47490
|
+
return statSync(path18).mtimeMs;
|
|
47491
47491
|
} catch {
|
|
47492
47492
|
return void 0;
|
|
47493
47493
|
}
|
|
47494
47494
|
}
|
|
47495
47495
|
function createReminderProvider(options = {}) {
|
|
47496
|
-
const
|
|
47496
|
+
const stat11 = options.statMtimeMs ?? defaultStatMtimeMs;
|
|
47497
47497
|
const memoryPaths = options.memoryPaths ?? [];
|
|
47498
47498
|
const mtimes = /* @__PURE__ */ new Map();
|
|
47499
|
-
for (const
|
|
47499
|
+
for (const path18 of memoryPaths) mtimes.set(path18, stat11(path18));
|
|
47500
47500
|
let lastTodoSerialized;
|
|
47501
47501
|
let securityNotePending = memoryPaths.length > 0;
|
|
47502
47502
|
let lastSeenModelTurns = Number.POSITIVE_INFINITY;
|
|
@@ -47509,12 +47509,12 @@ function createReminderProvider(options = {}) {
|
|
|
47509
47509
|
out.push(makeReminder("security_note", { sources: [...memoryPaths] }));
|
|
47510
47510
|
}
|
|
47511
47511
|
const changes = [];
|
|
47512
|
-
for (const
|
|
47513
|
-
const prev = mtimes.get(
|
|
47514
|
-
const current =
|
|
47512
|
+
for (const path18 of memoryPaths) {
|
|
47513
|
+
const prev = mtimes.get(path18);
|
|
47514
|
+
const current = stat11(path18);
|
|
47515
47515
|
if (current === prev) continue;
|
|
47516
|
-
mtimes.set(
|
|
47517
|
-
changes.push({ path:
|
|
47516
|
+
mtimes.set(path18, current);
|
|
47517
|
+
changes.push({ path: path18, change: current === void 0 ? "removed" : "modified" });
|
|
47518
47518
|
}
|
|
47519
47519
|
if (changes.length > 0) {
|
|
47520
47520
|
out.push(makeReminder("memory_change", { changes }));
|
|
@@ -49557,10 +49557,10 @@ function matchHardSafety(input, config = {}) {
|
|
|
49557
49557
|
if (typeof command !== "string") return null;
|
|
49558
49558
|
const structure = parseCommandStructure(command);
|
|
49559
49559
|
if (!structure.ok) return null;
|
|
49560
|
-
for (const
|
|
49561
|
-
const hasEgress =
|
|
49560
|
+
for (const pipeline3 of structure.pipelines) {
|
|
49561
|
+
const hasEgress = pipeline3.commands.some((c) => isEgressCommand(c, extraEgress));
|
|
49562
49562
|
if (!hasEgress) continue;
|
|
49563
|
-
const refsSecret =
|
|
49563
|
+
const refsSecret = pipeline3.commands.some((c) => nodeReferencesSecret(c, input.cwd));
|
|
49564
49564
|
if (refsSecret) {
|
|
49565
49565
|
return {
|
|
49566
49566
|
label: "secret-egress",
|
|
@@ -49654,13 +49654,13 @@ function canonicalCwd(cwd) {
|
|
|
49654
49654
|
const resolved = resolveForPermission(cwd, ".");
|
|
49655
49655
|
return resolved.kind === "ok" ? resolved.path : null;
|
|
49656
49656
|
}
|
|
49657
|
-
function canonicalPathEligible(cwdCanon,
|
|
49658
|
-
if (hasWindowsDeviceSegment(
|
|
49659
|
-
if (
|
|
49660
|
-
if (!
|
|
49661
|
-
if (guard.isProtectedContentPath(
|
|
49662
|
-
if (matchProtectedPath(
|
|
49663
|
-
const segments =
|
|
49657
|
+
function canonicalPathEligible(cwdCanon, path18, policy, guard) {
|
|
49658
|
+
if (hasWindowsDeviceSegment(path18)) return false;
|
|
49659
|
+
if (path18 === cwdCanon) return !policy.strict;
|
|
49660
|
+
if (!path18.startsWith(`${cwdCanon}/`)) return false;
|
|
49661
|
+
if (guard.isProtectedContentPath(path18)) return false;
|
|
49662
|
+
if (matchProtectedPath(path18, null) !== null) return false;
|
|
49663
|
+
const segments = path18.slice(cwdCanon.length + 1).split("/");
|
|
49664
49664
|
for (const [index, seg] of segments.entries()) {
|
|
49665
49665
|
const hasGlob = GLOB_CHAR_RE.test(seg);
|
|
49666
49666
|
if (hasGlob && seg.startsWith(".")) return false;
|
|
@@ -49844,9 +49844,9 @@ function verifyBundle(bundle, opts = {}) {
|
|
|
49844
49844
|
// ../kernel/src/permissions/soften-radius.ts
|
|
49845
49845
|
var PROTECTED_PATH_RULE_PREFIX = "protected-path(";
|
|
49846
49846
|
var MCP_TOOL_PREFIX = "mcp__";
|
|
49847
|
-
function pathInsideRoot(
|
|
49847
|
+
function pathInsideRoot(path18, root) {
|
|
49848
49848
|
if (root === null) return false;
|
|
49849
|
-
return
|
|
49849
|
+
return path18 === root || path18.startsWith(root.endsWith("/") ? root : `${root}/`);
|
|
49850
49850
|
}
|
|
49851
49851
|
function classifySoftenFace(input, base) {
|
|
49852
49852
|
if (base.matchedRule?.startsWith(PROTECTED_PATH_RULE_PREFIX) === true) return "F6";
|
|
@@ -51796,14 +51796,14 @@ var DispatchingToolExecutor = class _DispatchingToolExecutor {
|
|
|
51796
51796
|
let internalError;
|
|
51797
51797
|
const onCtxAbort = () => wake.wake();
|
|
51798
51798
|
ctx.signal.addEventListener("abort", onCtxAbort, { once: true });
|
|
51799
|
-
const
|
|
51799
|
+
const drain2 = function* () {
|
|
51800
51800
|
while (queued.length > 0) {
|
|
51801
51801
|
yield { t: "event", body: queued.shift() };
|
|
51802
51802
|
}
|
|
51803
51803
|
};
|
|
51804
51804
|
const waitUntil = async function* (cond) {
|
|
51805
51805
|
for (; ; ) {
|
|
51806
|
-
yield*
|
|
51806
|
+
yield* drain2();
|
|
51807
51807
|
if (cond()) return;
|
|
51808
51808
|
await wake.wait();
|
|
51809
51809
|
}
|
|
@@ -51831,7 +51831,7 @@ var DispatchingToolExecutor = class _DispatchingToolExecutor {
|
|
|
51831
51831
|
};
|
|
51832
51832
|
for (let i = 0; i < calls.length; i++) {
|
|
51833
51833
|
let call = calls[i];
|
|
51834
|
-
yield*
|
|
51834
|
+
yield* drain2();
|
|
51835
51835
|
if (ctx.signal.aborted) {
|
|
51836
51836
|
sawAbort = true;
|
|
51837
51837
|
fillSyntheticFrom(i);
|
|
@@ -52258,7 +52258,7 @@ var DispatchingToolExecutor = class _DispatchingToolExecutor {
|
|
|
52258
52258
|
}
|
|
52259
52259
|
try {
|
|
52260
52260
|
yield* waitUntil(() => inFlight === 0);
|
|
52261
|
-
yield*
|
|
52261
|
+
yield* drain2();
|
|
52262
52262
|
} finally {
|
|
52263
52263
|
ctx.signal.removeEventListener("abort", onCtxAbort);
|
|
52264
52264
|
}
|
|
@@ -52538,10 +52538,10 @@ async function renameWithRetry(from, to, deps = defaultRenameDeps) {
|
|
|
52538
52538
|
await deps.rename(from, to);
|
|
52539
52539
|
return;
|
|
52540
52540
|
} catch (err) {
|
|
52541
|
-
const
|
|
52541
|
+
const delay2 = RENAME_RETRY_DELAYS_MS[attempt];
|
|
52542
52542
|
const transient = deps.platform === "win32" && isErrnoException(err) && err.code !== void 0 && RENAME_TRANSIENT_CODES.has(err.code);
|
|
52543
|
-
if (!transient ||
|
|
52544
|
-
await deps.sleep(
|
|
52543
|
+
if (!transient || delay2 === void 0) throw err;
|
|
52544
|
+
await deps.sleep(delay2);
|
|
52545
52545
|
}
|
|
52546
52546
|
}
|
|
52547
52547
|
}
|
|
@@ -52810,13 +52810,13 @@ async function externalizeOne(block, sessionDir) {
|
|
|
52810
52810
|
const bytes = Buffer.from(block["data"], "base64");
|
|
52811
52811
|
const hex = createHash8("sha256").update(bytes).digest("hex");
|
|
52812
52812
|
const file = attachmentFilePath(sessionDir, hex);
|
|
52813
|
-
let
|
|
52813
|
+
let exists2 = true;
|
|
52814
52814
|
try {
|
|
52815
52815
|
await access(file);
|
|
52816
52816
|
} catch {
|
|
52817
|
-
|
|
52817
|
+
exists2 = false;
|
|
52818
52818
|
}
|
|
52819
|
-
if (!
|
|
52819
|
+
if (!exists2) {
|
|
52820
52820
|
await mkdir2(attachmentsDirPath(sessionDir), { recursive: true });
|
|
52821
52821
|
await writeFileDurable(file, bytes);
|
|
52822
52822
|
}
|
|
@@ -53116,13 +53116,13 @@ async function effectiveSegments(sessionDir, manifest) {
|
|
|
53116
53116
|
out.push(segment);
|
|
53117
53117
|
continue;
|
|
53118
53118
|
}
|
|
53119
|
-
let
|
|
53119
|
+
let exists2 = true;
|
|
53120
53120
|
try {
|
|
53121
53121
|
await stat2(segmentFilePath(sessionDir, segment.n));
|
|
53122
53122
|
} catch {
|
|
53123
|
-
|
|
53123
|
+
exists2 = false;
|
|
53124
53124
|
}
|
|
53125
|
-
if (isSegmentEffective(segment,
|
|
53125
|
+
if (isSegmentEffective(segment, exists2)) out.push(segment);
|
|
53126
53126
|
}
|
|
53127
53127
|
return out;
|
|
53128
53128
|
}
|
|
@@ -53399,9 +53399,9 @@ async function settleManifest(sessionDir) {
|
|
|
53399
53399
|
segments.push(segment);
|
|
53400
53400
|
continue;
|
|
53401
53401
|
}
|
|
53402
|
-
const
|
|
53402
|
+
const exists2 = await fileExists(segmentFilePath(sessionDir, segment.n));
|
|
53403
53403
|
changed = true;
|
|
53404
|
-
if (isSegmentEffective(segment,
|
|
53404
|
+
if (isSegmentEffective(segment, exists2)) segments.push({ ...segment, status: "sealed" });
|
|
53405
53405
|
}
|
|
53406
53406
|
const last = segments[segments.length - 1];
|
|
53407
53407
|
const liveFirstSeq = last === void 0 ? 0 : last.lastSeq + 1;
|
|
@@ -54043,8 +54043,8 @@ var VERSIONED_MANIFEST = /\/manifest\.g\d{9}-[0-9a-f]+\.json$/;
|
|
|
54043
54043
|
function isManifestObjectKey(key2) {
|
|
54044
54044
|
return key2.endsWith(`/${MANIFEST_OBJECT_NAME}`) || VERSIONED_MANIFEST.test(key2);
|
|
54045
54045
|
}
|
|
54046
|
-
function segmentKey(ref, segment, codec,
|
|
54047
|
-
return `${volumePrefix(ref)}seg-${String(segment.n).padStart(6, "0")}-${segment.firstSeq}-${segment.lastSeq}-${
|
|
54046
|
+
function segmentKey(ref, segment, codec, sha2562) {
|
|
54047
|
+
return `${volumePrefix(ref)}seg-${String(segment.n).padStart(6, "0")}-${segment.firstSeq}-${segment.lastSeq}-${sha2562.slice(0, 12)}.${codecFileExtension(codec)}`;
|
|
54048
54048
|
}
|
|
54049
54049
|
function deriveVolumeId(segments) {
|
|
54050
54050
|
const first = segments.find((s) => s.n === 1);
|
|
@@ -54527,9 +54527,881 @@ function createColdManifestStore(options) {
|
|
|
54527
54527
|
};
|
|
54528
54528
|
}
|
|
54529
54529
|
|
|
54530
|
+
// ../kernel/src/journal/segmented/fs-blob-store.ts
|
|
54531
|
+
import { createHash as createHash11, randomBytes as randomBytes2 } from "node:crypto";
|
|
54532
|
+
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2 } from "node:fs";
|
|
54533
|
+
import { link, mkdir as mkdir4, readdir, readFile as readFile6, rm as rm5, stat as stat3 } from "node:fs/promises";
|
|
54534
|
+
import path8 from "node:path";
|
|
54535
|
+
import { Transform as Transform2 } from "node:stream";
|
|
54536
|
+
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
54537
|
+
var KEY_PART2 = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
54538
|
+
function fsKeyParts(key2) {
|
|
54539
|
+
if (key2.length === 0 || key2.includes("\\") || key2.startsWith("/") || key2.endsWith("/")) {
|
|
54540
|
+
throw new StoreError("permanent", `非法对象键 ${JSON.stringify(key2)}:禁空键 / 反斜杠 / 首尾分隔符`);
|
|
54541
|
+
}
|
|
54542
|
+
const parts = key2.split("/");
|
|
54543
|
+
for (const part of parts) {
|
|
54544
|
+
if (!KEY_PART2.test(part) || part === "." || part === "..") {
|
|
54545
|
+
throw new StoreError("permanent", `非法对象键段 ${JSON.stringify(part)}(键 ${JSON.stringify(key2)}):仅允许字母数字与 . _ -,且须以字母数字开头`);
|
|
54546
|
+
}
|
|
54547
|
+
}
|
|
54548
|
+
return parts;
|
|
54549
|
+
}
|
|
54550
|
+
async function exists(p) {
|
|
54551
|
+
try {
|
|
54552
|
+
await stat3(p);
|
|
54553
|
+
return true;
|
|
54554
|
+
} catch {
|
|
54555
|
+
return false;
|
|
54556
|
+
}
|
|
54557
|
+
}
|
|
54558
|
+
var KeyLocks = class {
|
|
54559
|
+
#tails = /* @__PURE__ */ new Map();
|
|
54560
|
+
async run(key2, op) {
|
|
54561
|
+
const prev = this.#tails.get(key2) ?? Promise.resolve();
|
|
54562
|
+
let release;
|
|
54563
|
+
const mine = new Promise((resolve) => {
|
|
54564
|
+
release = resolve;
|
|
54565
|
+
});
|
|
54566
|
+
const tail = prev.then(() => mine);
|
|
54567
|
+
this.#tails.set(key2, tail);
|
|
54568
|
+
await prev;
|
|
54569
|
+
try {
|
|
54570
|
+
return await op();
|
|
54571
|
+
} finally {
|
|
54572
|
+
release();
|
|
54573
|
+
if (this.#tails.get(key2) === tail) this.#tails.delete(key2);
|
|
54574
|
+
}
|
|
54575
|
+
}
|
|
54576
|
+
};
|
|
54577
|
+
function createFsBlobStore(options) {
|
|
54578
|
+
const root = path8.resolve(options.dir);
|
|
54579
|
+
const objectsDir = path8.join(root, "objects");
|
|
54580
|
+
const metaDir = path8.join(root, "meta");
|
|
54581
|
+
const tmpDir = path8.join(root, "tmp");
|
|
54582
|
+
const capabilities = {
|
|
54583
|
+
consistency: "strong",
|
|
54584
|
+
conditionalPut: true,
|
|
54585
|
+
rangeGet: true,
|
|
54586
|
+
maxObjectBytes: Number.MAX_SAFE_INTEGER,
|
|
54587
|
+
list: "prefix",
|
|
54588
|
+
batchDelete: 1e3,
|
|
54589
|
+
...options.capabilities
|
|
54590
|
+
};
|
|
54591
|
+
const locks = new KeyLocks();
|
|
54592
|
+
let prepared = null;
|
|
54593
|
+
const prepare = () => {
|
|
54594
|
+
prepared ??= (async () => {
|
|
54595
|
+
await mkdir4(objectsDir, { recursive: true });
|
|
54596
|
+
await mkdir4(metaDir, { recursive: true });
|
|
54597
|
+
await rm5(tmpDir, { recursive: true, force: true }).catch(() => void 0);
|
|
54598
|
+
await mkdir4(tmpDir, { recursive: true });
|
|
54599
|
+
})();
|
|
54600
|
+
return prepared;
|
|
54601
|
+
};
|
|
54602
|
+
const objectPath = (key2) => path8.join(objectsDir, ...fsKeyParts(key2));
|
|
54603
|
+
const metaPath = (key2) => `${path8.join(metaDir, ...fsKeyParts(key2))}.json`;
|
|
54604
|
+
async function readMeta(key2) {
|
|
54605
|
+
let raw;
|
|
54606
|
+
try {
|
|
54607
|
+
raw = await readFile6(metaPath(key2), "utf8");
|
|
54608
|
+
} catch (err) {
|
|
54609
|
+
if (isErrnoException(err) && err.code === "ENOENT") return null;
|
|
54610
|
+
throw toStoreError(err);
|
|
54611
|
+
}
|
|
54612
|
+
try {
|
|
54613
|
+
return JSON.parse(raw);
|
|
54614
|
+
} catch {
|
|
54615
|
+
throw new StoreError("permanent", `对象 meta 损坏:${key2}`);
|
|
54616
|
+
}
|
|
54617
|
+
}
|
|
54618
|
+
async function spool(body, signal) {
|
|
54619
|
+
const tmp = path8.join(tmpDir, `${process.pid.toString(36)}-${randomBytes2(8).toString("hex")}`);
|
|
54620
|
+
const hash = createHash11("sha256");
|
|
54621
|
+
let bytes = 0;
|
|
54622
|
+
const counter = new Transform2({
|
|
54623
|
+
transform(chunk, _enc, callback) {
|
|
54624
|
+
hash.update(chunk);
|
|
54625
|
+
bytes += chunk.length;
|
|
54626
|
+
callback(null, chunk);
|
|
54627
|
+
}
|
|
54628
|
+
});
|
|
54629
|
+
try {
|
|
54630
|
+
await pipeline2(webToNode(body), counter, createWriteStream2(tmp), signal === void 0 ? {} : { signal });
|
|
54631
|
+
} catch (err) {
|
|
54632
|
+
await rm5(tmp, { force: true }).catch(() => void 0);
|
|
54633
|
+
if (signal?.aborted === true || err instanceof Error && err.name === "AbortError") {
|
|
54634
|
+
throw new StoreError("transient", "aborted", { cause: err });
|
|
54635
|
+
}
|
|
54636
|
+
throw toStoreError(err);
|
|
54637
|
+
}
|
|
54638
|
+
return { tmp, sha256: hash.digest("hex"), bytes };
|
|
54639
|
+
}
|
|
54640
|
+
async function writeMeta(key2, meta) {
|
|
54641
|
+
const p = metaPath(key2);
|
|
54642
|
+
await mkdir4(path8.dirname(p), { recursive: true });
|
|
54643
|
+
await writeFileDurable(p, `${JSON.stringify(meta)}
|
|
54644
|
+
`);
|
|
54645
|
+
}
|
|
54646
|
+
async function placeExclusive(tmp, target) {
|
|
54647
|
+
try {
|
|
54648
|
+
await link(tmp, target);
|
|
54649
|
+
await rm5(tmp, { force: true }).catch(() => void 0);
|
|
54650
|
+
return "created";
|
|
54651
|
+
} catch (err) {
|
|
54652
|
+
if (isErrnoException(err)) {
|
|
54653
|
+
if (err.code === "EEXIST") return "exists";
|
|
54654
|
+
if (err.code === "EPERM" || err.code === "ENOSYS" || err.code === "ENOTSUP" || err.code === "EXDEV") {
|
|
54655
|
+
if (await exists(target)) return "exists";
|
|
54656
|
+
await renameWithRetry(tmp, target);
|
|
54657
|
+
return "created";
|
|
54658
|
+
}
|
|
54659
|
+
}
|
|
54660
|
+
throw err;
|
|
54661
|
+
}
|
|
54662
|
+
}
|
|
54663
|
+
const store = {
|
|
54664
|
+
capabilities,
|
|
54665
|
+
async put(key2, body, meta, opts = {}) {
|
|
54666
|
+
const target = objectPath(key2);
|
|
54667
|
+
await prepare();
|
|
54668
|
+
if (opts.signal?.aborted === true) {
|
|
54669
|
+
await body.cancel().catch(() => void 0);
|
|
54670
|
+
throw new StoreError("transient", "aborted", { cause: opts.signal.reason });
|
|
54671
|
+
}
|
|
54672
|
+
const spooled = await spool(body, opts.signal);
|
|
54673
|
+
try {
|
|
54674
|
+
if (spooled.sha256 !== meta.sha256) {
|
|
54675
|
+
throw new StoreError("permanent", `sha256 不符:体 ${spooled.sha256} ≠ meta ${meta.sha256}(${key2})`);
|
|
54676
|
+
}
|
|
54677
|
+
const etag = spooled.sha256;
|
|
54678
|
+
const stored = { ...meta, bytes: spooled.bytes, etag };
|
|
54679
|
+
return await locks.run(key2, async () => {
|
|
54680
|
+
await mkdir4(path8.dirname(target), { recursive: true });
|
|
54681
|
+
if (opts.ifNoneMatch === "*") {
|
|
54682
|
+
const outcome = await placeExclusive(spooled.tmp, target);
|
|
54683
|
+
if (outcome === "exists") {
|
|
54684
|
+
const current = await readMeta(key2);
|
|
54685
|
+
if (current === null || current.etag !== etag) {
|
|
54686
|
+
throw new StoreError("precondition_failed", `ifNoneMatch:* 但对象已存在:${key2}`);
|
|
54687
|
+
}
|
|
54688
|
+
return { etag };
|
|
54689
|
+
}
|
|
54690
|
+
await writeMeta(key2, stored);
|
|
54691
|
+
return { etag };
|
|
54692
|
+
}
|
|
54693
|
+
if (opts.ifMatch !== void 0) {
|
|
54694
|
+
const current = await readMeta(key2);
|
|
54695
|
+
if (current === null || current.etag !== opts.ifMatch) {
|
|
54696
|
+
throw new StoreError("precondition_failed", `ifMatch ${opts.ifMatch} 但现行 etag ${current?.etag ?? "(absent)"}:${key2}`);
|
|
54697
|
+
}
|
|
54698
|
+
}
|
|
54699
|
+
await renameWithRetry(spooled.tmp, target);
|
|
54700
|
+
await writeMeta(key2, stored);
|
|
54701
|
+
return { etag };
|
|
54702
|
+
});
|
|
54703
|
+
} catch (err) {
|
|
54704
|
+
throw toStoreError(err);
|
|
54705
|
+
} finally {
|
|
54706
|
+
await rm5(spooled.tmp, { force: true }).catch(() => void 0);
|
|
54707
|
+
}
|
|
54708
|
+
},
|
|
54709
|
+
async get(key2, range, signal) {
|
|
54710
|
+
const target = objectPath(key2);
|
|
54711
|
+
await prepare();
|
|
54712
|
+
if (signal?.aborted === true) throw new StoreError("transient", "aborted", { cause: signal.reason });
|
|
54713
|
+
const meta = await readMeta(key2);
|
|
54714
|
+
if (meta === null || !await exists(target)) throw new StoreError("not_found", `对象不存在:${key2}`);
|
|
54715
|
+
const streamOptions = { highWaterMark: 256 * 1024 };
|
|
54716
|
+
if (range !== void 0) {
|
|
54717
|
+
if (range.start >= meta.bytes) return new ReadableStream({ start: (c) => c.close() });
|
|
54718
|
+
streamOptions.start = range.start;
|
|
54719
|
+
if (range.end !== void 0) streamOptions.end = Math.min(range.end, meta.bytes - 1);
|
|
54720
|
+
}
|
|
54721
|
+
const source = createReadStream2(target, streamOptions);
|
|
54722
|
+
if (signal !== void 0) {
|
|
54723
|
+
const abort = () => {
|
|
54724
|
+
source.destroy(new StoreError("transient", "aborted", { cause: signal.reason }));
|
|
54725
|
+
};
|
|
54726
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
54727
|
+
source.once("close", () => signal.removeEventListener("abort", abort));
|
|
54728
|
+
}
|
|
54729
|
+
return nodeToWeb(source);
|
|
54730
|
+
},
|
|
54731
|
+
async head(key2) {
|
|
54732
|
+
await prepare();
|
|
54733
|
+
const meta = await readMeta(key2);
|
|
54734
|
+
if (meta === null || !await exists(objectPath(key2))) return null;
|
|
54735
|
+
return { ...meta };
|
|
54736
|
+
},
|
|
54737
|
+
async *list(prefix, cursor, signal) {
|
|
54738
|
+
await prepare();
|
|
54739
|
+
const slash = prefix.lastIndexOf("/");
|
|
54740
|
+
const dirPart = slash === -1 ? "" : prefix.slice(0, slash);
|
|
54741
|
+
const dirParts = dirPart === "" ? [] : fsKeyParts(dirPart);
|
|
54742
|
+
const startDir = path8.join(objectsDir, ...dirParts);
|
|
54743
|
+
if (!await exists(startDir)) return;
|
|
54744
|
+
const keys = [];
|
|
54745
|
+
const walk = async (dir, keyPrefix) => {
|
|
54746
|
+
let entries;
|
|
54747
|
+
try {
|
|
54748
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
54749
|
+
} catch (err) {
|
|
54750
|
+
if (isErrnoException(err) && err.code === "ENOENT") return;
|
|
54751
|
+
throw toStoreError(err);
|
|
54752
|
+
}
|
|
54753
|
+
for (const entry of entries) {
|
|
54754
|
+
const key2 = keyPrefix === "" ? entry.name : `${keyPrefix}/${entry.name}`;
|
|
54755
|
+
if (entry.isDirectory()) await walk(path8.join(dir, entry.name), key2);
|
|
54756
|
+
else if (entry.isFile() && key2.startsWith(prefix)) keys.push(key2);
|
|
54757
|
+
}
|
|
54758
|
+
};
|
|
54759
|
+
await walk(startDir, dirPart);
|
|
54760
|
+
keys.sort();
|
|
54761
|
+
for (const key2 of keys) {
|
|
54762
|
+
if (signal?.aborted === true) throw new StoreError("transient", "aborted", { cause: signal.reason });
|
|
54763
|
+
if (cursor !== void 0 && key2 <= cursor) continue;
|
|
54764
|
+
const meta = await readMeta(key2);
|
|
54765
|
+
if (meta === null) continue;
|
|
54766
|
+
yield { key: key2, meta: { ...meta } };
|
|
54767
|
+
}
|
|
54768
|
+
},
|
|
54769
|
+
async delete(keys) {
|
|
54770
|
+
await prepare();
|
|
54771
|
+
for (const key2 of keys) {
|
|
54772
|
+
await rm5(objectPath(key2), { force: true }).catch((err) => {
|
|
54773
|
+
throw toStoreError(err);
|
|
54774
|
+
});
|
|
54775
|
+
await rm5(metaPath(key2), { force: true }).catch((err) => {
|
|
54776
|
+
throw toStoreError(err);
|
|
54777
|
+
});
|
|
54778
|
+
}
|
|
54779
|
+
}
|
|
54780
|
+
};
|
|
54781
|
+
return store;
|
|
54782
|
+
}
|
|
54783
|
+
|
|
54530
54784
|
// ../kernel/src/journal/segmented/conformance.ts
|
|
54785
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
54531
54786
|
var CHUNK = 256 * 1024;
|
|
54532
54787
|
var MIB = 1024 * 1024;
|
|
54788
|
+
function bytesOf(size, seed) {
|
|
54789
|
+
const out = new Uint8Array(size);
|
|
54790
|
+
let x = seed * 2654435761 + 1 >>> 0;
|
|
54791
|
+
for (let i = 0; i < size; i++) {
|
|
54792
|
+
x = x * 1664525 + 1013904223 >>> 0;
|
|
54793
|
+
out[i] = x >>> 24;
|
|
54794
|
+
}
|
|
54795
|
+
return out;
|
|
54796
|
+
}
|
|
54797
|
+
function sha256(bytes) {
|
|
54798
|
+
return createHash12("sha256").update(bytes).digest("hex");
|
|
54799
|
+
}
|
|
54800
|
+
function toStream(bytes, chunk = CHUNK) {
|
|
54801
|
+
let offset = 0;
|
|
54802
|
+
return new ReadableStream({
|
|
54803
|
+
pull(controller) {
|
|
54804
|
+
if (offset >= bytes.byteLength) {
|
|
54805
|
+
controller.close();
|
|
54806
|
+
return;
|
|
54807
|
+
}
|
|
54808
|
+
const end = Math.min(bytes.byteLength, offset + chunk);
|
|
54809
|
+
controller.enqueue(bytes.subarray(offset, end));
|
|
54810
|
+
offset = end;
|
|
54811
|
+
}
|
|
54812
|
+
});
|
|
54813
|
+
}
|
|
54814
|
+
async function collect(body) {
|
|
54815
|
+
const chunks = [];
|
|
54816
|
+
let total = 0;
|
|
54817
|
+
const reader = body.getReader();
|
|
54818
|
+
try {
|
|
54819
|
+
for (; ; ) {
|
|
54820
|
+
const { done, value } = await reader.read();
|
|
54821
|
+
if (done) break;
|
|
54822
|
+
chunks.push(value);
|
|
54823
|
+
total += value.byteLength;
|
|
54824
|
+
}
|
|
54825
|
+
} finally {
|
|
54826
|
+
reader.releaseLock();
|
|
54827
|
+
}
|
|
54828
|
+
const out = new Uint8Array(total);
|
|
54829
|
+
let o = 0;
|
|
54830
|
+
for (const c of chunks) {
|
|
54831
|
+
out.set(c, o);
|
|
54832
|
+
o += c.byteLength;
|
|
54833
|
+
}
|
|
54834
|
+
return out;
|
|
54835
|
+
}
|
|
54836
|
+
async function drain(body) {
|
|
54837
|
+
let total = 0;
|
|
54838
|
+
const reader = body.getReader();
|
|
54839
|
+
try {
|
|
54840
|
+
for (; ; ) {
|
|
54841
|
+
const { done, value } = await reader.read();
|
|
54842
|
+
if (done) break;
|
|
54843
|
+
total += value.byteLength;
|
|
54844
|
+
}
|
|
54845
|
+
} finally {
|
|
54846
|
+
reader.releaseLock();
|
|
54847
|
+
}
|
|
54848
|
+
return total;
|
|
54849
|
+
}
|
|
54850
|
+
function equalBytes(a, b) {
|
|
54851
|
+
if (a.byteLength !== b.byteLength) return false;
|
|
54852
|
+
for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;
|
|
54853
|
+
return true;
|
|
54854
|
+
}
|
|
54855
|
+
function metaFor(bytes, contentType = "application/octet-stream") {
|
|
54856
|
+
return { bytes: bytes.byteLength, contentType, sha256: sha256(bytes) };
|
|
54857
|
+
}
|
|
54858
|
+
function largeStream(total, seed) {
|
|
54859
|
+
let produced = 0;
|
|
54860
|
+
let x = seed * 2654435761 + 1 >>> 0;
|
|
54861
|
+
return new ReadableStream({
|
|
54862
|
+
pull(controller) {
|
|
54863
|
+
if (produced >= total) {
|
|
54864
|
+
controller.close();
|
|
54865
|
+
return;
|
|
54866
|
+
}
|
|
54867
|
+
const size = Math.min(CHUNK, total - produced);
|
|
54868
|
+
const chunk = new Uint8Array(size);
|
|
54869
|
+
for (let i = 0; i < size; i++) {
|
|
54870
|
+
x = x * 1664525 + 1013904223 >>> 0;
|
|
54871
|
+
chunk[i] = x >>> 24;
|
|
54872
|
+
}
|
|
54873
|
+
produced += size;
|
|
54874
|
+
controller.enqueue(chunk);
|
|
54875
|
+
}
|
|
54876
|
+
});
|
|
54877
|
+
}
|
|
54878
|
+
async function largeSha256(total, seed) {
|
|
54879
|
+
const hash = createHash12("sha256");
|
|
54880
|
+
const reader = largeStream(total, seed).getReader();
|
|
54881
|
+
for (; ; ) {
|
|
54882
|
+
const { done, value } = await reader.read();
|
|
54883
|
+
if (done) break;
|
|
54884
|
+
hash.update(value);
|
|
54885
|
+
}
|
|
54886
|
+
return hash.digest("hex");
|
|
54887
|
+
}
|
|
54888
|
+
function sampleRss() {
|
|
54889
|
+
const base = process.memoryUsage().rss;
|
|
54890
|
+
let peak = base;
|
|
54891
|
+
const timer = setInterval(() => {
|
|
54892
|
+
peak = Math.max(peak, process.memoryUsage().rss);
|
|
54893
|
+
}, 20);
|
|
54894
|
+
return {
|
|
54895
|
+
stop() {
|
|
54896
|
+
clearInterval(timer);
|
|
54897
|
+
return Math.max(peak, process.memoryUsage().rss) - base;
|
|
54898
|
+
}
|
|
54899
|
+
};
|
|
54900
|
+
}
|
|
54901
|
+
var fmtMiB = (n) => `${(n / MIB).toFixed(1)} MiB`;
|
|
54902
|
+
var CaseFailure = class extends Error {
|
|
54903
|
+
};
|
|
54904
|
+
var fail = (detail) => {
|
|
54905
|
+
throw new CaseFailure(detail);
|
|
54906
|
+
};
|
|
54907
|
+
var ensure = (cond, detail) => {
|
|
54908
|
+
if (!cond) fail(detail);
|
|
54909
|
+
};
|
|
54910
|
+
var isStoreErrorOf = (err, kind) => err instanceof StoreError && err.kind === kind;
|
|
54911
|
+
async function runStorageConformance(store, options = {}) {
|
|
54912
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
54913
|
+
const t0 = performance.now();
|
|
54914
|
+
const caps = store.capabilities;
|
|
54915
|
+
const largeBytes = options.largeObjectBytes ?? 16 * MIB;
|
|
54916
|
+
const rssBudget = options.rssBudgetBytes ?? 64 * MIB;
|
|
54917
|
+
const eventualMs = options.eventualConsistencyMs ?? 0;
|
|
54918
|
+
const prefix = options.keyPrefix ?? `conformance-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
54919
|
+
const concurrency = Math.max(2, options.concurrency ?? 16);
|
|
54920
|
+
const created = /* @__PURE__ */ new Set();
|
|
54921
|
+
const key2 = (name) => {
|
|
54922
|
+
const k = `${prefix}/${name}`;
|
|
54923
|
+
created.add(k);
|
|
54924
|
+
return k;
|
|
54925
|
+
};
|
|
54926
|
+
async function waitVisible(listPrefix, expected) {
|
|
54927
|
+
const deadline = performance.now() + eventualMs;
|
|
54928
|
+
for (; ; ) {
|
|
54929
|
+
for await (const entry of store.list(listPrefix, void 0, options.signal)) {
|
|
54930
|
+
if (entry.key === expected) return true;
|
|
54931
|
+
}
|
|
54932
|
+
if (performance.now() >= deadline) return false;
|
|
54933
|
+
await new Promise((r) => setTimeout(r, Math.min(50, Math.max(5, eventualMs / 20))));
|
|
54934
|
+
}
|
|
54935
|
+
}
|
|
54936
|
+
const cases = [];
|
|
54937
|
+
async function run(id, fn) {
|
|
54938
|
+
const start = performance.now();
|
|
54939
|
+
try {
|
|
54940
|
+
const detail = await fn();
|
|
54941
|
+
const skipped = detail.startsWith("skipped:");
|
|
54942
|
+
cases.push({ id, passed: true, detail, ...skipped ? { skipped: true } : {}, durationMs: Math.round(performance.now() - start) });
|
|
54943
|
+
} catch (err) {
|
|
54944
|
+
const detail = err instanceof CaseFailure ? err.message : `异常:${err instanceof Error ? `${err.name}: ${err.message}` : String(err)}`;
|
|
54945
|
+
cases.push({ id, passed: false, detail, durationMs: Math.round(performance.now() - start) });
|
|
54946
|
+
}
|
|
54947
|
+
}
|
|
54948
|
+
await run("idempotent_put", async () => {
|
|
54949
|
+
const k = key2("idempotent");
|
|
54950
|
+
const bytes = bytesOf(7e4, 1);
|
|
54951
|
+
const meta = metaFor(bytes);
|
|
54952
|
+
const r1 = await store.put(k, toStream(bytes), meta);
|
|
54953
|
+
const r2 = await store.put(k, toStream(bytes), meta);
|
|
54954
|
+
ensure(r1.etag === void 0 || r2.etag === void 0 || r1.etag === r2.etag, `同内容重复 put 的 etag 不同:${r1.etag} / ${r2.etag}`);
|
|
54955
|
+
const head = await store.head(k);
|
|
54956
|
+
ensure(head !== null, "put 后 head 为 null");
|
|
54957
|
+
ensure(head.bytes === bytes.byteLength, `head.bytes ${head.bytes} ≠ ${bytes.byteLength}`);
|
|
54958
|
+
ensure(head.sha256 === meta.sha256, "head.sha256 与 meta 不符");
|
|
54959
|
+
ensure(head.contentType === meta.contentType, "head.contentType 与 meta 不符");
|
|
54960
|
+
const back = await collect(await store.get(k));
|
|
54961
|
+
ensure(equalBytes(back, bytes), "get 回读与 put 体不同");
|
|
54962
|
+
return `2 次 put 成功,head/get 一致(${bytes.byteLength} B)`;
|
|
54963
|
+
});
|
|
54964
|
+
await run("range_get", async () => {
|
|
54965
|
+
if (!caps.rangeGet) return "skipped: capabilities.rangeGet:false";
|
|
54966
|
+
const k = key2("range");
|
|
54967
|
+
const bytes = bytesOf(1e5, 2);
|
|
54968
|
+
await store.put(k, toStream(bytes), metaFor(bytes));
|
|
54969
|
+
const mid = await collect(await store.get(k, { start: 10, end: 19 }));
|
|
54970
|
+
ensure(equalBytes(mid, bytes.subarray(10, 20)), `Range [10,19] 回读 ${mid.byteLength} B 与切片不同`);
|
|
54971
|
+
const tail = await collect(await store.get(k, { start: bytes.byteLength - 5 }));
|
|
54972
|
+
ensure(equalBytes(tail, bytes.subarray(bytes.byteLength - 5)), "Range 缺省 end 到尾不符");
|
|
54973
|
+
const clamped = await collect(await store.get(k, { start: bytes.byteLength - 3, end: bytes.byteLength + 1e3 }));
|
|
54974
|
+
ensure(equalBytes(clamped, bytes.subarray(bytes.byteLength - 3)), "Range end 越界未钳到尾");
|
|
54975
|
+
const first = await collect(await store.get(k, { start: 0, end: 0 }));
|
|
54976
|
+
ensure(first.byteLength === 1 && first[0] === bytes[0], "Range [0,0] 应回 1 字节");
|
|
54977
|
+
return "中段 / 到尾 / 越界钳 / 单字节 Range 皆正确";
|
|
54978
|
+
});
|
|
54979
|
+
await run("concurrent_put", async () => {
|
|
54980
|
+
const items = Array.from({ length: concurrency }, (_, i) => ({ k: key2(`concurrent/${String(i).padStart(3, "0")}`), bytes: bytesOf(2e4 + i * 7, 100 + i) }));
|
|
54981
|
+
await Promise.all(items.map((it) => store.put(it.k, toStream(it.bytes), metaFor(it.bytes))));
|
|
54982
|
+
for (const it of items) {
|
|
54983
|
+
const head = await store.head(it.k);
|
|
54984
|
+
ensure(head !== null && head.sha256 === sha256(it.bytes), `并发 put 后 ${it.k} head 缺失或哈希不符`);
|
|
54985
|
+
ensure(equalBytes(await collect(await store.get(it.k)), it.bytes), `并发 put 后 ${it.k} 内容不符`);
|
|
54986
|
+
}
|
|
54987
|
+
return `${concurrency} 键并发 put 全部一致`;
|
|
54988
|
+
});
|
|
54989
|
+
await run("partial_put_invisible", async () => {
|
|
54990
|
+
const k = key2("partial");
|
|
54991
|
+
const bytes = bytesOf(3e5, 4);
|
|
54992
|
+
const meta = metaFor(bytes);
|
|
54993
|
+
let sent = 0;
|
|
54994
|
+
const broken = new ReadableStream({
|
|
54995
|
+
pull(controller) {
|
|
54996
|
+
if (sent >= 2) {
|
|
54997
|
+
controller.error(new Error("conformance: connection dropped"));
|
|
54998
|
+
return;
|
|
54999
|
+
}
|
|
55000
|
+
controller.enqueue(bytes.subarray(sent * CHUNK, Math.min(bytes.byteLength, (sent + 1) * CHUNK)));
|
|
55001
|
+
sent++;
|
|
55002
|
+
}
|
|
55003
|
+
});
|
|
55004
|
+
let threw = false;
|
|
55005
|
+
try {
|
|
55006
|
+
await store.put(k, broken, meta);
|
|
55007
|
+
} catch {
|
|
55008
|
+
threw = true;
|
|
55009
|
+
}
|
|
55010
|
+
ensure(threw, "体流中断的 put 未失败");
|
|
55011
|
+
ensure(await store.head(k) === null, "体流中断后留下半对象(head 非 null)");
|
|
55012
|
+
let threw2 = null;
|
|
55013
|
+
try {
|
|
55014
|
+
await store.put(k, toStream(bytes), { ...meta, sha256: "f".repeat(64) });
|
|
55015
|
+
} catch (err) {
|
|
55016
|
+
threw2 = err;
|
|
55017
|
+
}
|
|
55018
|
+
ensure(threw2 !== null, "sha256 不符的 put 未失败");
|
|
55019
|
+
ensure(await store.head(k) === null, "sha256 不符后留下对象");
|
|
55020
|
+
return `体流中断 / sha256 不符均失败且无半对象${isStoreErrorOf(threw2, "permanent") ? "(sha256 不符归 permanent)" : ""}`;
|
|
55021
|
+
});
|
|
55022
|
+
await run("list_prefix_cursor", async () => {
|
|
55023
|
+
if (caps.list === "none") return "skipped: capabilities.list:'none'";
|
|
55024
|
+
const names = ["a-000", "a-001", "a-002", "b-000", "b-001"];
|
|
55025
|
+
const keys = names.map((n) => key2(`listing/${n}`));
|
|
55026
|
+
for (const [i, k] of keys.entries()) {
|
|
55027
|
+
const bytes = bytesOf(1e3 + i, 200 + i);
|
|
55028
|
+
await store.put(k, toStream(bytes), metaFor(bytes));
|
|
55029
|
+
}
|
|
55030
|
+
const listPrefix = `${prefix}/listing/`;
|
|
55031
|
+
for (const k of keys) ensure(await waitVisible(listPrefix, k), `${k} 在 ${eventualMs} ms 内未经 list 可见`);
|
|
55032
|
+
const all = [];
|
|
55033
|
+
for await (const e of store.list(listPrefix)) {
|
|
55034
|
+
all.push(e.key);
|
|
55035
|
+
ensure(e.meta.sha256.length === 64, `list 条目 meta.sha256 形状不对:${e.key}`);
|
|
55036
|
+
}
|
|
55037
|
+
ensure(all.length === keys.length, `list 返回 ${all.length} 项 ≠ ${keys.length}`);
|
|
55038
|
+
for (let i = 1; i < all.length; i++) ensure(all[i - 1] < all[i], "list 非字典升序");
|
|
55039
|
+
const sub = [];
|
|
55040
|
+
for await (const e of store.list(`${prefix}/listing/a-`)) sub.push(e.key);
|
|
55041
|
+
ensure(sub.length === 3 && sub.every((k) => k.includes("/a-")), `名前缀 list 应 3 项,得 ${sub.length}`);
|
|
55042
|
+
const rest = [];
|
|
55043
|
+
for await (const e of store.list(listPrefix, all[1])) rest.push(e.key);
|
|
55044
|
+
ensure(rest.length === all.length - 2 && rest[0] === all[2], `cursor 分页不正确:${rest.join(",")}`);
|
|
55045
|
+
const none = [];
|
|
55046
|
+
for await (const e of store.list(`${prefix}/nothing-here/`)) none.push(e.key);
|
|
55047
|
+
ensure(none.length === 0, "空前缀 list 应无项");
|
|
55048
|
+
return `${keys.length} 键前缀 / 名前缀 / cursor 分页 / 空前缀正确(可见窗口 ${eventualMs} ms)`;
|
|
55049
|
+
});
|
|
55050
|
+
await run("large_object_streaming", async () => {
|
|
55051
|
+
const k = key2("large");
|
|
55052
|
+
const digest = await largeSha256(largeBytes, 6);
|
|
55053
|
+
const meta = { bytes: largeBytes, contentType: "application/octet-stream", sha256: digest };
|
|
55054
|
+
const putSampler = sampleRss();
|
|
55055
|
+
await store.put(k, largeStream(largeBytes, 6), meta);
|
|
55056
|
+
const putDelta = putSampler.stop();
|
|
55057
|
+
const head = await store.head(k);
|
|
55058
|
+
ensure(head !== null && head.bytes === largeBytes, "large head 缺失或字节数不符");
|
|
55059
|
+
const getSampler = sampleRss();
|
|
55060
|
+
const drained = await drain(await store.get(k));
|
|
55061
|
+
const getDelta = getSampler.stop();
|
|
55062
|
+
ensure(drained === largeBytes, `get 回读 ${drained} B ≠ ${largeBytes}`);
|
|
55063
|
+
ensure(putDelta < rssBudget, `put RSS 峰值增量 ${fmtMiB(putDelta)} ≥ 预算 ${fmtMiB(rssBudget)}`);
|
|
55064
|
+
ensure(getDelta < rssBudget, `get RSS 峰值增量 ${fmtMiB(getDelta)} ≥ 预算 ${fmtMiB(rssBudget)}`);
|
|
55065
|
+
return `${fmtMiB(largeBytes)}:put RSS Δ ${fmtMiB(putDelta)} / get RSS Δ ${fmtMiB(getDelta)} < ${fmtMiB(rssBudget)}`;
|
|
55066
|
+
});
|
|
55067
|
+
await run("abort_signal", async () => {
|
|
55068
|
+
const k = key2("abort");
|
|
55069
|
+
const bytes = bytesOf(4e5, 7);
|
|
55070
|
+
const meta = metaFor(bytes);
|
|
55071
|
+
const pre = new AbortController();
|
|
55072
|
+
pre.abort(new Error("conformance: pre-aborted"));
|
|
55073
|
+
let threw = false;
|
|
55074
|
+
try {
|
|
55075
|
+
await store.put(k, toStream(bytes), meta, { signal: pre.signal });
|
|
55076
|
+
} catch {
|
|
55077
|
+
threw = true;
|
|
55078
|
+
}
|
|
55079
|
+
ensure(threw, "预中止 signal 的 put 未失败");
|
|
55080
|
+
ensure(await store.head(k) === null, "预中止 put 留下对象");
|
|
55081
|
+
const mid = new AbortController();
|
|
55082
|
+
let pulls = 0;
|
|
55083
|
+
const midBody = new ReadableStream({
|
|
55084
|
+
pull(controller) {
|
|
55085
|
+
if (pulls === 1) mid.abort(new Error("conformance: mid abort"));
|
|
55086
|
+
if (pulls * CHUNK >= bytes.byteLength) {
|
|
55087
|
+
controller.close();
|
|
55088
|
+
return;
|
|
55089
|
+
}
|
|
55090
|
+
controller.enqueue(bytes.subarray(pulls * CHUNK, Math.min(bytes.byteLength, (pulls + 1) * CHUNK)));
|
|
55091
|
+
pulls++;
|
|
55092
|
+
}
|
|
55093
|
+
});
|
|
55094
|
+
let threwMid = false;
|
|
55095
|
+
try {
|
|
55096
|
+
await store.put(k, midBody, meta, { signal: mid.signal });
|
|
55097
|
+
} catch {
|
|
55098
|
+
threwMid = true;
|
|
55099
|
+
}
|
|
55100
|
+
ensure(threwMid, "中途中止的 put 未失败");
|
|
55101
|
+
ensure(await store.head(k) === null, "中途中止 put 留下半对象");
|
|
55102
|
+
await store.put(k, toStream(bytes), meta);
|
|
55103
|
+
const getAbort = new AbortController();
|
|
55104
|
+
getAbort.abort(new Error("conformance: get aborted"));
|
|
55105
|
+
let getThrew = false;
|
|
55106
|
+
try {
|
|
55107
|
+
const body = await store.get(k, void 0, getAbort.signal);
|
|
55108
|
+
await drain(body);
|
|
55109
|
+
} catch {
|
|
55110
|
+
getThrew = true;
|
|
55111
|
+
}
|
|
55112
|
+
ensure(getThrew, "预中止 signal 的 get 未失败(既未拒绝也未以流出错)");
|
|
55113
|
+
return "预中止 / 中途中止 put 干净失败无半对象;预中止 get 失败";
|
|
55114
|
+
});
|
|
55115
|
+
await run("manifest_cas", async () => {
|
|
55116
|
+
if (!caps.conditionalPut) return "skipped: capabilities.conditionalPut:false(须挂 SessionIndexStore)";
|
|
55117
|
+
const k = key2("manifest.json");
|
|
55118
|
+
const v1 = new TextEncoder().encode('{"generation":1}\n');
|
|
55119
|
+
const v2 = new TextEncoder().encode('{"generation":2}\n');
|
|
55120
|
+
const v3 = new TextEncoder().encode('{"generation":3}\n');
|
|
55121
|
+
const r1 = await store.put(k, toStream(v1), metaFor(v1, "application/json"), { ifNoneMatch: "*" });
|
|
55122
|
+
ensure(r1.etag !== void 0, "conditionalPut:true 的 put 须返回 etag");
|
|
55123
|
+
let conflict = null;
|
|
55124
|
+
try {
|
|
55125
|
+
await store.put(k, toStream(v2), metaFor(v2, "application/json"), { ifNoneMatch: "*" });
|
|
55126
|
+
} catch (err) {
|
|
55127
|
+
conflict = err;
|
|
55128
|
+
}
|
|
55129
|
+
ensure(isStoreErrorOf(conflict, "precondition_failed"), `ifNoneMatch:* 对已存在键应 precondition_failed,实为 ${String(conflict)}`);
|
|
55130
|
+
ensure(equalBytes(await collect(await store.get(k)), v1), "ifNoneMatch 冲突后内容被改");
|
|
55131
|
+
const head1 = await store.head(k);
|
|
55132
|
+
ensure(head1 !== null && head1.etag === r1.etag, `head.etag(${head1?.etag})应等于 put 返回 etag(${r1.etag})`);
|
|
55133
|
+
const r2 = await store.put(k, toStream(v2), metaFor(v2, "application/json"), { ifMatch: r1.etag });
|
|
55134
|
+
ensure(r2.etag !== void 0 && r2.etag !== r1.etag, "ifMatch 改写后 etag 应变化");
|
|
55135
|
+
let stale = null;
|
|
55136
|
+
try {
|
|
55137
|
+
await store.put(k, toStream(v3), metaFor(v3, "application/json"), { ifMatch: r1.etag });
|
|
55138
|
+
} catch (err) {
|
|
55139
|
+
stale = err;
|
|
55140
|
+
}
|
|
55141
|
+
ensure(isStoreErrorOf(stale, "precondition_failed"), `过期 etag 的 ifMatch 应 precondition_failed,实为 ${String(stale)}`);
|
|
55142
|
+
ensure(equalBytes(await collect(await store.get(k)), v2), "过期 ifMatch 冲突后内容被改");
|
|
55143
|
+
let missing = null;
|
|
55144
|
+
try {
|
|
55145
|
+
await store.put(key2("manifest-missing.json"), toStream(v1), metaFor(v1, "application/json"), { ifMatch: "nope" });
|
|
55146
|
+
} catch (err) {
|
|
55147
|
+
missing = err;
|
|
55148
|
+
}
|
|
55149
|
+
ensure(isStoreErrorOf(missing, "precondition_failed"), "ifMatch 对不存在键应 precondition_failed");
|
|
55150
|
+
return "ifNoneMatch:* 首写 / 冲突 412;ifMatch etag 改写 / 过期 412 / 缺席 412;head 回带 etag";
|
|
55151
|
+
});
|
|
55152
|
+
await run("delete_idempotent", async () => {
|
|
55153
|
+
const k = key2("delete");
|
|
55154
|
+
const bytes = bytesOf(1234, 9);
|
|
55155
|
+
await store.put(k, toStream(bytes), metaFor(bytes));
|
|
55156
|
+
await store.delete([k]);
|
|
55157
|
+
ensure(await store.head(k) === null, "delete 后 head 仍非 null");
|
|
55158
|
+
let notFound = null;
|
|
55159
|
+
try {
|
|
55160
|
+
await drain(await store.get(k));
|
|
55161
|
+
} catch (err) {
|
|
55162
|
+
notFound = err;
|
|
55163
|
+
}
|
|
55164
|
+
ensure(notFound !== null, "delete 后 get 未失败");
|
|
55165
|
+
await store.delete([k]);
|
|
55166
|
+
await store.delete([key2("never-existed")]);
|
|
55167
|
+
const batch = Math.max(1, Math.min(caps.batchDelete ?? 1, 8));
|
|
55168
|
+
const many = Array.from({ length: batch }, (_, i) => key2(`delete-batch/${i}`));
|
|
55169
|
+
for (const [i, mk] of many.entries()) {
|
|
55170
|
+
const b = bytesOf(100 + i, 300 + i);
|
|
55171
|
+
await store.put(mk, toStream(b), metaFor(b));
|
|
55172
|
+
}
|
|
55173
|
+
await store.delete(many);
|
|
55174
|
+
for (const mk of many) ensure(await store.head(mk) === null, `批删后 ${mk} 仍在`);
|
|
55175
|
+
return `在场 / 重复 / 不存在 / 批量 ${batch} 键删除皆幂等`;
|
|
55176
|
+
});
|
|
55177
|
+
await run("capabilities_truthful", async () => {
|
|
55178
|
+
const notes = [];
|
|
55179
|
+
const missing = key2("missing");
|
|
55180
|
+
ensure(await store.head(missing) === null, "head 不存在键应返 null 而非抛");
|
|
55181
|
+
let getErr = null;
|
|
55182
|
+
try {
|
|
55183
|
+
await drain(await store.get(missing));
|
|
55184
|
+
} catch (err) {
|
|
55185
|
+
getErr = err;
|
|
55186
|
+
}
|
|
55187
|
+
ensure(getErr !== null, "get 不存在键应失败");
|
|
55188
|
+
notes.push(isStoreErrorOf(getErr, "not_found") ? "get 缺席 → not_found" : `get 缺席 → ${toStoreError(getErr).kind}(建议 not_found)`);
|
|
55189
|
+
ensure(caps.consistency === "strong" || caps.consistency === "eventual", `consistency 值非法:${String(caps.consistency)}`);
|
|
55190
|
+
ensure(Number.isFinite(caps.maxObjectBytes) && caps.maxObjectBytes > 0, "maxObjectBytes 须为正有限数");
|
|
55191
|
+
ensure(caps.list === "prefix" || caps.list === "none", `list 值非法:${String(caps.list)}`);
|
|
55192
|
+
ensure(caps.batchDelete === void 0 || Number.isInteger(caps.batchDelete) && caps.batchDelete >= 1, "batchDelete 须为 ≥1 整数");
|
|
55193
|
+
const bytes = bytesOf(5e4, 10);
|
|
55194
|
+
const k = key2("truthful");
|
|
55195
|
+
const r = await store.put(k, toStream(bytes), metaFor(bytes));
|
|
55196
|
+
if (caps.rangeGet) {
|
|
55197
|
+
const part = await collect(await store.get(k, { start: 100, end: 199 }));
|
|
55198
|
+
ensure(equalBytes(part, bytes.subarray(100, 200)), "声明 rangeGet:true 但 Range 读不正确");
|
|
55199
|
+
notes.push("rangeGet 属实");
|
|
55200
|
+
}
|
|
55201
|
+
if (caps.conditionalPut) {
|
|
55202
|
+
ensure(r.etag !== void 0, "声明 conditionalPut:true 但 put 未返回 etag");
|
|
55203
|
+
const head = await store.head(k);
|
|
55204
|
+
ensure(head?.etag === r.etag, "声明 conditionalPut:true 但 head 未回带 etag");
|
|
55205
|
+
let conflict = null;
|
|
55206
|
+
try {
|
|
55207
|
+
const other = bytesOf(5e4, 11);
|
|
55208
|
+
await store.put(k, toStream(other), metaFor(other), { ifNoneMatch: "*" });
|
|
55209
|
+
} catch (err) {
|
|
55210
|
+
conflict = err;
|
|
55211
|
+
}
|
|
55212
|
+
ensure(isStoreErrorOf(conflict, "precondition_failed"), "声明 conditionalPut:true 但 ifNoneMatch:* 未拒绝");
|
|
55213
|
+
notes.push("conditionalPut 属实");
|
|
55214
|
+
}
|
|
55215
|
+
if (caps.list === "prefix") {
|
|
55216
|
+
ensure(await waitVisible(`${prefix}/truthful`, k), "声明 list:prefix 但 put 后 list 不见");
|
|
55217
|
+
notes.push("list:prefix 属实");
|
|
55218
|
+
}
|
|
55219
|
+
if (caps.consistency === "strong") {
|
|
55220
|
+
ensure(await store.head(k) !== null, "声明 strong 但写后 head 不可见");
|
|
55221
|
+
notes.push("strong 写后即读属实");
|
|
55222
|
+
}
|
|
55223
|
+
return notes.join(";");
|
|
55224
|
+
});
|
|
55225
|
+
if (options.keepObjects !== true) {
|
|
55226
|
+
const keys = [...created];
|
|
55227
|
+
const batch = Math.max(1, caps.batchDelete ?? 1);
|
|
55228
|
+
for (let i = 0; i < keys.length; i += batch) {
|
|
55229
|
+
await store.delete(keys.slice(i, i + batch)).catch(() => void 0);
|
|
55230
|
+
}
|
|
55231
|
+
}
|
|
55232
|
+
return {
|
|
55233
|
+
cases,
|
|
55234
|
+
passed: cases.every((c) => c.passed),
|
|
55235
|
+
capabilities: { ...caps },
|
|
55236
|
+
startedAt,
|
|
55237
|
+
durationMs: Math.round(performance.now() - t0)
|
|
55238
|
+
};
|
|
55239
|
+
}
|
|
55240
|
+
|
|
55241
|
+
// ../kernel/src/journal/segmented/chaos-blob-store.ts
|
|
55242
|
+
function matches(pred, key2) {
|
|
55243
|
+
if (pred === void 0) return false;
|
|
55244
|
+
return typeof pred === "boolean" ? pred : pred(key2);
|
|
55245
|
+
}
|
|
55246
|
+
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
55247
|
+
function createChaosBlobStore(inner, faults = {}, now = Date.now) {
|
|
55248
|
+
const putAt = /* @__PURE__ */ new Map();
|
|
55249
|
+
let putsSeen = 0;
|
|
55250
|
+
const stats = {
|
|
55251
|
+
putFailures: 0,
|
|
55252
|
+
putTruncated: 0,
|
|
55253
|
+
listHidden: 0,
|
|
55254
|
+
listDropped: 0,
|
|
55255
|
+
corruptedGets: 0,
|
|
55256
|
+
abortedGets: 0,
|
|
55257
|
+
calls: { put: 0, get: 0, head: 0, list: 0, delete: 0 }
|
|
55258
|
+
};
|
|
55259
|
+
const latency = async () => {
|
|
55260
|
+
const l = faults.latencyMs;
|
|
55261
|
+
if (l === void 0) return;
|
|
55262
|
+
const ms = typeof l === "number" ? l : l.min + Math.random() * Math.max(0, l.max - l.min);
|
|
55263
|
+
if (ms > 0) await delay(ms);
|
|
55264
|
+
};
|
|
55265
|
+
const injectedPutError = (key2, detail) => {
|
|
55266
|
+
const kind = faults.putErrorKind ?? "transient";
|
|
55267
|
+
return new StoreError(kind, `chaos: ${detail} (${key2})`, kind === "transient" && faults.retryAfterMs !== void 0 ? { retryAfterMs: faults.retryAfterMs } : {});
|
|
55268
|
+
};
|
|
55269
|
+
const shouldFailPut = (key2) => {
|
|
55270
|
+
const f = faults.failPut;
|
|
55271
|
+
if (f === void 0) return false;
|
|
55272
|
+
if (typeof f === "number") return putsSeen <= f;
|
|
55273
|
+
return matches(f, key2);
|
|
55274
|
+
};
|
|
55275
|
+
const truncateBody = (body, afterBytes, key2) => {
|
|
55276
|
+
let seen = 0;
|
|
55277
|
+
return body.pipeThrough(
|
|
55278
|
+
new TransformStream({
|
|
55279
|
+
transform(chunk, controller) {
|
|
55280
|
+
if (seen >= afterBytes) {
|
|
55281
|
+
controller.error(injectedPutError(key2, `connection dropped after ${afterBytes} bytes`));
|
|
55282
|
+
return;
|
|
55283
|
+
}
|
|
55284
|
+
const take = Math.min(chunk.byteLength, afterBytes - seen);
|
|
55285
|
+
seen += take;
|
|
55286
|
+
controller.enqueue(chunk.subarray(0, take));
|
|
55287
|
+
if (seen >= afterBytes) controller.error(injectedPutError(key2, `connection dropped after ${afterBytes} bytes`));
|
|
55288
|
+
}
|
|
55289
|
+
})
|
|
55290
|
+
);
|
|
55291
|
+
};
|
|
55292
|
+
const capabilities = {
|
|
55293
|
+
...inner.capabilities,
|
|
55294
|
+
get consistency() {
|
|
55295
|
+
return (faults.eventualListLagMs ?? 0) > 0 || faults.dropListEntries !== void 0 ? "eventual" : inner.capabilities.consistency;
|
|
55296
|
+
}
|
|
55297
|
+
};
|
|
55298
|
+
return {
|
|
55299
|
+
faults,
|
|
55300
|
+
stats,
|
|
55301
|
+
inner,
|
|
55302
|
+
capabilities,
|
|
55303
|
+
async put(key2, body, meta, opts) {
|
|
55304
|
+
stats.calls.put++;
|
|
55305
|
+
putsSeen++;
|
|
55306
|
+
await latency();
|
|
55307
|
+
if (shouldFailPut(key2)) {
|
|
55308
|
+
stats.putFailures++;
|
|
55309
|
+
await body.cancel().catch(() => void 0);
|
|
55310
|
+
throw injectedPutError(key2, "put rejected");
|
|
55311
|
+
}
|
|
55312
|
+
const after = faults.failPutAfterBytes;
|
|
55313
|
+
if (after !== void 0) {
|
|
55314
|
+
stats.putTruncated++;
|
|
55315
|
+
try {
|
|
55316
|
+
return await inner.put(key2, truncateBody(body, after, key2), meta, opts);
|
|
55317
|
+
} catch (err) {
|
|
55318
|
+
if (err instanceof StoreError && err.kind === faults.putErrorKind) throw err;
|
|
55319
|
+
throw injectedPutError(key2, `connection dropped after ${after} bytes`);
|
|
55320
|
+
}
|
|
55321
|
+
}
|
|
55322
|
+
const result = await inner.put(key2, body, meta, opts);
|
|
55323
|
+
putAt.set(key2, now());
|
|
55324
|
+
return result;
|
|
55325
|
+
},
|
|
55326
|
+
async get(key2, range, signal) {
|
|
55327
|
+
stats.calls.get++;
|
|
55328
|
+
await latency();
|
|
55329
|
+
const body = await inner.get(key2, range, signal);
|
|
55330
|
+
if (matches(faults.corruptSegmentKeys, key2)) {
|
|
55331
|
+
stats.corruptedGets++;
|
|
55332
|
+
let flipped = false;
|
|
55333
|
+
return body.pipeThrough(
|
|
55334
|
+
new TransformStream({
|
|
55335
|
+
transform(chunk, controller) {
|
|
55336
|
+
if (!flipped && chunk.byteLength > 0) {
|
|
55337
|
+
const copy = new Uint8Array(chunk);
|
|
55338
|
+
copy[0] = copy[0] ^ 255;
|
|
55339
|
+
flipped = true;
|
|
55340
|
+
controller.enqueue(copy);
|
|
55341
|
+
return;
|
|
55342
|
+
}
|
|
55343
|
+
controller.enqueue(chunk);
|
|
55344
|
+
}
|
|
55345
|
+
})
|
|
55346
|
+
);
|
|
55347
|
+
}
|
|
55348
|
+
if (matches(faults.abortMidStream, key2)) {
|
|
55349
|
+
stats.abortedGets++;
|
|
55350
|
+
let passed = 0;
|
|
55351
|
+
return body.pipeThrough(
|
|
55352
|
+
new TransformStream({
|
|
55353
|
+
transform(chunk, controller) {
|
|
55354
|
+
if (passed === 0) {
|
|
55355
|
+
controller.enqueue(chunk);
|
|
55356
|
+
passed++;
|
|
55357
|
+
return;
|
|
55358
|
+
}
|
|
55359
|
+
controller.error(new StoreError("transient", `chaos: download aborted mid-stream (${key2})`));
|
|
55360
|
+
},
|
|
55361
|
+
flush(controller) {
|
|
55362
|
+
if (passed <= 1) controller.error(new StoreError("transient", `chaos: download aborted mid-stream (${key2})`));
|
|
55363
|
+
}
|
|
55364
|
+
})
|
|
55365
|
+
);
|
|
55366
|
+
}
|
|
55367
|
+
return body;
|
|
55368
|
+
},
|
|
55369
|
+
async head(key2, signal) {
|
|
55370
|
+
stats.calls.head++;
|
|
55371
|
+
await latency();
|
|
55372
|
+
return inner.head(key2, signal);
|
|
55373
|
+
},
|
|
55374
|
+
async *list(prefix, cursor, signal) {
|
|
55375
|
+
stats.calls.list++;
|
|
55376
|
+
await latency();
|
|
55377
|
+
const lag = faults.eventualListLagMs ?? 0;
|
|
55378
|
+
const drop = faults.dropListEntries;
|
|
55379
|
+
for await (const entry of inner.list(prefix, cursor, signal)) {
|
|
55380
|
+
if (lag > 0) {
|
|
55381
|
+
const at = putAt.get(entry.key);
|
|
55382
|
+
if (at !== void 0 && now() - at < lag) {
|
|
55383
|
+
stats.listHidden++;
|
|
55384
|
+
continue;
|
|
55385
|
+
}
|
|
55386
|
+
}
|
|
55387
|
+
if (drop !== void 0) {
|
|
55388
|
+
const dropped = typeof drop === "number" ? Math.random() < drop : matches(drop, entry.key);
|
|
55389
|
+
if (dropped) {
|
|
55390
|
+
stats.listDropped++;
|
|
55391
|
+
continue;
|
|
55392
|
+
}
|
|
55393
|
+
}
|
|
55394
|
+
yield entry;
|
|
55395
|
+
}
|
|
55396
|
+
},
|
|
55397
|
+
async delete(keys, signal) {
|
|
55398
|
+
stats.calls.delete++;
|
|
55399
|
+
await latency();
|
|
55400
|
+
await inner.delete(keys, signal);
|
|
55401
|
+
for (const key2 of keys) putAt.delete(key2);
|
|
55402
|
+
}
|
|
55403
|
+
};
|
|
55404
|
+
}
|
|
54533
55405
|
|
|
54534
55406
|
// ../kernel/src/journal/segmented/store-metrics.ts
|
|
54535
55407
|
var STORE_BUCKETS_MS = DURATION_BUCKETS_MS.filter((b) => b >= 5);
|
|
@@ -54561,8 +55433,8 @@ function storeMetricsFor(registry = defaultMetrics) {
|
|
|
54561
55433
|
}
|
|
54562
55434
|
|
|
54563
55435
|
// ../kernel/src/journal/segmented/cold-tier.ts
|
|
54564
|
-
import { mkdir as
|
|
54565
|
-
import
|
|
55436
|
+
import { mkdir as mkdir5, rm as rm6, stat as stat4 } from "node:fs/promises";
|
|
55437
|
+
import path9 from "node:path";
|
|
54566
55438
|
async function observed(metrics, op, fn, bytes) {
|
|
54567
55439
|
const t0 = performance.now();
|
|
54568
55440
|
try {
|
|
@@ -54789,13 +55661,13 @@ function createColdTier(options) {
|
|
|
54789
55661
|
return state.sessionMeta;
|
|
54790
55662
|
}
|
|
54791
55663
|
async function uploadOne(state, segment) {
|
|
54792
|
-
const filePath =
|
|
55664
|
+
const filePath = path9.join(state.ref.sessionDir, segment.file);
|
|
54793
55665
|
const volume = await currentVolume(state);
|
|
54794
55666
|
const stillHot = volume?.manifest.segments.find((s) => s.n === segment.n && s.lastHash === segment.lastHash);
|
|
54795
55667
|
if (volume === null || stillHot === void 0) return;
|
|
54796
55668
|
let rawBytes;
|
|
54797
55669
|
try {
|
|
54798
|
-
rawBytes = (await
|
|
55670
|
+
rawBytes = (await stat4(filePath)).size;
|
|
54799
55671
|
} catch (err) {
|
|
54800
55672
|
if (isErrnoException(err) && err.code === "ENOENT") {
|
|
54801
55673
|
const laterHot = volume.manifest.segments.some((s) => s.n > segment.n && s.status === "sealed");
|
|
@@ -54861,7 +55733,7 @@ function createColdTier(options) {
|
|
|
54861
55733
|
emit({ type: "store.segment_committed", session: state.ref, segment, key: key2, bytes: entry.bytes, generation: snapshot.manifest.generation });
|
|
54862
55734
|
} finally {
|
|
54863
55735
|
state.inflight.delete(key2);
|
|
54864
|
-
await
|
|
55736
|
+
await rm6(spoolPath, { force: true }).catch(() => void 0);
|
|
54865
55737
|
}
|
|
54866
55738
|
}
|
|
54867
55739
|
async function evictIfNeeded() {
|
|
@@ -54887,7 +55759,7 @@ function createColdTier(options) {
|
|
|
54887
55759
|
continue;
|
|
54888
55760
|
}
|
|
54889
55761
|
try {
|
|
54890
|
-
await
|
|
55762
|
+
await rm6(path9.join(c.state.ref.sessionDir, segment.file), { force: true });
|
|
54891
55763
|
} catch {
|
|
54892
55764
|
continue;
|
|
54893
55765
|
}
|
|
@@ -54917,7 +55789,7 @@ function createColdTier(options) {
|
|
|
54917
55789
|
if (segment.status !== "sealed") continue;
|
|
54918
55790
|
let size;
|
|
54919
55791
|
try {
|
|
54920
|
-
size = (await
|
|
55792
|
+
size = (await stat4(path9.join(state.ref.sessionDir, segment.file))).size;
|
|
54921
55793
|
} catch {
|
|
54922
55794
|
continue;
|
|
54923
55795
|
}
|
|
@@ -54944,7 +55816,7 @@ function createColdTier(options) {
|
|
|
54944
55816
|
while (active < upload.concurrency && runQueue.length > 0) {
|
|
54945
55817
|
const state = runQueue.shift();
|
|
54946
55818
|
active++;
|
|
54947
|
-
void
|
|
55819
|
+
void drain2(state).finally(() => {
|
|
54948
55820
|
active--;
|
|
54949
55821
|
state.scheduled = false;
|
|
54950
55822
|
if (!closed && state.pending.length > 0 && !state.stopped && !state.paused && states.has(state.ref.sessionDir)) schedule(state);
|
|
@@ -54956,7 +55828,7 @@ function createColdTier(options) {
|
|
|
54956
55828
|
});
|
|
54957
55829
|
}
|
|
54958
55830
|
}
|
|
54959
|
-
async function
|
|
55831
|
+
async function drain2(state) {
|
|
54960
55832
|
try {
|
|
54961
55833
|
if (!state.reconciled) await reconcile(state);
|
|
54962
55834
|
while (state.pending.length > 0 && !state.stopped && !closed) {
|
|
@@ -55099,7 +55971,7 @@ function createColdTier(options) {
|
|
|
55099
55971
|
const last = manifest.segments[manifest.segments.length - 1];
|
|
55100
55972
|
const base = { meta, segments: manifest.segments.length, lastSeq: last?.lastSeq ?? -1, volumeId: manifest.volumeId, generation: manifest.generation };
|
|
55101
55973
|
if (hot !== null) return { ...base, restored: false };
|
|
55102
|
-
await
|
|
55974
|
+
await mkdir5(session.sessionDir, { recursive: true });
|
|
55103
55975
|
await writeManifest(session.sessionDir, coldManifestToHot(manifest));
|
|
55104
55976
|
const state = states.get(session.sessionDir);
|
|
55105
55977
|
if (state !== void 0) {
|
|
@@ -55158,11 +56030,11 @@ function createColdTier(options) {
|
|
|
55158
56030
|
}
|
|
55159
56031
|
|
|
55160
56032
|
// ../kernel/src/journal/session-index.ts
|
|
55161
|
-
import { appendFile as appendFile2, readFile as
|
|
55162
|
-
import
|
|
56033
|
+
import { appendFile as appendFile2, readFile as readFile7, readdir as readdir2, rm as rm7, stat as stat5 } from "node:fs/promises";
|
|
56034
|
+
import path10 from "node:path";
|
|
55163
56035
|
var SESSION_INDEX_FILE_NAME = "index.jsonl";
|
|
55164
56036
|
function sessionIndexFilePath(storageRoot) {
|
|
55165
|
-
return
|
|
56037
|
+
return path10.join(storageRoot, SESSION_INDEX_FILE_NAME);
|
|
55166
56038
|
}
|
|
55167
56039
|
var COMPACT_SLACK_ROWS = 256;
|
|
55168
56040
|
var COMPACT_RATIO = 4;
|
|
@@ -55177,7 +56049,7 @@ var SessionIndex = class {
|
|
|
55177
56049
|
constructor(options) {
|
|
55178
56050
|
this.#root = options.storageRoot;
|
|
55179
56051
|
this.#file = sessionIndexFilePath(options.storageRoot);
|
|
55180
|
-
this.#sessionsDir =
|
|
56052
|
+
this.#sessionsDir = path10.join(options.storageRoot, "sessions");
|
|
55181
56053
|
this.#readMeta = options.readMeta;
|
|
55182
56054
|
}
|
|
55183
56055
|
/** 全部存活条目(无序;调用方自行排序/截断) */
|
|
@@ -55241,14 +56113,14 @@ var SessionIndex = class {
|
|
|
55241
56113
|
}
|
|
55242
56114
|
async #dirMtime() {
|
|
55243
56115
|
try {
|
|
55244
|
-
return (await
|
|
56116
|
+
return (await stat5(this.#sessionsDir)).mtimeMs;
|
|
55245
56117
|
} catch {
|
|
55246
56118
|
return -1;
|
|
55247
56119
|
}
|
|
55248
56120
|
}
|
|
55249
56121
|
async #fileSize() {
|
|
55250
56122
|
try {
|
|
55251
|
-
return (await
|
|
56123
|
+
return (await stat5(this.#file)).size;
|
|
55252
56124
|
} catch {
|
|
55253
56125
|
return -1;
|
|
55254
56126
|
}
|
|
@@ -55285,7 +56157,7 @@ var SessionIndex = class {
|
|
|
55285
56157
|
async #loadFile() {
|
|
55286
56158
|
let raw;
|
|
55287
56159
|
try {
|
|
55288
|
-
raw = await
|
|
56160
|
+
raw = await readFile7(this.#file, "utf8");
|
|
55289
56161
|
} catch (err) {
|
|
55290
56162
|
if (isErrnoException(err) && err.code === "ENOENT") return null;
|
|
55291
56163
|
throw err;
|
|
@@ -55326,13 +56198,13 @@ var SessionIndex = class {
|
|
|
55326
56198
|
const entries = /* @__PURE__ */ new Map();
|
|
55327
56199
|
let names = [];
|
|
55328
56200
|
try {
|
|
55329
|
-
names = await
|
|
56201
|
+
names = await readdir2(this.#sessionsDir, { withFileTypes: true });
|
|
55330
56202
|
} catch {
|
|
55331
56203
|
names = [];
|
|
55332
56204
|
}
|
|
55333
56205
|
for (const entry of names) {
|
|
55334
56206
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
55335
|
-
const meta = await this.#readMeta(
|
|
56207
|
+
const meta = await this.#readMeta(path10.join(this.#sessionsDir, entry.name), entry.name);
|
|
55336
56208
|
if (meta !== null) entries.set(meta.sessionId, meta);
|
|
55337
56209
|
}
|
|
55338
56210
|
const state = { entries, fileSize: -1, dirMtimeMs, rows: 0 };
|
|
@@ -55352,7 +56224,7 @@ var SessionIndex = class {
|
|
|
55352
56224
|
` : "";
|
|
55353
56225
|
try {
|
|
55354
56226
|
if (state.entries.size === 0 && state.dirMtimeMs === -1) {
|
|
55355
|
-
await
|
|
56227
|
+
await rm7(this.#file, { force: true }).catch(() => void 0);
|
|
55356
56228
|
state.fileSize = -1;
|
|
55357
56229
|
state.rows = 0;
|
|
55358
56230
|
return;
|
|
@@ -55383,9 +56255,9 @@ var SessionIndex = class {
|
|
|
55383
56255
|
};
|
|
55384
56256
|
|
|
55385
56257
|
// ../kernel/src/journal/checkpoints.ts
|
|
55386
|
-
import { createHash as
|
|
55387
|
-
import { access as access3, mkdir as
|
|
55388
|
-
import
|
|
56258
|
+
import { createHash as createHash13, randomBytes as randomBytes3 } from "node:crypto";
|
|
56259
|
+
import { access as access3, mkdir as mkdir6, readdir as readdir3, readFile as readFile8, rm as rm8 } from "node:fs/promises";
|
|
56260
|
+
import path11 from "node:path";
|
|
55389
56261
|
import { z as z18 } from "zod";
|
|
55390
56262
|
var ContextCheckpointTriggerSchema = z18.enum([
|
|
55391
56263
|
"manual",
|
|
@@ -55439,7 +56311,7 @@ function newCheckpointId(now = Date.now()) {
|
|
|
55439
56311
|
ulidLastRandom[i] = 0;
|
|
55440
56312
|
}
|
|
55441
56313
|
} else {
|
|
55442
|
-
ulidLastRandom = Array.from(
|
|
56314
|
+
ulidLastRandom = Array.from(randomBytes3(16), (b) => b & 31);
|
|
55443
56315
|
ulidLastTime = now;
|
|
55444
56316
|
}
|
|
55445
56317
|
let timePart = "";
|
|
@@ -55462,13 +56334,13 @@ var META_SUFFIX = ".meta.json";
|
|
|
55462
56334
|
var BODY_SUFFIX = ".json";
|
|
55463
56335
|
function checkpointsDirPath(root, sessionId) {
|
|
55464
56336
|
assertValidSessionId(sessionId);
|
|
55465
|
-
return
|
|
56337
|
+
return path11.join(root, sessionId);
|
|
55466
56338
|
}
|
|
55467
56339
|
function bodyFilePath(dir, checkpointId) {
|
|
55468
|
-
return
|
|
56340
|
+
return path11.join(dir, `${checkpointId}${BODY_SUFFIX}`);
|
|
55469
56341
|
}
|
|
55470
56342
|
function metaFilePath2(dir, checkpointId) {
|
|
55471
|
-
return
|
|
56343
|
+
return path11.join(dir, `${checkpointId}${META_SUFFIX}`);
|
|
55472
56344
|
}
|
|
55473
56345
|
var isRecord3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
55474
56346
|
var REF_PATTERN2 = /^sha256:([0-9a-f]{64})$/;
|
|
@@ -55500,7 +56372,7 @@ async function storeImages(messages, cpDir, attachmentsFrom) {
|
|
|
55500
56372
|
`messages 含 ${refs.length} 个已外置($ref)image 块,须以 opts.attachmentsFrom 指明附件来源会话目录`
|
|
55501
56373
|
);
|
|
55502
56374
|
}
|
|
55503
|
-
await
|
|
56375
|
+
await mkdir6(attachmentsDirPath(cpDir), { recursive: true });
|
|
55504
56376
|
for (const hex of refs) {
|
|
55505
56377
|
const target = attachmentFilePath(cpDir, hex);
|
|
55506
56378
|
let targetExists = true;
|
|
@@ -55512,7 +56384,7 @@ async function storeImages(messages, cpDir, attachmentsFrom) {
|
|
|
55512
56384
|
if (targetExists) continue;
|
|
55513
56385
|
let bytes;
|
|
55514
56386
|
try {
|
|
55515
|
-
bytes = await
|
|
56387
|
+
bytes = await readFile8(attachmentFilePath(attachmentsFrom, hex));
|
|
55516
56388
|
} catch (err) {
|
|
55517
56389
|
if (isErrnoException(err) && err.code === "ENOENT") continue;
|
|
55518
56390
|
throw err;
|
|
@@ -55529,7 +56401,7 @@ async function storeImages(messages, cpDir, attachmentsFrom) {
|
|
|
55529
56401
|
async function writeCheckpoint(root, cp, opts = {}) {
|
|
55530
56402
|
assertValidCheckpointId(cp.checkpointId);
|
|
55531
56403
|
const dir = checkpointsDirPath(root, cp.sessionId);
|
|
55532
|
-
await
|
|
56404
|
+
await mkdir6(dir, { recursive: true });
|
|
55533
56405
|
const { messages } = repairHistoryPairing(cp.messages);
|
|
55534
56406
|
const { messages: _ignored, ...head } = cp;
|
|
55535
56407
|
const metaCandidate = { ...head, schemaVersion: 1, messageCount: messages.length };
|
|
@@ -55552,7 +56424,7 @@ async function writeCheckpoint(root, cp, opts = {}) {
|
|
|
55552
56424
|
async function readJsonFile(filePath) {
|
|
55553
56425
|
let raw;
|
|
55554
56426
|
try {
|
|
55555
|
-
raw = await
|
|
56427
|
+
raw = await readFile8(filePath, "utf8");
|
|
55556
56428
|
} catch (err) {
|
|
55557
56429
|
if (isErrnoException(err) && err.code === "ENOENT") return null;
|
|
55558
56430
|
throw err;
|
|
@@ -55604,7 +56476,7 @@ async function listCheckpoints(root, sessionId) {
|
|
|
55604
56476
|
const dir = checkpointsDirPath(root, sessionId);
|
|
55605
56477
|
let names;
|
|
55606
56478
|
try {
|
|
55607
|
-
names = await
|
|
56479
|
+
names = await readdir3(dir);
|
|
55608
56480
|
} catch (err) {
|
|
55609
56481
|
if (isErrnoException(err) && err.code === "ENOENT") return [];
|
|
55610
56482
|
throw err;
|
|
@@ -55644,12 +56516,12 @@ async function deleteCheckpoint(root, sessionId, checkpointId, opts = {}) {
|
|
|
55644
56516
|
const refs = opts.gcAttachments === false ? [] : await collectBodyRefs(bodyFilePath(dir, checkpointId));
|
|
55645
56517
|
let existed = true;
|
|
55646
56518
|
try {
|
|
55647
|
-
await
|
|
56519
|
+
await rm8(bodyFilePath(dir, checkpointId));
|
|
55648
56520
|
} catch (err) {
|
|
55649
56521
|
if (!isErrnoException(err) || err.code !== "ENOENT") throw err;
|
|
55650
56522
|
existed = false;
|
|
55651
56523
|
}
|
|
55652
|
-
await
|
|
56524
|
+
await rm8(metaFilePath2(dir, checkpointId), { force: true });
|
|
55653
56525
|
if (refs.length > 0) await gcAttachments(dir, refs);
|
|
55654
56526
|
return existed;
|
|
55655
56527
|
}
|
|
@@ -55667,7 +56539,7 @@ async function gcAttachments(dir, candidates) {
|
|
|
55667
56539
|
const pending = new Set(candidates);
|
|
55668
56540
|
let names;
|
|
55669
56541
|
try {
|
|
55670
|
-
names = await
|
|
56542
|
+
names = await readdir3(dir);
|
|
55671
56543
|
} catch (err) {
|
|
55672
56544
|
if (isErrnoException(err) && err.code === "ENOENT") return;
|
|
55673
56545
|
throw err;
|
|
@@ -55677,10 +56549,10 @@ async function gcAttachments(dir, candidates) {
|
|
|
55677
56549
|
if (!name.endsWith(BODY_SUFFIX) || name.endsWith(META_SUFFIX)) continue;
|
|
55678
56550
|
const id = name.slice(0, -BODY_SUFFIX.length);
|
|
55679
56551
|
if (!CHECKPOINT_ID_PATTERN.test(id)) continue;
|
|
55680
|
-
for (const hex of await collectBodyRefs(
|
|
56552
|
+
for (const hex of await collectBodyRefs(path11.join(dir, name))) pending.delete(hex);
|
|
55681
56553
|
}
|
|
55682
56554
|
for (const hex of pending) {
|
|
55683
|
-
await
|
|
56555
|
+
await rm8(attachmentFilePath(dir, hex), { force: true });
|
|
55684
56556
|
}
|
|
55685
56557
|
}
|
|
55686
56558
|
async function applyRetention(root, sessionId, reference, retention) {
|
|
@@ -55726,7 +56598,7 @@ function detachInlineImage(block, attachments) {
|
|
|
55726
56598
|
if (!isRecord3(block)) return block;
|
|
55727
56599
|
if (block["t"] === "image" && typeof block["data"] === "string" && block["$ref"] === void 0) {
|
|
55728
56600
|
const bytes = Buffer.from(block["data"], "base64");
|
|
55729
|
-
const hex =
|
|
56601
|
+
const hex = createHash13("sha256").update(bytes).digest("hex");
|
|
55730
56602
|
attachments[hex] = bytes.toString("base64");
|
|
55731
56603
|
return { t: "image", mime: block["mime"], $ref: `sha256:${hex}` };
|
|
55732
56604
|
}
|
|
@@ -55787,9 +56659,9 @@ function decodeCheckpointImport(bytes, target) {
|
|
|
55787
56659
|
);
|
|
55788
56660
|
}
|
|
55789
56661
|
for (const [hex, b64] of Object.entries(bundle.attachments)) {
|
|
55790
|
-
const
|
|
55791
|
-
if (
|
|
55792
|
-
const digest =
|
|
56662
|
+
const bytesOf2 = Buffer.from(b64, "base64");
|
|
56663
|
+
if (bytesOf2.toString("base64") !== b64.replace(/\s+/g, "")) throw importInvalid(`附件 ${hex} 不是合法 base64`);
|
|
56664
|
+
const digest = createHash13("sha256").update(bytesOf2).digest("hex");
|
|
55793
56665
|
if (digest !== hex) throw importInvalid(`附件 ${hex} 字节摘要不符(实为 ${digest})`);
|
|
55794
56666
|
}
|
|
55795
56667
|
const messages = [];
|
|
@@ -55820,11 +56692,11 @@ function decodeCheckpointImport(bytes, target) {
|
|
|
55820
56692
|
}
|
|
55821
56693
|
|
|
55822
56694
|
// ../kernel/src/journal/rotate.ts
|
|
55823
|
-
import { access as access4, mkdir as
|
|
55824
|
-
import
|
|
56695
|
+
import { access as access4, mkdir as mkdir7, readdir as readdir4, readFile as readFile9, rm as rm9, stat as stat6 } from "node:fs/promises";
|
|
56696
|
+
import path12 from "node:path";
|
|
55825
56697
|
var ROTATION_NEXT_FILE_NAME = "journal.next.jsonl";
|
|
55826
56698
|
function rotationNextPath(sessionDir) {
|
|
55827
|
-
return
|
|
56699
|
+
return path12.join(sessionDir, ROTATION_NEXT_FILE_NAME);
|
|
55828
56700
|
}
|
|
55829
56701
|
async function fileExists2(filePath) {
|
|
55830
56702
|
try {
|
|
@@ -55859,28 +56731,28 @@ async function moveTempAttachments(tempDir, sessionDir) {
|
|
|
55859
56731
|
const tempAttachments = attachmentsDirPath(tempDir);
|
|
55860
56732
|
let names = [];
|
|
55861
56733
|
try {
|
|
55862
|
-
names = await
|
|
56734
|
+
names = await readdir4(tempAttachments);
|
|
55863
56735
|
} catch {
|
|
55864
56736
|
names = [];
|
|
55865
56737
|
}
|
|
55866
56738
|
if (names.length === 0) return;
|
|
55867
56739
|
const target = attachmentsDirPath(sessionDir);
|
|
55868
|
-
await
|
|
56740
|
+
await mkdir7(target, { recursive: true });
|
|
55869
56741
|
for (const name of names) {
|
|
55870
|
-
await renameWithRetry(
|
|
56742
|
+
await renameWithRetry(path12.join(tempAttachments, name), path12.join(target, name));
|
|
55871
56743
|
}
|
|
55872
56744
|
}
|
|
55873
56745
|
async function copyReferencedAttachments(tempDir, sessionDir, from) {
|
|
55874
56746
|
const { records } = await readAll(tempDir, { rehydrateImages: false });
|
|
55875
56747
|
const refs = collectImageRefs2(records.map((r) => r.payload));
|
|
55876
56748
|
if (refs.length === 0) return;
|
|
55877
|
-
await
|
|
56749
|
+
await mkdir7(attachmentsDirPath(sessionDir), { recursive: true });
|
|
55878
56750
|
for (const hex of refs) {
|
|
55879
56751
|
const target = attachmentFilePath(sessionDir, hex);
|
|
55880
56752
|
if (await fileExists2(target)) continue;
|
|
55881
56753
|
let bytes;
|
|
55882
56754
|
try {
|
|
55883
|
-
bytes = await
|
|
56755
|
+
bytes = await readFile9(attachmentFilePath(from, hex));
|
|
55884
56756
|
} catch (err) {
|
|
55885
56757
|
if (isErrnoException(err) && err.code === "ENOENT") continue;
|
|
55886
56758
|
throw err;
|
|
@@ -55896,8 +56768,8 @@ async function settleVolume(sessionDir) {
|
|
|
55896
56768
|
return true;
|
|
55897
56769
|
}
|
|
55898
56770
|
async function rotateVolume(sessionDir, build, opts = {}) {
|
|
55899
|
-
const tempDir =
|
|
55900
|
-
await
|
|
56771
|
+
const tempDir = path12.join(sessionDir, `.rotate-${process.pid}-${Date.now().toString(36)}`);
|
|
56772
|
+
await mkdir7(tempDir, { recursive: true });
|
|
55901
56773
|
try {
|
|
55902
56774
|
const writer = await JournalWriter.open(tempDir);
|
|
55903
56775
|
let cursor;
|
|
@@ -55913,16 +56785,16 @@ async function rotateVolume(sessionDir, build, opts = {}) {
|
|
|
55913
56785
|
}
|
|
55914
56786
|
await renameWithRetry(journalFilePath(tempDir), rotationNextPath(sessionDir));
|
|
55915
56787
|
await settleVolume(sessionDir);
|
|
55916
|
-
const { mtimeMs } = await
|
|
56788
|
+
const { mtimeMs } = await stat6(journalFilePath(sessionDir));
|
|
55917
56789
|
return { ...cursor, mtimeMs };
|
|
55918
56790
|
} finally {
|
|
55919
|
-
await
|
|
56791
|
+
await rm9(tempDir, { recursive: true, force: true }).catch(() => void 0);
|
|
55920
56792
|
}
|
|
55921
56793
|
}
|
|
55922
56794
|
|
|
55923
56795
|
// ../kernel/src/journal/fork.ts
|
|
55924
56796
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
55925
|
-
import { access as access5, mkdir as
|
|
56797
|
+
import { access as access5, mkdir as mkdir8, readFile as readFile10, stat as stat7 } from "node:fs/promises";
|
|
55926
56798
|
var FORK_DEFAULT_PRODUCER = "kernel";
|
|
55927
56799
|
function journalKindOf(message) {
|
|
55928
56800
|
if (message.role === "assistant") return "assistant_message";
|
|
@@ -55958,13 +56830,13 @@ async function pathExists(filePath) {
|
|
|
55958
56830
|
}
|
|
55959
56831
|
async function copyRefAttachments(refs, from, sessionDir) {
|
|
55960
56832
|
if (refs.length === 0) return;
|
|
55961
|
-
await
|
|
56833
|
+
await mkdir8(attachmentsDirPath(sessionDir), { recursive: true });
|
|
55962
56834
|
for (const hex of refs) {
|
|
55963
56835
|
const target = attachmentFilePath(sessionDir, hex);
|
|
55964
56836
|
if (await pathExists(target)) continue;
|
|
55965
56837
|
let bytes;
|
|
55966
56838
|
try {
|
|
55967
|
-
bytes = await
|
|
56839
|
+
bytes = await readFile10(attachmentFilePath(from, hex));
|
|
55968
56840
|
} catch (err) {
|
|
55969
56841
|
if (isErrnoException(err) && err.code === "ENOENT") continue;
|
|
55970
56842
|
throw err;
|
|
@@ -56059,27 +56931,27 @@ async function forkSessionFromCheckpoint(input) {
|
|
|
56059
56931
|
} finally {
|
|
56060
56932
|
await lock.release();
|
|
56061
56933
|
}
|
|
56062
|
-
const { mtimeMs } = await
|
|
56934
|
+
const { mtimeMs } = await stat7(journalFilePath(sessionDir));
|
|
56063
56935
|
return { sessionId, sessionDir, cursor: { ...cursor, mtimeMs } };
|
|
56064
56936
|
}
|
|
56065
56937
|
|
|
56066
56938
|
// ../kernel/src/session/cwd.ts
|
|
56067
|
-
import { realpath, stat as
|
|
56068
|
-
import
|
|
56939
|
+
import { realpath, stat as stat8 } from "node:fs/promises";
|
|
56940
|
+
import path13 from "node:path";
|
|
56069
56941
|
var CASE_INSENSITIVE = process.platform === "win32";
|
|
56070
56942
|
function insideRealSubtree(child, base) {
|
|
56071
56943
|
const c = CASE_INSENSITIVE ? child.toLowerCase() : child;
|
|
56072
56944
|
const b = CASE_INSENSITIVE ? base.toLowerCase() : base;
|
|
56073
|
-
const rel =
|
|
56074
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
56945
|
+
const rel = path13.relative(b, c);
|
|
56946
|
+
return rel === "" || !rel.startsWith("..") && !path13.isAbsolute(rel);
|
|
56075
56947
|
}
|
|
56076
56948
|
async function probeDirectory(candidate) {
|
|
56077
|
-
if (!
|
|
56949
|
+
if (!path13.isAbsolute(candidate)) {
|
|
56078
56950
|
return { ok: false, reason: "not_absolute", detail: `cwd 须为绝对路径(不展开 ~):${candidate}` };
|
|
56079
56951
|
}
|
|
56080
56952
|
let isDirectory;
|
|
56081
56953
|
try {
|
|
56082
|
-
isDirectory = (await
|
|
56954
|
+
isDirectory = (await stat8(candidate)).isDirectory();
|
|
56083
56955
|
} catch (err) {
|
|
56084
56956
|
const code = isErrnoException(err) ? err.code : void 0;
|
|
56085
56957
|
return { ok: false, reason: "not_found", detail: `cwd 不可访问(${code ?? "io error"}):${candidate}` };
|
|
@@ -56107,7 +56979,7 @@ async function resolveSessionCwd(input) {
|
|
|
56107
56979
|
};
|
|
56108
56980
|
}
|
|
56109
56981
|
if ("resolve" in policy) {
|
|
56110
|
-
if (!
|
|
56982
|
+
if (!path13.isAbsolute(requested)) {
|
|
56111
56983
|
return { ok: false, reason: "not_absolute", detail: `cwd 须为绝对路径(不展开 ~):${requested}` };
|
|
56112
56984
|
}
|
|
56113
56985
|
let resolved;
|
|
@@ -56122,7 +56994,7 @@ async function resolveSessionCwd(input) {
|
|
|
56122
56994
|
}
|
|
56123
56995
|
const probed2 = await probeDirectory(resolved);
|
|
56124
56996
|
if (!probed2.ok) return probed2;
|
|
56125
|
-
return { ok: true, cwd:
|
|
56997
|
+
return { ok: true, cwd: path13.resolve(resolved) };
|
|
56126
56998
|
}
|
|
56127
56999
|
const probed = await probeDirectory(requested);
|
|
56128
57000
|
if (!probed.ok) return probed;
|
|
@@ -56133,7 +57005,7 @@ async function resolveSessionCwd(input) {
|
|
|
56133
57005
|
} catch {
|
|
56134
57006
|
continue;
|
|
56135
57007
|
}
|
|
56136
|
-
if (insideRealSubtree(probed.real, realRoot)) return { ok: true, cwd:
|
|
57008
|
+
if (insideRealSubtree(probed.real, realRoot)) return { ok: true, cwd: path13.resolve(requested) };
|
|
56137
57009
|
}
|
|
56138
57010
|
return {
|
|
56139
57011
|
ok: false,
|
|
@@ -56516,7 +57388,7 @@ var SESSION_EVENT_VOCABULARY = {
|
|
|
56516
57388
|
var SESSION_EVENT_KINDS = Object.keys(SESSION_EVENT_VOCABULARY);
|
|
56517
57389
|
|
|
56518
57390
|
// ../kernel/src/tools/files/read.ts
|
|
56519
|
-
import
|
|
57391
|
+
import path14 from "node:path";
|
|
56520
57392
|
import { z as z19 } from "zod";
|
|
56521
57393
|
|
|
56522
57394
|
// ../kernel/src/tools/files/encoding.ts
|
|
@@ -56583,19 +57455,19 @@ function truncateLine(line) {
|
|
|
56583
57455
|
return `${line.slice(0, cut)}…[line truncated: ${line.length} chars total; use Grep to inspect the rest]`;
|
|
56584
57456
|
}
|
|
56585
57457
|
async function findSimilarFiles(fs2, filePath) {
|
|
56586
|
-
const dir =
|
|
56587
|
-
const targetBase =
|
|
56588
|
-
const targetName =
|
|
57458
|
+
const dir = path14.dirname(filePath);
|
|
57459
|
+
const targetBase = path14.basename(filePath);
|
|
57460
|
+
const targetName = path14.parse(filePath).name.toLowerCase();
|
|
56589
57461
|
try {
|
|
56590
57462
|
const entries = await fs2.readdir(dir);
|
|
56591
57463
|
return entries.filter((entry) => entry.isFile()).map((entry) => entry.name).filter(
|
|
56592
|
-
(name) => name.toLowerCase() !== targetBase.toLowerCase() &&
|
|
56593
|
-
).slice(0, 3).map((name) =>
|
|
57464
|
+
(name) => name.toLowerCase() !== targetBase.toLowerCase() && path14.parse(name).name.toLowerCase() === targetName
|
|
57465
|
+
).slice(0, 3).map((name) => path14.join(dir, name));
|
|
56594
57466
|
} catch {
|
|
56595
57467
|
return [];
|
|
56596
57468
|
}
|
|
56597
57469
|
}
|
|
56598
|
-
async function executeImageRead(resolved, args, ctx, fs2,
|
|
57470
|
+
async function executeImageRead(resolved, args, ctx, fs2, stat11, options) {
|
|
56599
57471
|
let mode;
|
|
56600
57472
|
try {
|
|
56601
57473
|
mode = options.imageInput?.();
|
|
@@ -56614,9 +57486,9 @@ async function executeImageRead(resolved, args, ctx, fs2, stat10, options) {
|
|
|
56614
57486
|
"offset/limit apply to text files only. Call Read again without offset/limit to read this image file."
|
|
56615
57487
|
);
|
|
56616
57488
|
}
|
|
56617
|
-
if (
|
|
57489
|
+
if (stat11.size > READ_IMAGE_RAW_MAX_BYTES) {
|
|
56618
57490
|
return errorResult(
|
|
56619
|
-
`Image file is ${
|
|
57491
|
+
`Image file is ${stat11.size} bytes, which exceeds the per-image limit of ${READ_IMAGE_RAW_MAX_BYTES} bytes (5 MiB base64-encoded, aligned with the platform cap). Downscale or compress the image, then retry.`
|
|
56620
57492
|
);
|
|
56621
57493
|
}
|
|
56622
57494
|
let buf;
|
|
@@ -56631,10 +57503,10 @@ async function executeImageRead(resolved, args, ctx, fs2, stat10, options) {
|
|
|
56631
57503
|
const probed = probeImage(buf);
|
|
56632
57504
|
if (probed === null) {
|
|
56633
57505
|
return errorResult(
|
|
56634
|
-
`File has an image extension but its content is not a readable PNG/JPEG/GIF/WebP image (bad or truncated header): ${
|
|
57506
|
+
`File has an image extension but its content is not a readable PNG/JPEG/GIF/WebP image (bad or truncated header): ${path14.basename(resolved)}. If it is actually a text file, rename it; otherwise re-export the image and retry.`
|
|
56635
57507
|
);
|
|
56636
57508
|
}
|
|
56637
|
-
registerFileRead(ctx, normalizeFileKey(resolved),
|
|
57509
|
+
registerFileRead(ctx, normalizeFileKey(resolved), stat11.mtimeMs);
|
|
56638
57510
|
const data = {
|
|
56639
57511
|
path: resolved,
|
|
56640
57512
|
mime: probed.mime,
|
|
@@ -56642,7 +57514,7 @@ async function executeImageRead(resolved, args, ctx, fs2, stat10, options) {
|
|
|
56642
57514
|
height: probed.height,
|
|
56643
57515
|
bytes: buf.length
|
|
56644
57516
|
};
|
|
56645
|
-
const meta = `Image file: ${
|
|
57517
|
+
const meta = `Image file: ${path14.basename(resolved)}
|
|
56646
57518
|
Format: ${probed.mime}
|
|
56647
57519
|
Dimensions: ${probed.width}x${probed.height} px
|
|
56648
57520
|
Size: ${buf.length} bytes`;
|
|
@@ -56665,8 +57537,8 @@ function createReadTool(options = {}) {
|
|
|
56665
57537
|
isConcurrencySafe: true,
|
|
56666
57538
|
touchedPathsOf(args) {
|
|
56667
57539
|
const parsed = ReadArgsSchema.safeParse(args);
|
|
56668
|
-
if (!parsed.success || !
|
|
56669
|
-
return [
|
|
57540
|
+
if (!parsed.success || !path14.isAbsolute(parsed.data.file_path)) return [];
|
|
57541
|
+
return [path14.resolve(parsed.data.file_path)];
|
|
56670
57542
|
},
|
|
56671
57543
|
async execute(args, ctx) {
|
|
56672
57544
|
if (ctx.signal.aborted) {
|
|
@@ -56680,15 +57552,15 @@ function createReadTool(options = {}) {
|
|
|
56680
57552
|
if (invalid) {
|
|
56681
57553
|
return invalid;
|
|
56682
57554
|
}
|
|
56683
|
-
const resolved =
|
|
57555
|
+
const resolved = path14.resolve(args.file_path);
|
|
56684
57556
|
const fs2 = fsOf(ctx);
|
|
56685
57557
|
const realTarget = await checkRealTarget("Read", resolved, { cwd: ctx.cwd, access: "read", fs: fs2 });
|
|
56686
57558
|
if (!realTarget.ok) {
|
|
56687
57559
|
return errorResult(realTarget.reason);
|
|
56688
57560
|
}
|
|
56689
|
-
let
|
|
57561
|
+
let stat11;
|
|
56690
57562
|
try {
|
|
56691
|
-
|
|
57563
|
+
stat11 = await fs2.stat(resolved);
|
|
56692
57564
|
} catch (err) {
|
|
56693
57565
|
if (fsErrorCode(err) === "ENOENT") {
|
|
56694
57566
|
const similar = await findSimilarFiles(fs2, resolved);
|
|
@@ -56697,11 +57569,11 @@ function createReadTool(options = {}) {
|
|
|
56697
57569
|
}
|
|
56698
57570
|
return errorResult(`Failed to read file: ${errorMessageOf2(err)}`);
|
|
56699
57571
|
}
|
|
56700
|
-
if (
|
|
57572
|
+
if (stat11.isDirectory()) {
|
|
56701
57573
|
return errorResult(`Path is a directory, not a file: ${resolved}.`);
|
|
56702
57574
|
}
|
|
56703
|
-
if (isImageFileExtension(
|
|
56704
|
-
return executeImageRead(resolved, args, ctx, fs2,
|
|
57575
|
+
if (isImageFileExtension(path14.extname(resolved))) {
|
|
57576
|
+
return executeImageRead(resolved, args, ctx, fs2, stat11, options);
|
|
56705
57577
|
}
|
|
56706
57578
|
const fileKey = normalizeFileKey(resolved);
|
|
56707
57579
|
const effectiveOffset = args.offset ?? 1;
|
|
@@ -56709,7 +57581,7 @@ function createReadTool(options = {}) {
|
|
|
56709
57581
|
const dupWindow = takeDuplicateReadWindow(
|
|
56710
57582
|
ctx,
|
|
56711
57583
|
fileKey,
|
|
56712
|
-
|
|
57584
|
+
stat11.mtimeMs,
|
|
56713
57585
|
effectiveOffset,
|
|
56714
57586
|
effectiveLimit
|
|
56715
57587
|
);
|
|
@@ -56726,9 +57598,9 @@ function createReadTool(options = {}) {
|
|
|
56726
57598
|
data2
|
|
56727
57599
|
);
|
|
56728
57600
|
}
|
|
56729
|
-
if (
|
|
57601
|
+
if (stat11.size > READ_MAX_FULL_BYTES && args.offset === void 0 && args.limit === void 0) {
|
|
56730
57602
|
return errorResult(
|
|
56731
|
-
`File is ${
|
|
57603
|
+
`File is ${stat11.size} bytes, which exceeds the ${READ_MAX_FULL_BYTES}-byte limit for reading the whole file at once (large files inflate context: this one would be roughly ${Math.ceil(stat11.size / 4)}+ tokens). Use the offset and limit parameters to read it in pages, or use Grep to locate the relevant sections first.`
|
|
56732
57604
|
);
|
|
56733
57605
|
}
|
|
56734
57606
|
let buf;
|
|
@@ -56747,7 +57619,7 @@ function createReadTool(options = {}) {
|
|
|
56747
57619
|
);
|
|
56748
57620
|
}
|
|
56749
57621
|
if (decoded.text.length === 0) {
|
|
56750
|
-
registerFileRead(ctx, fileKey,
|
|
57622
|
+
registerFileRead(ctx, fileKey, stat11.mtimeMs, {
|
|
56751
57623
|
offset: effectiveOffset,
|
|
56752
57624
|
limit: effectiveLimit,
|
|
56753
57625
|
totalLines: 0,
|
|
@@ -56761,7 +57633,7 @@ function createReadTool(options = {}) {
|
|
|
56761
57633
|
const startLine = effectiveOffset;
|
|
56762
57634
|
const maxLines = effectiveLimit;
|
|
56763
57635
|
if (startLine > totalLines) {
|
|
56764
|
-
registerFileRead(ctx, fileKey,
|
|
57636
|
+
registerFileRead(ctx, fileKey, stat11.mtimeMs, {
|
|
56765
57637
|
offset: effectiveOffset,
|
|
56766
57638
|
limit: effectiveLimit,
|
|
56767
57639
|
totalLines,
|
|
@@ -56780,7 +57652,7 @@ function createReadTool(options = {}) {
|
|
|
56780
57652
|
text += `
|
|
56781
57653
|
… (showing lines ${startLine}-${endLine} of ${totalLines}; use offset=${endLine + 1} to continue)`;
|
|
56782
57654
|
}
|
|
56783
|
-
registerFileRead(ctx, fileKey,
|
|
57655
|
+
registerFileRead(ctx, fileKey, stat11.mtimeMs, {
|
|
56784
57656
|
offset: effectiveOffset,
|
|
56785
57657
|
limit: effectiveLimit,
|
|
56786
57658
|
totalLines,
|
|
@@ -58056,35 +58928,35 @@ var SUBAGENT_TYPE_TIER_MAP = {
|
|
|
58056
58928
|
"test-runner": "inherit"
|
|
58057
58929
|
};
|
|
58058
58930
|
function assertDispatchPolicyInvariants() {
|
|
58059
|
-
const
|
|
58931
|
+
const fail2 = (detail) => {
|
|
58060
58932
|
throw new Error(`dispatch-policy 不变式违约(装载期 fail-fast):${detail}`);
|
|
58061
58933
|
};
|
|
58062
58934
|
const tierList = SUBAGENT_DISPATCH_TIERS;
|
|
58063
58935
|
const defaultTier = DEFAULT_SUBAGENT_DISPATCH_TIER;
|
|
58064
|
-
if (tierList.length === 0)
|
|
58936
|
+
if (tierList.length === 0) fail2("档位词表不得为空");
|
|
58065
58937
|
if (new Set(tierList).size !== tierList.length) {
|
|
58066
|
-
|
|
58938
|
+
fail2("档位词表存在重复项");
|
|
58067
58939
|
}
|
|
58068
58940
|
if (!tierList.includes("inherit")) {
|
|
58069
|
-
|
|
58941
|
+
fail2("档位词表必含 'inherit'(fail-safe 锚:未知类型/回落链尽头的现状档)");
|
|
58070
58942
|
}
|
|
58071
58943
|
if (defaultTier !== "inherit") {
|
|
58072
|
-
|
|
58944
|
+
fail2(
|
|
58073
58945
|
`缺省档位必须为 'inherit'(新增/未知类型恒不降档的 fail-safe 语义),得到 '${defaultTier}'`
|
|
58074
58946
|
);
|
|
58075
58947
|
}
|
|
58076
58948
|
const tiers = new Set(SUBAGENT_DISPATCH_TIERS);
|
|
58077
58949
|
for (const [name, tier] of Object.entries(SUBAGENT_TYPE_TIER_MAP)) {
|
|
58078
58950
|
if (!AGENT_NAME_RE.test(name)) {
|
|
58079
|
-
|
|
58951
|
+
fail2(`映射表键 '${name}' 不符合代理名约束(${String(AGENT_NAME_RE)})`);
|
|
58080
58952
|
}
|
|
58081
58953
|
if (!tiers.has(tier)) {
|
|
58082
|
-
|
|
58954
|
+
fail2(`映射表值 '${tier}'(键 '${name}')不在档位词表内`);
|
|
58083
58955
|
}
|
|
58084
58956
|
}
|
|
58085
58957
|
for (const template of BUILTIN_AGENT_TEMPLATES) {
|
|
58086
58958
|
if (SUBAGENT_TYPE_TIER_MAP[template.name] === void 0) {
|
|
58087
|
-
|
|
58959
|
+
fail2(
|
|
58088
58960
|
`内置模板 '${template.name}' 未在 SUBAGENT_TYPE_TIER_MAP 显式登记档位——新增内置类型必须做一次显式档位决策(fail-safe 建制)`
|
|
58089
58961
|
);
|
|
58090
58962
|
}
|
|
@@ -58741,8 +59613,8 @@ function suggestedAudioName(audio) {
|
|
|
58741
59613
|
async function sinkInlineAudio(sink, audio) {
|
|
58742
59614
|
try {
|
|
58743
59615
|
const bytes = new Uint8Array(Buffer.from(audio.b64, "base64"));
|
|
58744
|
-
const
|
|
58745
|
-
return { path:
|
|
59616
|
+
const path18 = await sink(bytes, audio.mime, suggestedAudioName(audio));
|
|
59617
|
+
return { path: path18 };
|
|
58746
59618
|
} catch (err) {
|
|
58747
59619
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
58748
59620
|
}
|
|
@@ -60130,7 +61002,7 @@ function createServeObservability(deps) {
|
|
|
60130
61002
|
let requestsTotal = 0;
|
|
60131
61003
|
let closed = false;
|
|
60132
61004
|
const eventLoopDelay = () => eld.sample();
|
|
60133
|
-
const
|
|
61005
|
+
const collect2 = () => {
|
|
60134
61006
|
const v1 = deps.v1Active();
|
|
60135
61007
|
const v2 = deps.v2();
|
|
60136
61008
|
metrics.sessionsActive.set(v1, { face: "v1" });
|
|
@@ -60138,10 +61010,10 @@ function createServeObservability(deps) {
|
|
|
60138
61010
|
if (v2?.pending !== void 0) metrics.sessionsPending.set(v2.pending);
|
|
60139
61011
|
if (v2?.retainedEnded !== void 0) metrics.sessionsRetainedEnded.set(v2.retainedEnded);
|
|
60140
61012
|
metrics.sseConnectionsActive.set(sseOpen);
|
|
60141
|
-
const
|
|
60142
|
-
metrics.eventLoopDelayMs.set(
|
|
60143
|
-
metrics.eventLoopDelayMs.set(
|
|
60144
|
-
metrics.eventLoopDelayMs.set(
|
|
61013
|
+
const delay2 = eventLoopDelay();
|
|
61014
|
+
metrics.eventLoopDelayMs.set(delay2.p50, { stat: "p50" });
|
|
61015
|
+
metrics.eventLoopDelayMs.set(delay2.p99, { stat: "p99" });
|
|
61016
|
+
metrics.eventLoopDelayMs.set(delay2.max, { stat: "max" });
|
|
60145
61017
|
metrics.residentMemoryBytes.set(process.memoryUsage.rss());
|
|
60146
61018
|
const notifier = deps.notifierStats();
|
|
60147
61019
|
if (notifier !== void 0) {
|
|
@@ -60176,7 +61048,7 @@ function createServeObservability(deps) {
|
|
|
60176
61048
|
return void 0;
|
|
60177
61049
|
}
|
|
60178
61050
|
};
|
|
60179
|
-
const offCollect = registry.onCollect(
|
|
61051
|
+
const offCollect = registry.onCollect(collect2);
|
|
60180
61052
|
const readiness = () => {
|
|
60181
61053
|
const reasons = [];
|
|
60182
61054
|
if (deps.closing()) reasons.push("closing");
|
|
@@ -61351,8 +62223,8 @@ var TansrSdkError = class extends Error {
|
|
|
61351
62223
|
};
|
|
61352
62224
|
|
|
61353
62225
|
// ../sdk/src/skills.ts
|
|
61354
|
-
import
|
|
61355
|
-
var NO_DISCOVERY_ROOT =
|
|
62226
|
+
import path15 from "node:path";
|
|
62227
|
+
var NO_DISCOVERY_ROOT = path15.resolve(path15.sep, ".tansr-sdk-no-discovery");
|
|
61356
62228
|
|
|
61357
62229
|
// ../providers/src/anthropic/wire.ts
|
|
61358
62230
|
function asRecord(v) {
|
|
@@ -63429,7 +64301,7 @@ var OpenAIResponsesAdapter = class {
|
|
|
63429
64301
|
};
|
|
63430
64302
|
|
|
63431
64303
|
// ../providers/src/retry/attempt-observer.ts
|
|
63432
|
-
import { createHash as
|
|
64304
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
63433
64305
|
var PROVIDER_CALL_META_FIELD = "callMeta";
|
|
63434
64306
|
function providerCallMetaOf(options) {
|
|
63435
64307
|
if (options === void 0) return void 0;
|
|
@@ -63458,12 +64330,12 @@ function endpointKeyOf(baseUrl) {
|
|
|
63458
64330
|
let normalized;
|
|
63459
64331
|
try {
|
|
63460
64332
|
const url = new URL(baseUrl);
|
|
63461
|
-
const
|
|
63462
|
-
normalized = `${url.protocol}//${url.host}${
|
|
64333
|
+
const path18 = url.pathname.replace(/\/+$/, "");
|
|
64334
|
+
normalized = `${url.protocol}//${url.host}${path18}`.toLowerCase();
|
|
63463
64335
|
} catch {
|
|
63464
64336
|
normalized = baseUrl.trim().replace(/\/+$/, "").toLowerCase();
|
|
63465
64337
|
}
|
|
63466
|
-
return
|
|
64338
|
+
return createHash14("sha256").update(normalized, "utf8").digest("hex").slice(0, 16);
|
|
63467
64339
|
}
|
|
63468
64340
|
function safeAttemptCall(fn) {
|
|
63469
64341
|
if (fn === void 0) return;
|
|
@@ -63616,16 +64488,16 @@ function sendableTwpReasoningContent(features) {
|
|
|
63616
64488
|
}
|
|
63617
64489
|
|
|
63618
64490
|
// ../providers/src/twp/signing.ts
|
|
63619
|
-
import { createHash as
|
|
64491
|
+
import { createHash as createHash15, createHmac as createHmac2, randomBytes as randomBytes4 } from "node:crypto";
|
|
63620
64492
|
var TWP_SIGNING_ALGORITHM = "TWP1-HMAC-SHA256";
|
|
63621
64493
|
var TWP_NONCE_LENGTH = 24;
|
|
63622
64494
|
function deriveTwpSigningKey(secretKey) {
|
|
63623
|
-
return
|
|
64495
|
+
return createHash15("sha256").update(secretKey, "utf8").digest();
|
|
63624
64496
|
}
|
|
63625
64497
|
function sha256Hex2(data) {
|
|
63626
|
-
return
|
|
64498
|
+
return createHash15("sha256").update(typeof data === "string" ? Buffer.from(data, "utf8") : data).digest("hex");
|
|
63627
64499
|
}
|
|
63628
|
-
function generateTwpNonce(random =
|
|
64500
|
+
function generateTwpNonce(random = randomBytes4) {
|
|
63629
64501
|
return random(TWP_NONCE_LENGTH / 2).toString("hex");
|
|
63630
64502
|
}
|
|
63631
64503
|
function buildTwpSigningString(input) {
|
|
@@ -64642,9 +65514,9 @@ var MissingApiKeyError = class extends ProviderRegistryError {
|
|
|
64642
65514
|
var CyclicFallbackError = class extends ProviderRegistryError {
|
|
64643
65515
|
/** 成环路径,末项为再次出现的别名,如 ['main','fast','main'] */
|
|
64644
65516
|
path;
|
|
64645
|
-
constructor(
|
|
64646
|
-
super("cyclic_fallback", `Cyclic fallback chain: ${
|
|
64647
|
-
this.path =
|
|
65517
|
+
constructor(path18) {
|
|
65518
|
+
super("cyclic_fallback", `Cyclic fallback chain: ${path18.join(" -> ")}`);
|
|
65519
|
+
this.path = path18;
|
|
64648
65520
|
}
|
|
64649
65521
|
};
|
|
64650
65522
|
|
|
@@ -65132,9 +66004,9 @@ function pushUnique(out, seen, resolved) {
|
|
|
65132
66004
|
seen.add(dedupeKey);
|
|
65133
66005
|
out.push(resolved);
|
|
65134
66006
|
}
|
|
65135
|
-
function expandInto(config, alias,
|
|
65136
|
-
if (
|
|
65137
|
-
const nextPath = [...
|
|
66007
|
+
function expandInto(config, alias, path18, out, seen) {
|
|
66008
|
+
if (path18.includes(alias)) throw new CyclicFallbackError([...path18, alias]);
|
|
66009
|
+
const nextPath = [...path18, alias];
|
|
65138
66010
|
pushUnique(out, seen, resolveAliasOrRef(config, alias));
|
|
65139
66011
|
for (const entry of config.fallbacks[alias] ?? []) {
|
|
65140
66012
|
if (entry.includes("/")) {
|
|
@@ -66068,7 +66940,7 @@ function createTokenBucket(origin, options) {
|
|
|
66068
66940
|
waiter.signal.removeEventListener("abort", waiter.onAbort);
|
|
66069
66941
|
}
|
|
66070
66942
|
};
|
|
66071
|
-
const
|
|
66943
|
+
const drain2 = () => {
|
|
66072
66944
|
refill();
|
|
66073
66945
|
while (queue.length > 0 && tokens >= 1) {
|
|
66074
66946
|
const waiter = queue.shift();
|
|
@@ -66085,7 +66957,7 @@ function createTokenBucket(origin, options) {
|
|
|
66085
66957
|
const waitMs = Math.max(1, Math.ceil(needed / ratePerMs));
|
|
66086
66958
|
refillTimer = clock.setTimeout(() => {
|
|
66087
66959
|
refillTimer = void 0;
|
|
66088
|
-
|
|
66960
|
+
drain2();
|
|
66089
66961
|
}, waitMs);
|
|
66090
66962
|
};
|
|
66091
66963
|
const detail = () => `tokens ${tokens.toFixed(2)}/${burst} @ ${ratePerMinute}/min, queued ${queue.length}/${maxQueue}`;
|
|
@@ -68653,7 +69525,7 @@ function buildClientFromRegistry(registry, aliasOrRef, onProviderSelected) {
|
|
|
68653
69525
|
}
|
|
68654
69526
|
|
|
68655
69527
|
// ../sdk/src/adjudication/prompts.ts
|
|
68656
|
-
import { createHash as
|
|
69528
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
68657
69529
|
var STAGE1_MAX_TOKENS = 64;
|
|
68658
69530
|
var STAGE2_MAX_TOKENS = 1024;
|
|
68659
69531
|
var TWO_STAGE_TIMEOUT_MS = 15e3;
|
|
@@ -68750,7 +69622,7 @@ function serializeTimeoutPolicy(policy) {
|
|
|
68750
69622
|
].join(";");
|
|
68751
69623
|
}
|
|
68752
69624
|
function makeProtocolFingerprint(components) {
|
|
68753
|
-
return
|
|
69625
|
+
return createHash16("sha256").update(components.join("\n\0")).digest("hex").slice(0, 16);
|
|
68754
69626
|
}
|
|
68755
69627
|
var PAYLOAD_VERSION_COMPONENT = "payload:v4-engine-facts-shell";
|
|
68756
69628
|
var SETTLE_COMPONENT = "settle:verdict-first";
|
|
@@ -69928,7 +70800,7 @@ function platformErrorOf(body, status) {
|
|
|
69928
70800
|
}
|
|
69929
70801
|
|
|
69930
70802
|
// ../sdk/src/platform/bundle-cache.ts
|
|
69931
|
-
import { createHash as
|
|
70803
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
69932
70804
|
var DEFAULT_BUNDLE_CACHE_TTL_MS = 6e4;
|
|
69933
70805
|
var DEFAULT_MAX_BUNDLE_ENTRIES = 16;
|
|
69934
70806
|
var DEFAULT_MAX_FEATURE_ENTRIES = 1e5;
|
|
@@ -69968,7 +70840,7 @@ var Lru = class {
|
|
|
69968
70840
|
}
|
|
69969
70841
|
};
|
|
69970
70842
|
function tokenScope(token) {
|
|
69971
|
-
return
|
|
70843
|
+
return createHash17("sha256").update(token, "utf8").digest("hex");
|
|
69972
70844
|
}
|
|
69973
70845
|
function bundleKey(base, appId) {
|
|
69974
70846
|
return `${base}\0${appId ?? ""}`;
|
|
@@ -70237,9 +71109,9 @@ function stripReminderBlocks(messages) {
|
|
|
70237
71109
|
}
|
|
70238
71110
|
|
|
70239
71111
|
// src/v2/agent-session-store.ts
|
|
70240
|
-
import { createHash as
|
|
70241
|
-
import { access as access6, mkdir as
|
|
70242
|
-
import
|
|
71112
|
+
import { createHash as createHash18, randomUUID as randomUUID10 } from "node:crypto";
|
|
71113
|
+
import { access as access6, mkdir as mkdir9, readFile as readFile11, rm as rm10, stat as stat9 } from "node:fs/promises";
|
|
71114
|
+
import path16 from "node:path";
|
|
70243
71115
|
var AgentSessionStoreError = class extends Error {
|
|
70244
71116
|
code = "session_store_corrupted";
|
|
70245
71117
|
constructor(sessionId, detail, cause) {
|
|
@@ -70251,7 +71123,7 @@ var AgentSessionStoreError = class extends Error {
|
|
|
70251
71123
|
}
|
|
70252
71124
|
};
|
|
70253
71125
|
function endUserKeyOf(endUserId) {
|
|
70254
|
-
return
|
|
71126
|
+
return createHash18("sha256").update(endUserId, "utf8").digest("hex").slice(0, 16);
|
|
70255
71127
|
}
|
|
70256
71128
|
async function fileExists3(filePath) {
|
|
70257
71129
|
try {
|
|
@@ -70285,7 +71157,7 @@ function sessionTitleOf(messages) {
|
|
|
70285
71157
|
}
|
|
70286
71158
|
async function readRawMeta(sessionDir) {
|
|
70287
71159
|
try {
|
|
70288
|
-
const parsed = JSON.parse(await
|
|
71160
|
+
const parsed = JSON.parse(await readFile11(metaFilePath(sessionDir), "utf8"));
|
|
70289
71161
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
|
|
70290
71162
|
return parsed;
|
|
70291
71163
|
} catch {
|
|
@@ -70444,7 +71316,7 @@ function createServeAgentSessionStore(options) {
|
|
|
70444
71316
|
});
|
|
70445
71317
|
return task;
|
|
70446
71318
|
}
|
|
70447
|
-
const domainRootOfKey = (endUserKey) =>
|
|
71319
|
+
const domainRootOfKey = (endUserKey) => path16.join(options.dir, "agent-sessions", endUserKey);
|
|
70448
71320
|
const domainRoot = (endUserId) => domainRootOfKey(endUserKeyOf(endUserId));
|
|
70449
71321
|
const hooksOf = (sessionId, endUserKey, sessionDir) => tier?.bind({ sessionId, endUserKey, sessionDir });
|
|
70450
71322
|
const writerOptionsFor = (hooks) => hooks === void 0 ? writerOptions : { ...writerOptions, onSegmentSealed: hooks.onSegmentSealed };
|
|
@@ -70473,7 +71345,7 @@ function createServeAgentSessionStore(options) {
|
|
|
70473
71345
|
cursors.set(key2, tail);
|
|
70474
71346
|
}
|
|
70475
71347
|
async function withMtime(sessionDir, cursor) {
|
|
70476
|
-
const { mtimeMs } = await
|
|
71348
|
+
const { mtimeMs } = await stat9(journalFilePath(sessionDir));
|
|
70477
71349
|
return { ...cursor, mtimeMs };
|
|
70478
71350
|
}
|
|
70479
71351
|
async function patchRawMeta(sessionDir, mutate) {
|
|
@@ -70544,16 +71416,16 @@ function createServeAgentSessionStore(options) {
|
|
|
70544
71416
|
}
|
|
70545
71417
|
if (await readRawMeta(sessionDir) !== null) return false;
|
|
70546
71418
|
const existed = await fileExists3(sessionDir);
|
|
70547
|
-
await
|
|
71419
|
+
await mkdir9(sessionDir, { recursive: true });
|
|
70548
71420
|
let restored;
|
|
70549
71421
|
try {
|
|
70550
71422
|
restored = await tier.restore({ sessionId, endUserKey, sessionDir });
|
|
70551
71423
|
} catch (err) {
|
|
70552
|
-
if (!existed) await
|
|
71424
|
+
if (!existed) await rm10(sessionDir, { recursive: true, force: true }).catch(() => void 0);
|
|
70553
71425
|
throw readError(sessionId, err);
|
|
70554
71426
|
}
|
|
70555
71427
|
if (restored === null) {
|
|
70556
|
-
if (!existed) await
|
|
71428
|
+
if (!existed) await rm10(sessionDir, { recursive: true, force: true }).catch(() => void 0);
|
|
70557
71429
|
return false;
|
|
70558
71430
|
}
|
|
70559
71431
|
const cold = restored.meta;
|
|
@@ -70767,7 +71639,7 @@ function createServeAgentSessionStore(options) {
|
|
|
70767
71639
|
tier.unbind(sessionDir);
|
|
70768
71640
|
await tier.remove({ sessionId, endUserKey });
|
|
70769
71641
|
}
|
|
70770
|
-
await
|
|
71642
|
+
await rm10(sessionDir, { recursive: true, force: true });
|
|
70771
71643
|
await indexOf(storageRoot).remove(sessionId);
|
|
70772
71644
|
});
|
|
70773
71645
|
},
|
|
@@ -73566,7 +74438,7 @@ async function startServer(options) {
|
|
|
73566
74438
|
};
|
|
73567
74439
|
let closed = false;
|
|
73568
74440
|
let draining;
|
|
73569
|
-
const
|
|
74441
|
+
const drain2 = async (drainOptions = {}) => {
|
|
73570
74442
|
const timeoutMs = drainOptions.timeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS;
|
|
73571
74443
|
const startedAt2 = Date.now();
|
|
73572
74444
|
closing = true;
|
|
@@ -73623,7 +74495,7 @@ async function startServer(options) {
|
|
|
73623
74495
|
readiness: () => admission.readiness(),
|
|
73624
74496
|
drain: (drainOptions) => {
|
|
73625
74497
|
if (draining === void 0) {
|
|
73626
|
-
draining = closed ? Promise.resolve({ completedTurns: 0, abortedTurns: 0, flushedCommits: 0, durationMs: 0 }) :
|
|
74498
|
+
draining = closed ? Promise.resolve({ completedTurns: 0, abortedTurns: 0, flushedCommits: 0, durationMs: 0 }) : drain2(drainOptions);
|
|
73627
74499
|
}
|
|
73628
74500
|
return draining;
|
|
73629
74501
|
},
|
|
@@ -73842,7 +74714,7 @@ function appliedRuntimeEnvByGroup(resolved, ...groups) {
|
|
|
73842
74714
|
|
|
73843
74715
|
// src/v2/agent-session-factory.ts
|
|
73844
74716
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
73845
|
-
import { stat as
|
|
74717
|
+
import { stat as stat10 } from "node:fs/promises";
|
|
73846
74718
|
|
|
73847
74719
|
// src/v2/agent-bridges.ts
|
|
73848
74720
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
@@ -74246,7 +75118,7 @@ function buildRemoteTool(decl, bridge, now = Date.now) {
|
|
|
74246
75118
|
}
|
|
74247
75119
|
|
|
74248
75120
|
// src/v2/checkpoints.ts
|
|
74249
|
-
import
|
|
75121
|
+
import path17 from "node:path";
|
|
74250
75122
|
function isInvalidIdError(err) {
|
|
74251
75123
|
return err instanceof JournalError && err.code === "INVALID_CHECKPOINT_ID";
|
|
74252
75124
|
}
|
|
@@ -74256,7 +75128,7 @@ function createServeCheckpointStore(options) {
|
|
|
74256
75128
|
'createServeCheckpointStore requires exactly one of "dir" (standalone root) or "rootOf" (co-located root resolver)'
|
|
74257
75129
|
);
|
|
74258
75130
|
}
|
|
74259
|
-
const rootOf = options.rootOf ?? ((endUserId) =>
|
|
75131
|
+
const rootOf = options.rootOf ?? ((endUserId) => path17.join(options.dir, "agent-checkpoints", endUserKeyOf(endUserId)));
|
|
74260
75132
|
const writeOptions = options.max !== void 0 ? { max: options.max } : {};
|
|
74261
75133
|
return {
|
|
74262
75134
|
put(endUserId, checkpoint, putOptions) {
|
|
@@ -76047,7 +76919,7 @@ async function reconcileResumeCwd(storedCwd, currentCwd, mode) {
|
|
|
76047
76919
|
}
|
|
76048
76920
|
let isDirectory = false;
|
|
76049
76921
|
try {
|
|
76050
|
-
isDirectory = (await
|
|
76922
|
+
isDirectory = (await stat10(storedCwd)).isDirectory();
|
|
76051
76923
|
} catch {
|
|
76052
76924
|
isDirectory = false;
|
|
76053
76925
|
}
|
|
@@ -76226,6 +77098,8 @@ export {
|
|
|
76226
77098
|
createAgentSessionFactory,
|
|
76227
77099
|
createAppTokenMinter,
|
|
76228
77100
|
createBundleCache,
|
|
77101
|
+
createChaosBlobStore,
|
|
77102
|
+
createFsBlobStore,
|
|
76229
77103
|
createMemoryBlobStore,
|
|
76230
77104
|
createMetricsRegistry,
|
|
76231
77105
|
createPlatformServeSessionFactory,
|
|
@@ -76260,6 +77134,7 @@ export {
|
|
|
76260
77134
|
resolveUpstreamFetch,
|
|
76261
77135
|
routeTemplateOf,
|
|
76262
77136
|
runIdleCompaction2 as runIdleCompaction,
|
|
77137
|
+
runStorageConformance,
|
|
76263
77138
|
serveMetricsFor,
|
|
76264
77139
|
sessionIdShardOf,
|
|
76265
77140
|
sessionIdShardPrefix,
|