@solidjs/web 2.0.0-rc.5 → 2.0.0-rc.6
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/dev.cjs +113 -31
- package/dist/dev.js +113 -32
- package/dist/server.cjs +17 -3
- package/dist/server.js +17 -3
- package/dist/web.cjs +113 -31
- package/dist/web.js +113 -32
- package/frames/dist/server.cjs +87 -22
- package/frames/dist/server.js +87 -22
- package/package.json +2 -2
- package/server-functions/dist/client.cjs +14 -2
- package/server-functions/dist/client.js +14 -2
- package/server-functions/dist/server.cjs +219 -69
- package/server-functions/dist/server.dev.cjs +219 -69
- package/server-functions/dist/server.dev.js +219 -69
- package/server-functions/dist/server.js +219 -69
- package/types/client.d.ts +2 -1
- package/types/constants.d.ts +3 -1
- package/types/server-functions/server.d.ts +73 -2
- package/types-cjs/client.d.cts +2 -1
- package/types-cjs/constants.d.cts +3 -1
- package/types-cjs/server-functions/server.d.cts +73 -2
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
var solidJs = require('solid-js');
|
|
4
4
|
|
|
5
|
+
const COMPOSED_BODY_FRAMING = /*#__PURE__*/new Set(["content-length", "content-encoding", "transfer-encoding"]);
|
|
6
|
+
function isHttpNavigationTarget(target) {
|
|
7
|
+
try {
|
|
8
|
+
const protocol = new URL(target, "http://base.invalid").protocol;
|
|
9
|
+
return protocol === "http:" || protocol === "https:";
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
|
|
6
16
|
function isResponseEnvelope(value) {
|
|
7
17
|
return !!(value && typeof value === "object" && value[ENVELOPE]);
|
|
@@ -556,7 +566,8 @@ function copyInitHeaders(init) {
|
|
|
556
566
|
for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
|
|
557
567
|
return headers;
|
|
558
568
|
}
|
|
559
|
-
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location"
|
|
569
|
+
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location",
|
|
570
|
+
...COMPOSED_BODY_FRAMING].map(header => header.toLowerCase()));
|
|
560
571
|
function fillsStubGap(key, headers, response) {
|
|
561
572
|
if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
|
|
562
573
|
if (response.body === null && (key === "content-type" || key === "content-length")) return false;
|
|
@@ -716,6 +727,52 @@ function provideEvent(event, fn) {
|
|
|
716
727
|
if (ctx) return ctx.run(event, fn);
|
|
717
728
|
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
718
729
|
}
|
|
730
|
+
function scopeDeferredResult(value, scope) {
|
|
731
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
732
|
+
const promised = scope(() => nativePromise(value));
|
|
733
|
+
if (promised) {
|
|
734
|
+
return promised.then(result => scope(() => scopeDeferredResult(result, scope)));
|
|
735
|
+
}
|
|
736
|
+
if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) {
|
|
737
|
+
let reader;
|
|
738
|
+
return new ReadableStream({
|
|
739
|
+
async pull(controller) {
|
|
740
|
+
try {
|
|
741
|
+
const step = await scope(() => {
|
|
742
|
+
if (!reader) reader = value.getReader();
|
|
743
|
+
return reader.read();
|
|
744
|
+
});
|
|
745
|
+
if (step.done) controller.close();else controller.enqueue(step.value);
|
|
746
|
+
} catch (error) {
|
|
747
|
+
controller.error(error);
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
cancel(reason) {
|
|
751
|
+
return scope(() => reader ? reader.cancel(reason) : value.cancel(reason));
|
|
752
|
+
}
|
|
753
|
+
}, {
|
|
754
|
+
highWaterMark: 0
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
const scopedIterator = symbol => ({
|
|
758
|
+
[symbol]() {
|
|
759
|
+
const iterator = scope(() => value[symbol]());
|
|
760
|
+
return new Proxy(iterator, {
|
|
761
|
+
get(target, property) {
|
|
762
|
+
const member = Reflect.get(target, property, target);
|
|
763
|
+
return typeof member === "function" && (property === "next" || property === "return" || property === "throw") ? (...args) => scope(() => member.apply(target, args)) : member;
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
if (typeof value[Symbol.asyncIterator] === "function") {
|
|
769
|
+
return scopedIterator(Symbol.asyncIterator);
|
|
770
|
+
}
|
|
771
|
+
if (typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
772
|
+
return scopedIterator(Symbol.iterator);
|
|
773
|
+
}
|
|
774
|
+
return value;
|
|
775
|
+
}
|
|
719
776
|
const REGISTRATIONS = new Map();
|
|
720
777
|
const METHODS = new Map();
|
|
721
778
|
const INVOCATIONS = new WeakMap();
|
|
@@ -813,7 +870,8 @@ function createServerReference({
|
|
|
813
870
|
id
|
|
814
871
|
});
|
|
815
872
|
evt.serverOnly = true;
|
|
816
|
-
const
|
|
873
|
+
const scope = run => provideEvent(evt, run);
|
|
874
|
+
let result = provideEvent(evt, () => {
|
|
817
875
|
const run = () => fn.apply(thisArg, args);
|
|
818
876
|
return config.wrapInvocation ? config.wrapInvocation(run, {
|
|
819
877
|
id,
|
|
@@ -822,19 +880,20 @@ function createServerReference({
|
|
|
822
880
|
direct: true
|
|
823
881
|
}) : run();
|
|
824
882
|
});
|
|
883
|
+
result = scopeDeferredResult(result, scope);
|
|
825
884
|
const transform = config.transformDirectResult;
|
|
826
885
|
if (transform && result && typeof result.then === "function") {
|
|
827
|
-
return result.then(value => transform(value, {
|
|
886
|
+
return result.then(value => scopeDeferredResult(transform(value, {
|
|
828
887
|
id,
|
|
829
888
|
args,
|
|
830
889
|
event: evt
|
|
831
|
-
}));
|
|
890
|
+
}), scope));
|
|
832
891
|
}
|
|
833
|
-
return transform ? transform(result, {
|
|
892
|
+
return transform ? scopeDeferredResult(transform(result, {
|
|
834
893
|
id,
|
|
835
894
|
args,
|
|
836
895
|
event: evt
|
|
837
|
-
}) : result;
|
|
896
|
+
}), scope) : result;
|
|
838
897
|
}
|
|
839
898
|
});
|
|
840
899
|
return proxy;
|
|
@@ -900,22 +959,58 @@ function assertDecodeDepth(value) {
|
|
|
900
959
|
level = next;
|
|
901
960
|
}
|
|
902
961
|
}
|
|
962
|
+
const UNSAFE_ARGUMENT_KEYS = ["__proto__", "constructor", "prototype"];
|
|
963
|
+
function stripUnsafeArgumentKeys(value) {
|
|
964
|
+
const stack = [value];
|
|
965
|
+
const seen = new Set();
|
|
966
|
+
while (stack.length) {
|
|
967
|
+
const v = stack.pop();
|
|
968
|
+
if (v === null || typeof v !== "object" || seen.has(v)) continue;
|
|
969
|
+
seen.add(v);
|
|
970
|
+
for (const key of UNSAFE_ARGUMENT_KEYS) {
|
|
971
|
+
delete v[key];
|
|
972
|
+
}
|
|
973
|
+
for (const key of Object.keys(v)) stack.push(v[key]);
|
|
974
|
+
if (v instanceof Map) {
|
|
975
|
+
for (const [k, entry] of v) stack.push(k, entry);
|
|
976
|
+
} else if (v instanceof Set) {
|
|
977
|
+
for (const member of v) stack.push(member);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
return value;
|
|
981
|
+
}
|
|
903
982
|
async function bufferBodyWithin(request, limit) {
|
|
904
|
-
const reader = request.
|
|
983
|
+
const reader = request.body.getReader();
|
|
984
|
+
const signal = request.signal;
|
|
905
985
|
const chunks = [];
|
|
906
986
|
let total = 0;
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
987
|
+
const onAbort = () => {
|
|
988
|
+
reader.cancel(signal.reason).catch(() => {});
|
|
989
|
+
};
|
|
990
|
+
if (signal.aborted) onAbort();else signal.addEventListener("abort", onAbort, {
|
|
991
|
+
once: true
|
|
992
|
+
});
|
|
993
|
+
try {
|
|
994
|
+
for (;;) {
|
|
995
|
+
const {
|
|
996
|
+
done,
|
|
997
|
+
value
|
|
998
|
+
} = await reader.read();
|
|
999
|
+
if (signal.aborted) throw signal.reason;
|
|
1000
|
+
if (done) break;
|
|
1001
|
+
total += value.byteLength;
|
|
1002
|
+
if (total > limit) {
|
|
1003
|
+
reader.cancel().catch(() => {});
|
|
1004
|
+
return null;
|
|
1005
|
+
}
|
|
1006
|
+
chunks.push(value);
|
|
917
1007
|
}
|
|
918
|
-
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
reader.cancel(error).catch(() => {});
|
|
1010
|
+
throw error;
|
|
1011
|
+
} finally {
|
|
1012
|
+
signal.removeEventListener("abort", onAbort);
|
|
1013
|
+
reader.releaseLock();
|
|
919
1014
|
}
|
|
920
1015
|
const body = new Uint8Array(total);
|
|
921
1016
|
let offset = 0;
|
|
@@ -942,6 +1037,7 @@ async function parseArguments(request, url, scripted, codec) {
|
|
|
942
1037
|
if (!Array.isArray(result)) {
|
|
943
1038
|
throw new TypeError("Server function arguments must encode an array");
|
|
944
1039
|
}
|
|
1040
|
+
stripUnsafeArgumentKeys(result);
|
|
945
1041
|
for (const arg of result) {
|
|
946
1042
|
parsed.push(arg);
|
|
947
1043
|
}
|
|
@@ -955,9 +1051,12 @@ async function parseArguments(request, url, scripted, codec) {
|
|
|
955
1051
|
if (!Array.isArray(decoded)) {
|
|
956
1052
|
throw new TypeError("Server function arguments must encode an array");
|
|
957
1053
|
}
|
|
958
|
-
return decoded;
|
|
1054
|
+
return stripUnsafeArgumentKeys(decoded);
|
|
959
1055
|
}
|
|
960
1056
|
if (decoded === undefined) {
|
|
1057
|
+
if (bodyFormat === null && (await request.clone().arrayBuffer()).byteLength === 0) {
|
|
1058
|
+
return parsed;
|
|
1059
|
+
}
|
|
961
1060
|
throw new TypeError("Server function body carries no usable encoding");
|
|
962
1061
|
}
|
|
963
1062
|
parsed.push(decoded);
|
|
@@ -1058,7 +1157,7 @@ function foldSetCookies(headers, setCookies) {
|
|
|
1058
1157
|
}
|
|
1059
1158
|
function mergeResponseHeaders(target, source) {
|
|
1060
1159
|
source.forEach((value, key) => {
|
|
1061
|
-
if (key !== "set-cookie") target.append(key, value);
|
|
1160
|
+
if (key !== "set-cookie" && !COMPOSED_BODY_FRAMING.has(key)) target.append(key, value);
|
|
1062
1161
|
});
|
|
1063
1162
|
if (source.getSetCookie) {
|
|
1064
1163
|
for (const cookie of source.getSetCookie()) target.append("Set-Cookie", cookie);
|
|
@@ -1075,10 +1174,6 @@ function maskRedirect(headers, response, requestUrl) {
|
|
|
1075
1174
|
headers.delete("Location");
|
|
1076
1175
|
}
|
|
1077
1176
|
const BOUNDED_COMPOSED_HEADERS = [REDIRECT_HEADER, "Location", REVALIDATE_HEADER];
|
|
1078
|
-
function refusedTargetScheme(target) {
|
|
1079
|
-
const match = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.exec(target);
|
|
1080
|
-
return match !== null && !/^https?:$/i.test(match[0]);
|
|
1081
|
-
}
|
|
1082
1177
|
function enforceComposedHeaderInvariants(response) {
|
|
1083
1178
|
for (const name of BOUNDED_COMPOSED_HEADERS) {
|
|
1084
1179
|
const value = response.headers.get(name);
|
|
@@ -1088,7 +1183,7 @@ function enforceComposedHeaderInvariants(response) {
|
|
|
1088
1183
|
}
|
|
1089
1184
|
if (name === REVALIDATE_HEADER) continue;
|
|
1090
1185
|
const target = name === REDIRECT_HEADER ? value.slice(value.indexOf(" ") + 1) : value;
|
|
1091
|
-
if (
|
|
1186
|
+
if (!isHttpNavigationTarget(target)) {
|
|
1092
1187
|
return refuseComposedHeader(response, name, `${name} response header refused: non-http(s) navigation target`, DEV ? `The ${name} response header carries a navigation target with a non-http(s) ` + `scheme ("${target.slice(0, 64)}"). A javascript: target is same-origin script ` + `execution in any integration that navigates to it, so only http(s) and ` + `relative targets leave this transport. If the target came from request data ` + `(?next= and friends), validate it against your own origin before redirecting.` : null);
|
|
1093
1188
|
}
|
|
1094
1189
|
}
|
|
@@ -1216,14 +1311,11 @@ function guardFailures(value, state) {
|
|
|
1216
1311
|
top.next.add(guarded);
|
|
1217
1312
|
if (guarded !== original) top.changed = true;
|
|
1218
1313
|
} else if (guarded !== original || top.accessorRead === i) {
|
|
1219
|
-
Object.defineProperty(top.next, items[i],
|
|
1220
|
-
|
|
1221
|
-
configurable: true,
|
|
1314
|
+
Object.defineProperty(top.next, items[i], {
|
|
1315
|
+
value: guarded,
|
|
1222
1316
|
writable: true,
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
...top.descriptors[items[i]],
|
|
1226
|
-
value: guarded
|
|
1317
|
+
configurable: true,
|
|
1318
|
+
enumerable: top.descriptors[items[i]].enumerable
|
|
1227
1319
|
});
|
|
1228
1320
|
top.changed = true;
|
|
1229
1321
|
}
|
|
@@ -1258,6 +1350,9 @@ class Frame {
|
|
|
1258
1350
|
this.pendingKey = undefined;
|
|
1259
1351
|
}
|
|
1260
1352
|
}
|
|
1353
|
+
function guardOperation(state, run) {
|
|
1354
|
+
return state.scope ? state.scope(run) : run();
|
|
1355
|
+
}
|
|
1261
1356
|
function enterGuard(value, state) {
|
|
1262
1357
|
if (value === null || typeof value !== "object") return value;
|
|
1263
1358
|
if (state.seen.has(value)) {
|
|
@@ -1272,7 +1367,7 @@ function enterGuard(value, state) {
|
|
|
1272
1367
|
if (finished) return;
|
|
1273
1368
|
finished = true;
|
|
1274
1369
|
try {
|
|
1275
|
-
const cancelled = reader ? reader.cancel() : value.cancel();
|
|
1370
|
+
const cancelled = guardOperation(state, () => reader ? reader.cancel() : value.cancel());
|
|
1276
1371
|
if (cancelled && typeof cancelled.then === "function") cancelled.then(undefined, () => {});
|
|
1277
1372
|
} catch {}
|
|
1278
1373
|
};
|
|
@@ -1284,19 +1379,19 @@ function enterGuard(value, state) {
|
|
|
1284
1379
|
controller.close();
|
|
1285
1380
|
return;
|
|
1286
1381
|
}
|
|
1287
|
-
if (!reader) reader = value.getReader();
|
|
1382
|
+
if (!reader) reader = guardOperation(state, () => value.getReader());
|
|
1288
1383
|
const {
|
|
1289
1384
|
done,
|
|
1290
1385
|
value: chunk
|
|
1291
|
-
} = await reader.read();
|
|
1292
|
-
done ? controller.close() : controller.enqueue(guardFailures(chunk, state));
|
|
1386
|
+
} = await guardOperation(state, () => reader.read());
|
|
1387
|
+
done ? controller.close() : controller.enqueue(guardOperation(state, () => guardFailures(chunk, state)));
|
|
1293
1388
|
} catch (error) {
|
|
1294
|
-
controller.error(sanitizeServerError(error));
|
|
1389
|
+
controller.error(guardOperation(state, () => sanitizeServerError(error)));
|
|
1295
1390
|
}
|
|
1296
1391
|
},
|
|
1297
1392
|
cancel(reason) {
|
|
1298
1393
|
finished = true;
|
|
1299
|
-
return reader ? reader.cancel(reason) : value.cancel(reason);
|
|
1394
|
+
return guardOperation(state, () => reader ? reader.cancel(reason) : value.cancel(reason));
|
|
1300
1395
|
}
|
|
1301
1396
|
});
|
|
1302
1397
|
if (gate) gate.onOpen(close);
|
|
@@ -1304,9 +1399,10 @@ function enterGuard(value, state) {
|
|
|
1304
1399
|
return guardedStream;
|
|
1305
1400
|
}
|
|
1306
1401
|
if (typeof value.then === "function") {
|
|
1307
|
-
const guardedPromise = Promise.resolve(value).then(resolved => guardFailures(resolved, state), error => {
|
|
1308
|
-
throw sanitizeServerError(error);
|
|
1402
|
+
const guardedPromise = Promise.resolve(value).then(resolved => guardOperation(state, () => guardFailures(resolved, state)), error => {
|
|
1403
|
+
throw guardOperation(state, () => sanitizeServerError(error));
|
|
1309
1404
|
});
|
|
1405
|
+
guardedPromise.catch(() => {});
|
|
1310
1406
|
state.seen.set(value, guardedPromise);
|
|
1311
1407
|
return guardedPromise;
|
|
1312
1408
|
}
|
|
@@ -1315,13 +1411,13 @@ function enterGuard(value, state) {
|
|
|
1315
1411
|
const gate = state.gate;
|
|
1316
1412
|
const guardedIterable = {
|
|
1317
1413
|
[Symbol.asyncIterator]() {
|
|
1318
|
-
const iterator = source[Symbol.asyncIterator]();
|
|
1414
|
+
const iterator = guardOperation(state, () => source[Symbol.asyncIterator]());
|
|
1319
1415
|
let finished = false;
|
|
1320
1416
|
const close = () => {
|
|
1321
1417
|
if (finished) return;
|
|
1322
1418
|
finished = true;
|
|
1323
1419
|
try {
|
|
1324
|
-
const returned = iterator.return && iterator.return();
|
|
1420
|
+
const returned = iterator.return && guardOperation(state, () => iterator.return());
|
|
1325
1421
|
if (returned && typeof returned.then === "function") returned.then(undefined, () => {});
|
|
1326
1422
|
} catch {}
|
|
1327
1423
|
};
|
|
@@ -1329,17 +1425,17 @@ function enterGuard(value, state) {
|
|
|
1329
1425
|
const step = () => finished ? Promise.resolve({
|
|
1330
1426
|
done: true,
|
|
1331
1427
|
value: undefined
|
|
1332
|
-
}) : iterator.next().then(step => {
|
|
1428
|
+
}) : guardOperation(state, () => iterator.next()).then(step => {
|
|
1333
1429
|
if (step.done) {
|
|
1334
1430
|
finished = true;
|
|
1335
1431
|
return step;
|
|
1336
1432
|
}
|
|
1337
1433
|
return {
|
|
1338
1434
|
done: false,
|
|
1339
|
-
value: guardFailures(step.value, state)
|
|
1435
|
+
value: guardOperation(state, () => guardFailures(step.value, state))
|
|
1340
1436
|
};
|
|
1341
1437
|
}, error => {
|
|
1342
|
-
throw sanitizeServerError(error);
|
|
1438
|
+
throw guardOperation(state, () => sanitizeServerError(error));
|
|
1343
1439
|
});
|
|
1344
1440
|
return {
|
|
1345
1441
|
next: () => finished || !gate || gate.wantsMore() ? step() : gate.awaitDemand().then(step),
|
|
@@ -1356,6 +1452,11 @@ function enterGuard(value, state) {
|
|
|
1356
1452
|
state.seen.set(value, guardedIterable);
|
|
1357
1453
|
return guardedIterable;
|
|
1358
1454
|
}
|
|
1455
|
+
if (state.scope && typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
1456
|
+
const scopedIterable = scopeDeferredResult(value, state.scope);
|
|
1457
|
+
state.seen.set(value, scopedIterable);
|
|
1458
|
+
return scopedIterable;
|
|
1459
|
+
}
|
|
1359
1460
|
if (Array.isArray(value)) {
|
|
1360
1461
|
const next = value.slice();
|
|
1361
1462
|
state.seen.set(value, next);
|
|
@@ -1379,16 +1480,20 @@ function enterGuard(value, state) {
|
|
|
1379
1480
|
return value;
|
|
1380
1481
|
}
|
|
1381
1482
|
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
1483
|
+
for (const key of Object.keys(descriptors)) {
|
|
1484
|
+
descriptors[key].configurable = true;
|
|
1485
|
+
if ("value" in descriptors[key]) descriptors[key].writable = true;
|
|
1486
|
+
}
|
|
1382
1487
|
const next = Object.create(prototype, descriptors);
|
|
1383
1488
|
state.seen.set(value, next);
|
|
1384
|
-
return new Frame(OBJECT, value, next, Object.keys(
|
|
1489
|
+
return new Frame(OBJECT, value, next, Object.keys(value), descriptors);
|
|
1385
1490
|
}
|
|
1386
1491
|
function keepGuarded(value, next, changed, state) {
|
|
1387
1492
|
if (changed || state.cyclic.has(value)) return next;
|
|
1388
1493
|
state.seen.set(value, value);
|
|
1389
1494
|
return value;
|
|
1390
1495
|
}
|
|
1391
|
-
function serializeResponseStream(value, codecOptions, signal) {
|
|
1496
|
+
function serializeResponseStream(value, codecOptions, signal, scope) {
|
|
1392
1497
|
let closed = false;
|
|
1393
1498
|
let streamController = null;
|
|
1394
1499
|
let demandWaiters = null;
|
|
@@ -1407,11 +1512,13 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
1407
1512
|
if (closed) close();else sourceClosers.add(close);
|
|
1408
1513
|
}
|
|
1409
1514
|
};
|
|
1410
|
-
|
|
1515
|
+
const guardState = {
|
|
1411
1516
|
seen: new WeakMap(),
|
|
1412
1517
|
cyclic: new WeakSet(),
|
|
1413
|
-
gate
|
|
1414
|
-
|
|
1518
|
+
gate,
|
|
1519
|
+
scope
|
|
1520
|
+
};
|
|
1521
|
+
value = guardOperation(guardState, () => guardFailures(value, guardState));
|
|
1415
1522
|
let cancelSerialize = null;
|
|
1416
1523
|
let onAbort = null;
|
|
1417
1524
|
const finishSource = () => {
|
|
@@ -1492,14 +1599,14 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
1492
1599
|
}
|
|
1493
1600
|
});
|
|
1494
1601
|
}
|
|
1495
|
-
function serializedResponse(value, headers, codec, signal) {
|
|
1602
|
+
function serializedResponse(value, headers, codec, signal, scope) {
|
|
1496
1603
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
1497
1604
|
headers.set("Content-Type", "text/plain");
|
|
1498
|
-
return new Response(serializeResponseStream(value, codec, signal), {
|
|
1605
|
+
return new Response(serializeResponseStream(value, codec, signal, scope), {
|
|
1499
1606
|
headers
|
|
1500
1607
|
});
|
|
1501
1608
|
}
|
|
1502
|
-
function encodeResult(value, headers, status, codec, signal) {
|
|
1609
|
+
function encodeResult(value, headers, status, codec, signal, scope) {
|
|
1503
1610
|
if (NULL_BODY_STATUSES.has(status)) {
|
|
1504
1611
|
if (value === undefined || value === null) {
|
|
1505
1612
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Void);
|
|
@@ -1510,7 +1617,7 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1510
1617
|
}
|
|
1511
1618
|
const error = new Error(`Server function answered status ${status}, which forbids a response body, with a value. ` + `Return respond(undefined, { status: ${status} }) for a bodiless answer, or drop the ` + `status to send the value.`);
|
|
1512
1619
|
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error.message));
|
|
1513
|
-
return encodeResult(error, headers, 500, codec, signal);
|
|
1620
|
+
return encodeResult(error, headers, 500, codec, signal, scope);
|
|
1514
1621
|
}
|
|
1515
1622
|
const direct = getHeadersAndBody(value);
|
|
1516
1623
|
if (direct) {
|
|
@@ -1530,10 +1637,12 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1530
1637
|
});
|
|
1531
1638
|
}
|
|
1532
1639
|
try {
|
|
1533
|
-
|
|
1640
|
+
const jsonSafe = scope ? scope(() => isJSONSafe(value)) : isJSONSafe(value);
|
|
1641
|
+
if (jsonSafe) {
|
|
1534
1642
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Json);
|
|
1535
1643
|
headers.set("Content-Type", "application/json");
|
|
1536
|
-
|
|
1644
|
+
const body = scope ? scope(() => JSON.stringify(value)) : JSON.stringify(value);
|
|
1645
|
+
return new Response(body, {
|
|
1537
1646
|
status,
|
|
1538
1647
|
headers
|
|
1539
1648
|
});
|
|
@@ -1541,7 +1650,7 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1541
1650
|
} catch {
|
|
1542
1651
|
}
|
|
1543
1652
|
try {
|
|
1544
|
-
const response = serializedResponse(value, headers, codec, signal);
|
|
1653
|
+
const response = serializedResponse(value, headers, codec, signal, scope);
|
|
1545
1654
|
return status === 200 ? response : new Response(response.body, {
|
|
1546
1655
|
status,
|
|
1547
1656
|
headers
|
|
@@ -1639,8 +1748,17 @@ function forbiddenResponse() {
|
|
|
1639
1748
|
}
|
|
1640
1749
|
}));
|
|
1641
1750
|
}
|
|
1751
|
+
function nativePromise(value) {
|
|
1752
|
+
if (value instanceof Promise) return value;
|
|
1753
|
+
try {
|
|
1754
|
+
if (Object.prototype.toString.call(value) === "[object Promise]") return Promise.prototype.then.call(value, value => value);
|
|
1755
|
+
} catch {}
|
|
1756
|
+
}
|
|
1642
1757
|
async function handleServerFunctionRequest(request, options = {}) {
|
|
1643
|
-
const codec =
|
|
1758
|
+
const codec = {
|
|
1759
|
+
...(options.codec !== undefined ? options.codec : getServerFunctionsCodec())
|
|
1760
|
+
};
|
|
1761
|
+
codec.serializeErrorStacks ??= DEV;
|
|
1644
1762
|
const url = new URL(request.url);
|
|
1645
1763
|
const method = request.method;
|
|
1646
1764
|
const address = resolveAddress(url);
|
|
@@ -1699,7 +1817,15 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1699
1817
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1700
1818
|
}
|
|
1701
1819
|
if (!(declared > 0)) {
|
|
1702
|
-
|
|
1820
|
+
let bounded;
|
|
1821
|
+
try {
|
|
1822
|
+
bounded = await bufferBodyWithin(request, bodySizeLimit);
|
|
1823
|
+
} catch {
|
|
1824
|
+
const response = new Response(DEV ? "Malformed server function arguments" : null, {
|
|
1825
|
+
status: 400
|
|
1826
|
+
});
|
|
1827
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1828
|
+
}
|
|
1703
1829
|
if (bounded === null) {
|
|
1704
1830
|
const response = new Response(DEV ? "Server function request body exceeds the configured bodySizeLimit" : null, {
|
|
1705
1831
|
status: 413
|
|
@@ -1709,16 +1835,30 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1709
1835
|
request = bounded;
|
|
1710
1836
|
}
|
|
1711
1837
|
}
|
|
1712
|
-
let event
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1838
|
+
let event;
|
|
1839
|
+
try {
|
|
1840
|
+
event = options.createEvent ? options.createEvent(request) : {
|
|
1841
|
+
request,
|
|
1842
|
+
locals: {}
|
|
1843
|
+
};
|
|
1844
|
+
const promised = nativePromise(event);
|
|
1845
|
+
if (promised) event = await promised;
|
|
1846
|
+
} catch (error) {
|
|
1847
|
+
const safe = sanitizeServerError(error);
|
|
1848
|
+
const message = safe instanceof Error ? safe.message : String(safe);
|
|
1849
|
+
const headers = new Headers();
|
|
1850
|
+
headers.set(ERROR_HEADER, boundedErrorHeaderValue(message));
|
|
1851
|
+
const response = scripted ? encodeResult(safe, headers, 500, codec, request.signal) : new Response(DEV ? message : null, {
|
|
1852
|
+
status: 500
|
|
1853
|
+
});
|
|
1854
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1855
|
+
}
|
|
1717
1856
|
const refuseCommitted = raw => {
|
|
1718
1857
|
const response = commitEventResponse(raw, event);
|
|
1719
1858
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1720
1859
|
};
|
|
1721
1860
|
const provide = options.provideEvent || provideEvent;
|
|
1861
|
+
const scope = run => provide(event, run);
|
|
1722
1862
|
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
1723
1863
|
const transformResult = options.transformResult !== undefined ? options.transformResult : config.transformResult;
|
|
1724
1864
|
const wrapInvocation = options.wrapInvocation !== undefined ? options.wrapInvocation : config.wrapInvocation;
|
|
@@ -1769,7 +1909,8 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1769
1909
|
const headers = new Headers();
|
|
1770
1910
|
const dispatch = async () => {
|
|
1771
1911
|
try {
|
|
1772
|
-
let
|
|
1912
|
+
let invocations = 0;
|
|
1913
|
+
const invokeOnce = async () => {
|
|
1773
1914
|
INVOCATIONS.set(event, {
|
|
1774
1915
|
id: functionId
|
|
1775
1916
|
});
|
|
@@ -1781,7 +1922,16 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1781
1922
|
request,
|
|
1782
1923
|
direct: false
|
|
1783
1924
|
}) : run();
|
|
1925
|
+
};
|
|
1926
|
+
let result = await provide(event, () => {
|
|
1927
|
+
if (++invocations > 1) {
|
|
1928
|
+
throw new Error("provideEvent invoked the server function callback more than once: a second " + "invocation would commit the call's side effects twice. The hook must call " + "fn exactly once and return its result.");
|
|
1929
|
+
}
|
|
1930
|
+
return invokeOnce();
|
|
1784
1931
|
});
|
|
1932
|
+
if (invocations !== 1) {
|
|
1933
|
+
throw new Error(invocations === 0 ? "provideEvent returned without invoking the server function callback: the call " + "would have answered as a void success without running the function. The hook " + "must call fn exactly once and return its result." : "provideEvent invoked the server function callback more than once: a second " + "invocation would commit the call's side effects twice. The hook must call " + "fn exactly once and return its result.");
|
|
1934
|
+
}
|
|
1785
1935
|
if (transformResult) {
|
|
1786
1936
|
result = await transformResult(event, result, flightContext);
|
|
1787
1937
|
}
|
|
@@ -1835,10 +1985,10 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1835
1985
|
if (!scripted) {
|
|
1836
1986
|
if (handleNoJS) return handleNoJS(result ?? metadata, request, parsed);
|
|
1837
1987
|
if (result instanceof Response) return result;
|
|
1838
|
-
return encodeResult(result, headers, status, codec, request.signal);
|
|
1988
|
+
return encodeResult(result, headers, status, codec, request.signal, scope);
|
|
1839
1989
|
}
|
|
1840
1990
|
if (status === 304) warnScripted304(functionId);
|
|
1841
|
-
return encodeResult(result, headers, status, codec, request.signal);
|
|
1991
|
+
return encodeResult(result, headers, status, codec, request.signal, scope);
|
|
1842
1992
|
} catch (x) {
|
|
1843
1993
|
const respondThrown = value => {
|
|
1844
1994
|
const safe = sanitizeServerError(value);
|
|
@@ -1851,7 +2001,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1851
2001
|
}
|
|
1852
2002
|
const error = safe instanceof Error ? safe.message : typeof safe === "string" ? safe : "true";
|
|
1853
2003
|
headers.set(ERROR_HEADER, boundedErrorHeaderValue(error));
|
|
1854
|
-
return encodeResult(safe, headers, 500, codec, request.signal);
|
|
2004
|
+
return encodeResult(safe, headers, 500, codec, request.signal, scope);
|
|
1855
2005
|
};
|
|
1856
2006
|
if (x instanceof Response || isResponseEnvelope(x)) {
|
|
1857
2007
|
if (transformResult) {
|
|
@@ -1915,7 +2065,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1915
2065
|
if (x instanceof Response) return x;
|
|
1916
2066
|
}
|
|
1917
2067
|
if (scripted && status === 304) warnScripted304(functionId);
|
|
1918
|
-
return encodeResult(x, headers, status, codec, request.signal);
|
|
2068
|
+
return encodeResult(x, headers, status, codec, request.signal, scope);
|
|
1919
2069
|
}
|
|
1920
2070
|
return respondThrown(x);
|
|
1921
2071
|
}
|