capnweb 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index-bun.cjs +69 -20
- package/dist/index-bun.cjs.map +1 -1
- package/dist/index-bun.d.cts +19 -2
- package/dist/index-bun.d.ts +19 -2
- package/dist/index-bun.js +68 -21
- package/dist/index-bun.js.map +1 -1
- package/dist/index-workers.cjs +69 -20
- package/dist/index-workers.cjs.map +1 -1
- package/dist/index-workers.d.cts +19 -2
- package/dist/index-workers.d.ts +19 -2
- package/dist/index-workers.js +68 -21
- package/dist/index-workers.js.map +1 -1
- package/dist/index.cjs +69 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +68 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index-workers.cjs
CHANGED
|
@@ -964,6 +964,12 @@ var PromiseStubHook = class PromiseStubHook extends StubHook {
|
|
|
964
964
|
|
|
965
965
|
//#endregion
|
|
966
966
|
//#region src/serialize.ts
|
|
967
|
+
const DEFAULT_MAX_DEPTH = 256;
|
|
968
|
+
const DEFAULT_LIMITS = {
|
|
969
|
+
maxBigIntDigits: 16384,
|
|
970
|
+
maxDepth: 256,
|
|
971
|
+
maxMessageSize: 32 * 1024 * 1024
|
|
972
|
+
};
|
|
967
973
|
var NullExporter = class {
|
|
968
974
|
exportStub(stub) {
|
|
969
975
|
throw new Error("Cannot serialize RPC stubs without an RPC session.");
|
|
@@ -983,7 +989,7 @@ async function streamToBlob(stream, type) {
|
|
|
983
989
|
let b = await new Response(stream).blob();
|
|
984
990
|
return b.type === type ? b : b.slice(0, b.size, type);
|
|
985
991
|
}
|
|
986
|
-
const ERROR_TYPES = {
|
|
992
|
+
const ERROR_TYPES = Object.assign(Object.create(null), {
|
|
987
993
|
Error,
|
|
988
994
|
EvalError,
|
|
989
995
|
RangeError,
|
|
@@ -992,7 +998,7 @@ const ERROR_TYPES = {
|
|
|
992
998
|
TypeError,
|
|
993
999
|
URIError,
|
|
994
1000
|
AggregateError
|
|
995
|
-
};
|
|
1001
|
+
});
|
|
996
1002
|
var Devaluator = class Devaluator {
|
|
997
1003
|
exporter;
|
|
998
1004
|
source;
|
|
@@ -1015,7 +1021,7 @@ var Devaluator = class Devaluator {
|
|
|
1015
1021
|
}
|
|
1016
1022
|
exports;
|
|
1017
1023
|
devaluateImpl(value, parent, depth) {
|
|
1018
|
-
if (depth >=
|
|
1024
|
+
if (depth >= 256) throw new Error("Serialization exceeded maximum allowed depth. (Does the message contain cycles?)");
|
|
1019
1025
|
switch (typeForRpc(value)) {
|
|
1020
1026
|
case "unsupported": {
|
|
1021
1027
|
let msg;
|
|
@@ -1249,6 +1255,9 @@ var NullImporter = class {
|
|
|
1249
1255
|
getPipeReadable(exportId) {
|
|
1250
1256
|
throw new Error("Cannot retrieve pipe readable without an RPC session.");
|
|
1251
1257
|
}
|
|
1258
|
+
getLimits() {
|
|
1259
|
+
return DEFAULT_LIMITS;
|
|
1260
|
+
}
|
|
1252
1261
|
};
|
|
1253
1262
|
const NULL_IMPORTER = new NullImporter();
|
|
1254
1263
|
function fixBrokenRequestBody(request, body) {
|
|
@@ -1266,16 +1275,21 @@ function streamToBlobPromise(stream, type) {
|
|
|
1266
1275
|
var Evaluator = class Evaluator {
|
|
1267
1276
|
importer;
|
|
1268
1277
|
encodingLevel;
|
|
1278
|
+
limits;
|
|
1269
1279
|
constructor(importer, encodingLevel = "string") {
|
|
1270
1280
|
this.importer = importer;
|
|
1271
1281
|
this.encodingLevel = encodingLevel;
|
|
1282
|
+
this.limits = importer.getLimits();
|
|
1272
1283
|
}
|
|
1273
1284
|
hooks = [];
|
|
1274
1285
|
promises = [];
|
|
1275
1286
|
evaluate(value) {
|
|
1287
|
+
return this.evaluateWithDepth(value, 0);
|
|
1288
|
+
}
|
|
1289
|
+
evaluateWithDepth(value, depth) {
|
|
1276
1290
|
let payload = RpcPayload.forEvaluate(this.hooks, this.promises);
|
|
1277
1291
|
try {
|
|
1278
|
-
payload.value = this.evaluateImpl(value, payload, "value");
|
|
1292
|
+
payload.value = this.evaluateImpl(value, payload, "value", depth);
|
|
1279
1293
|
return payload;
|
|
1280
1294
|
} catch (err) {
|
|
1281
1295
|
payload.dispose();
|
|
@@ -1285,18 +1299,25 @@ var Evaluator = class Evaluator {
|
|
|
1285
1299
|
evaluateCopy(value) {
|
|
1286
1300
|
return this.evaluate(structuredClone(value));
|
|
1287
1301
|
}
|
|
1288
|
-
evaluateImpl(value, parent, property) {
|
|
1302
|
+
evaluateImpl(value, parent, property, depth) {
|
|
1303
|
+
let maxDepth = this.limits.maxDepth;
|
|
1304
|
+
if (depth >= maxDepth) throw new TypeError(`Deserialization exceeded maximum allowed message depth of ${maxDepth}.`);
|
|
1289
1305
|
if (this.encodingLevel === "structuredClonable") {
|
|
1290
1306
|
if (value instanceof Date || typeof value === "bigint") return value;
|
|
1291
1307
|
}
|
|
1292
1308
|
if (value instanceof Array) {
|
|
1293
1309
|
if (value.length == 1 && value[0] instanceof Array) {
|
|
1294
1310
|
let result = value[0];
|
|
1295
|
-
for (let i = 0; i < result.length; i++) result[i] = this.evaluateImpl(result[i], result, i);
|
|
1311
|
+
for (let i = 0; i < result.length; i++) result[i] = this.evaluateImpl(result[i], result, i, depth + 1);
|
|
1296
1312
|
return result;
|
|
1297
1313
|
} else switch (value[0]) {
|
|
1298
1314
|
case "bigint":
|
|
1299
|
-
if (typeof value[1] == "string")
|
|
1315
|
+
if (typeof value[1] == "string") {
|
|
1316
|
+
let digits = value[1];
|
|
1317
|
+
let maxBigIntDigits = this.limits.maxBigIntDigits;
|
|
1318
|
+
if (digits.length > maxBigIntDigits) throw new TypeError(`Deserialized bigint exceeds maximum length of ${maxBigIntDigits} digits.`);
|
|
1319
|
+
return BigInt(digits);
|
|
1320
|
+
}
|
|
1300
1321
|
break;
|
|
1301
1322
|
case "date":
|
|
1302
1323
|
if (value[1] === null) return /* @__PURE__ */ new Date(NaN);
|
|
@@ -1326,7 +1347,11 @@ var Evaluator = class Evaluator {
|
|
|
1326
1347
|
let propsObj = props;
|
|
1327
1348
|
for (let key of Object.keys(propsObj)) {
|
|
1328
1349
|
if (key === "name" || key === "message" || key === "stack") continue;
|
|
1329
|
-
|
|
1350
|
+
if (key in Object.prototype || key === "toJSON") {
|
|
1351
|
+
this.evaluateImpl(propsObj[key], result, key, depth + 1);
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
anyResult[key] = this.evaluateImpl(propsObj[key], result, key, depth + 1);
|
|
1330
1355
|
}
|
|
1331
1356
|
}
|
|
1332
1357
|
return result;
|
|
@@ -1347,11 +1372,11 @@ var Evaluator = class Evaluator {
|
|
|
1347
1372
|
let init = value[2];
|
|
1348
1373
|
if (typeof init !== "object" || init === null) break;
|
|
1349
1374
|
if (init.body) {
|
|
1350
|
-
init.body = this.evaluateImpl(init.body, init, "body");
|
|
1375
|
+
init.body = this.evaluateImpl(init.body, init, "body", depth + 1);
|
|
1351
1376
|
if (init.body === null || typeof init.body === "string" || init.body instanceof Uint8Array || init.body instanceof ReadableStream) {} else throw new TypeError("Request body must be of type ReadableStream.");
|
|
1352
1377
|
}
|
|
1353
1378
|
if (init.signal) {
|
|
1354
|
-
init.signal = this.evaluateImpl(init.signal, init, "signal");
|
|
1379
|
+
init.signal = this.evaluateImpl(init.signal, init, "signal", depth + 1);
|
|
1355
1380
|
if (!(init.signal instanceof AbortSignal)) throw new TypeError("Request siganl must be of type AbortSignal.");
|
|
1356
1381
|
}
|
|
1357
1382
|
if (init.headers && !(init.headers instanceof Array)) throw new TypeError("Request headers must be serialized as an array of pairs.");
|
|
@@ -1368,7 +1393,7 @@ var Evaluator = class Evaluator {
|
|
|
1368
1393
|
}
|
|
1369
1394
|
case "response": {
|
|
1370
1395
|
if (value.length !== 3) break;
|
|
1371
|
-
let body = this.evaluateImpl(value[1], parent, property);
|
|
1396
|
+
let body = this.evaluateImpl(value[1], parent, property, depth + 1);
|
|
1372
1397
|
if (body === null || typeof body === "string" || body instanceof Uint8Array || body instanceof ReadableStream) {} else throw new TypeError("Response body must be of type ReadableStream.");
|
|
1373
1398
|
let init = value[2];
|
|
1374
1399
|
if (typeof init !== "object" || init === null) break;
|
|
@@ -1379,7 +1404,7 @@ var Evaluator = class Evaluator {
|
|
|
1379
1404
|
case "blob": {
|
|
1380
1405
|
if (value.length !== 3 || typeof value[1] !== "string") break;
|
|
1381
1406
|
let contentType = value[1];
|
|
1382
|
-
let content = this.evaluateImpl(value[2], parent, property);
|
|
1407
|
+
let content = this.evaluateImpl(value[2], parent, property, depth + 1);
|
|
1383
1408
|
if (!(content instanceof ReadableStream)) throw new TypeError("Blob content must be serialized as a ReadableStream.");
|
|
1384
1409
|
let promise = streamToBlobPromise(content, contentType);
|
|
1385
1410
|
this.promises.push({
|
|
@@ -1420,7 +1445,7 @@ var Evaluator = class Evaluator {
|
|
|
1420
1445
|
if (value.length == 3) return addStub(hook.get(path));
|
|
1421
1446
|
let args = value[3];
|
|
1422
1447
|
if (!(args instanceof Array)) break;
|
|
1423
|
-
args = new Evaluator(this.importer).
|
|
1448
|
+
args = new Evaluator(this.importer).evaluateWithDepth([args], depth);
|
|
1424
1449
|
return addStub(hook.call(path, args));
|
|
1425
1450
|
}
|
|
1426
1451
|
case "remap": {
|
|
@@ -1486,9 +1511,9 @@ var Evaluator = class Evaluator {
|
|
|
1486
1511
|
} else if (value instanceof Object) {
|
|
1487
1512
|
let result = value;
|
|
1488
1513
|
for (let key in result) if (key in Object.prototype || key === "toJSON") {
|
|
1489
|
-
this.evaluateImpl(result[key], result, key);
|
|
1514
|
+
this.evaluateImpl(result[key], result, key, depth + 1);
|
|
1490
1515
|
delete result[key];
|
|
1491
|
-
} else result[key] = this.evaluateImpl(result[key], result, key);
|
|
1516
|
+
} else result[key] = this.evaluateImpl(result[key], result, key, depth + 1);
|
|
1492
1517
|
return result;
|
|
1493
1518
|
} else return value;
|
|
1494
1519
|
}
|
|
@@ -1559,6 +1584,10 @@ var ImportTableEntry = class {
|
|
|
1559
1584
|
resolution;
|
|
1560
1585
|
onBrokenRegistrations;
|
|
1561
1586
|
resolve(resolution) {
|
|
1587
|
+
if (this.resolution) {
|
|
1588
|
+
resolution.dispose();
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1562
1591
|
if (this.localRefcount == 0) {
|
|
1563
1592
|
resolution.dispose();
|
|
1564
1593
|
return;
|
|
@@ -1711,6 +1740,7 @@ var RpcSessionImpl = class {
|
|
|
1711
1740
|
pullCount = 0;
|
|
1712
1741
|
onBrokenCallbacks = [];
|
|
1713
1742
|
encodingLevel;
|
|
1743
|
+
limits;
|
|
1714
1744
|
constructor(transport, mainHook, options) {
|
|
1715
1745
|
this.transport = transport;
|
|
1716
1746
|
this.options = options;
|
|
@@ -1723,6 +1753,10 @@ var RpcSessionImpl = class {
|
|
|
1723
1753
|
}
|
|
1724
1754
|
}
|
|
1725
1755
|
this.encodingLevel = level;
|
|
1756
|
+
this.limits = {
|
|
1757
|
+
...DEFAULT_LIMITS,
|
|
1758
|
+
...options.limits
|
|
1759
|
+
};
|
|
1726
1760
|
this.exports.push({
|
|
1727
1761
|
hook: mainHook,
|
|
1728
1762
|
refcount: 1
|
|
@@ -1865,6 +1899,9 @@ var RpcSessionImpl = class {
|
|
|
1865
1899
|
entry.pipeReadable = void 0;
|
|
1866
1900
|
return readable;
|
|
1867
1901
|
}
|
|
1902
|
+
getLimits() {
|
|
1903
|
+
return this.limits;
|
|
1904
|
+
}
|
|
1868
1905
|
createPipe(readable, readableHook) {
|
|
1869
1906
|
if (this.abortReason) throw this.abortReason;
|
|
1870
1907
|
this.send(["pipe"]);
|
|
@@ -2024,6 +2061,7 @@ var RpcSessionImpl = class {
|
|
|
2024
2061
|
} finally {
|
|
2025
2062
|
if (this.cancelReadLoop === readCanceled.reject) this.cancelReadLoop = void 0;
|
|
2026
2063
|
}
|
|
2064
|
+
if (this.encodingLevel === "string" && raw.length > this.limits.maxMessageSize) throw new TypeError(`Incoming message exceeds maximum size of ${this.limits.maxMessageSize} UTF-16 code units.`);
|
|
2027
2065
|
if (this.abortReason) break;
|
|
2028
2066
|
let msg = this.encodingLevel === "string" ? JSON.parse(raw) : raw;
|
|
2029
2067
|
if (msg instanceof Array) switch (msg[0]) {
|
|
@@ -2098,7 +2136,7 @@ var RpcSessionImpl = class {
|
|
|
2098
2136
|
case "abort": {
|
|
2099
2137
|
let payload = new Evaluator(this, this.encodingLevel).evaluate(msg[1]);
|
|
2100
2138
|
payload.dispose();
|
|
2101
|
-
this.abort(payload, false);
|
|
2139
|
+
this.abort(payload.value, false);
|
|
2102
2140
|
break;
|
|
2103
2141
|
}
|
|
2104
2142
|
}
|
|
@@ -2224,6 +2262,8 @@ var WebSocketTransport = class {
|
|
|
2224
2262
|
let message;
|
|
2225
2263
|
if (reason instanceof Error) message = reason.message;
|
|
2226
2264
|
else message = `${reason}`;
|
|
2265
|
+
let reasonBytes = new TextEncoder().encode(message);
|
|
2266
|
+
if (reasonBytes.length > 123) message = new TextDecoder().decode(reasonBytes.subarray(0, 123), { stream: true });
|
|
2227
2267
|
this.#webSocket.close(3e3, message);
|
|
2228
2268
|
if (!this.#error) this.#error = reason;
|
|
2229
2269
|
}
|
|
@@ -2340,7 +2380,11 @@ async function newHttpBatchRpcResponse(request, localMain, options) {
|
|
|
2340
2380
|
* @param options Optional RPC session options. You can also pass headers to set on the response.
|
|
2341
2381
|
*/
|
|
2342
2382
|
async function nodeHttpBatchRpcResponse(request, response, localMain, options) {
|
|
2343
|
-
if (request.method !== "POST")
|
|
2383
|
+
if (request.method !== "POST") {
|
|
2384
|
+
response.writeHead(405, "This endpoint only accepts POST requests.", options?.headers);
|
|
2385
|
+
response.end();
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2344
2388
|
let body = await new Promise((resolve, reject) => {
|
|
2345
2389
|
let chunks = [];
|
|
2346
2390
|
request.on("data", (chunk) => {
|
|
@@ -2605,6 +2649,9 @@ var MapApplicator = class {
|
|
|
2605
2649
|
getPipeReadable(exportId) {
|
|
2606
2650
|
throw new Error("A mapper function cannot use pipe readables.");
|
|
2607
2651
|
}
|
|
2652
|
+
getLimits() {
|
|
2653
|
+
return DEFAULT_LIMITS;
|
|
2654
|
+
}
|
|
2608
2655
|
};
|
|
2609
2656
|
function applyMapToElement(input, parent, owner, captures, instructions) {
|
|
2610
2657
|
let mapper = new MapApplicator(captures, new PayloadStubHook(RpcPayload.deepCopyFrom(input, parent, owner)));
|
|
@@ -2943,16 +2990,18 @@ let newMessagePortRpcSession = newMessagePortRpcSession$1;
|
|
|
2943
2990
|
* credentials as parameters and returns the authorized API), then cross-origin requests should
|
|
2944
2991
|
* be safe.
|
|
2945
2992
|
*/
|
|
2946
|
-
async function newWorkersRpcResponse(request, localMain) {
|
|
2993
|
+
async function newWorkersRpcResponse(request, localMain, options) {
|
|
2947
2994
|
if (request.method === "POST") {
|
|
2948
|
-
let response = await newHttpBatchRpcResponse(request, localMain);
|
|
2995
|
+
let response = await newHttpBatchRpcResponse(request, localMain, options);
|
|
2949
2996
|
response.headers.set("Access-Control-Allow-Origin", "*");
|
|
2950
2997
|
return response;
|
|
2951
|
-
} else if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") return newWorkersWebSocketRpcResponse(request, localMain);
|
|
2998
|
+
} else if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") return newWorkersWebSocketRpcResponse(request, localMain, options);
|
|
2952
2999
|
else return new Response("This endpoint only accepts POST or WebSocket requests.", { status: 400 });
|
|
2953
3000
|
}
|
|
2954
3001
|
|
|
2955
3002
|
//#endregion
|
|
3003
|
+
exports.DEFAULT_LIMITS = DEFAULT_LIMITS;
|
|
3004
|
+
exports.DEFAULT_MAX_DEPTH = DEFAULT_MAX_DEPTH;
|
|
2956
3005
|
exports.RpcPromise = RpcPromise;
|
|
2957
3006
|
exports.RpcSession = RpcSession;
|
|
2958
3007
|
exports.RpcStub = RpcStub;
|