@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
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { sharedConfig } from 'solid-js';
|
|
2
2
|
|
|
3
|
+
const COMPOSED_BODY_FRAMING = /*#__PURE__*/new Set(["content-length", "content-encoding", "transfer-encoding"]);
|
|
4
|
+
function isHttpNavigationTarget(target) {
|
|
5
|
+
try {
|
|
6
|
+
const protocol = new URL(target, "http://base.invalid").protocol;
|
|
7
|
+
return protocol === "http:" || protocol === "https:";
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
|
|
4
14
|
function isResponseEnvelope(value) {
|
|
5
15
|
return !!(value && typeof value === "object" && value[ENVELOPE]);
|
|
@@ -554,7 +564,8 @@ function copyInitHeaders(init) {
|
|
|
554
564
|
for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
|
|
555
565
|
return headers;
|
|
556
566
|
}
|
|
557
|
-
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location"
|
|
567
|
+
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location",
|
|
568
|
+
...COMPOSED_BODY_FRAMING].map(header => header.toLowerCase()));
|
|
558
569
|
function fillsStubGap(key, headers, response) {
|
|
559
570
|
if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
|
|
560
571
|
if (response.body === null && (key === "content-type" || key === "content-length")) return false;
|
|
@@ -714,6 +725,52 @@ function provideEvent(event, fn) {
|
|
|
714
725
|
if (ctx) return ctx.run(event, fn);
|
|
715
726
|
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
716
727
|
}
|
|
728
|
+
function scopeDeferredResult(value, scope) {
|
|
729
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
730
|
+
const promised = scope(() => nativePromise(value));
|
|
731
|
+
if (promised) {
|
|
732
|
+
return promised.then(result => scope(() => scopeDeferredResult(result, scope)));
|
|
733
|
+
}
|
|
734
|
+
if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) {
|
|
735
|
+
let reader;
|
|
736
|
+
return new ReadableStream({
|
|
737
|
+
async pull(controller) {
|
|
738
|
+
try {
|
|
739
|
+
const step = await scope(() => {
|
|
740
|
+
if (!reader) reader = value.getReader();
|
|
741
|
+
return reader.read();
|
|
742
|
+
});
|
|
743
|
+
if (step.done) controller.close();else controller.enqueue(step.value);
|
|
744
|
+
} catch (error) {
|
|
745
|
+
controller.error(error);
|
|
746
|
+
}
|
|
747
|
+
},
|
|
748
|
+
cancel(reason) {
|
|
749
|
+
return scope(() => reader ? reader.cancel(reason) : value.cancel(reason));
|
|
750
|
+
}
|
|
751
|
+
}, {
|
|
752
|
+
highWaterMark: 0
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
const scopedIterator = symbol => ({
|
|
756
|
+
[symbol]() {
|
|
757
|
+
const iterator = scope(() => value[symbol]());
|
|
758
|
+
return new Proxy(iterator, {
|
|
759
|
+
get(target, property) {
|
|
760
|
+
const member = Reflect.get(target, property, target);
|
|
761
|
+
return typeof member === "function" && (property === "next" || property === "return" || property === "throw") ? (...args) => scope(() => member.apply(target, args)) : member;
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
if (typeof value[Symbol.asyncIterator] === "function") {
|
|
767
|
+
return scopedIterator(Symbol.asyncIterator);
|
|
768
|
+
}
|
|
769
|
+
if (typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
770
|
+
return scopedIterator(Symbol.iterator);
|
|
771
|
+
}
|
|
772
|
+
return value;
|
|
773
|
+
}
|
|
717
774
|
const REGISTRATIONS = new Map();
|
|
718
775
|
const METHODS = new Map();
|
|
719
776
|
const INVOCATIONS = new WeakMap();
|
|
@@ -811,7 +868,8 @@ function createServerReference({
|
|
|
811
868
|
id
|
|
812
869
|
});
|
|
813
870
|
evt.serverOnly = true;
|
|
814
|
-
const
|
|
871
|
+
const scope = run => provideEvent(evt, run);
|
|
872
|
+
let result = provideEvent(evt, () => {
|
|
815
873
|
const run = () => fn.apply(thisArg, args);
|
|
816
874
|
return config.wrapInvocation ? config.wrapInvocation(run, {
|
|
817
875
|
id,
|
|
@@ -820,19 +878,20 @@ function createServerReference({
|
|
|
820
878
|
direct: true
|
|
821
879
|
}) : run();
|
|
822
880
|
});
|
|
881
|
+
result = scopeDeferredResult(result, scope);
|
|
823
882
|
const transform = config.transformDirectResult;
|
|
824
883
|
if (transform && result && typeof result.then === "function") {
|
|
825
|
-
return result.then(value => transform(value, {
|
|
884
|
+
return result.then(value => scopeDeferredResult(transform(value, {
|
|
826
885
|
id,
|
|
827
886
|
args,
|
|
828
887
|
event: evt
|
|
829
|
-
}));
|
|
888
|
+
}), scope));
|
|
830
889
|
}
|
|
831
|
-
return transform ? transform(result, {
|
|
890
|
+
return transform ? scopeDeferredResult(transform(result, {
|
|
832
891
|
id,
|
|
833
892
|
args,
|
|
834
893
|
event: evt
|
|
835
|
-
}) : result;
|
|
894
|
+
}), scope) : result;
|
|
836
895
|
}
|
|
837
896
|
});
|
|
838
897
|
return proxy;
|
|
@@ -898,22 +957,58 @@ function assertDecodeDepth(value) {
|
|
|
898
957
|
level = next;
|
|
899
958
|
}
|
|
900
959
|
}
|
|
960
|
+
const UNSAFE_ARGUMENT_KEYS = ["__proto__", "constructor", "prototype"];
|
|
961
|
+
function stripUnsafeArgumentKeys(value) {
|
|
962
|
+
const stack = [value];
|
|
963
|
+
const seen = new Set();
|
|
964
|
+
while (stack.length) {
|
|
965
|
+
const v = stack.pop();
|
|
966
|
+
if (v === null || typeof v !== "object" || seen.has(v)) continue;
|
|
967
|
+
seen.add(v);
|
|
968
|
+
for (const key of UNSAFE_ARGUMENT_KEYS) {
|
|
969
|
+
delete v[key];
|
|
970
|
+
}
|
|
971
|
+
for (const key of Object.keys(v)) stack.push(v[key]);
|
|
972
|
+
if (v instanceof Map) {
|
|
973
|
+
for (const [k, entry] of v) stack.push(k, entry);
|
|
974
|
+
} else if (v instanceof Set) {
|
|
975
|
+
for (const member of v) stack.push(member);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
return value;
|
|
979
|
+
}
|
|
901
980
|
async function bufferBodyWithin(request, limit) {
|
|
902
|
-
const reader = request.
|
|
981
|
+
const reader = request.body.getReader();
|
|
982
|
+
const signal = request.signal;
|
|
903
983
|
const chunks = [];
|
|
904
984
|
let total = 0;
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
985
|
+
const onAbort = () => {
|
|
986
|
+
reader.cancel(signal.reason).catch(() => {});
|
|
987
|
+
};
|
|
988
|
+
if (signal.aborted) onAbort();else signal.addEventListener("abort", onAbort, {
|
|
989
|
+
once: true
|
|
990
|
+
});
|
|
991
|
+
try {
|
|
992
|
+
for (;;) {
|
|
993
|
+
const {
|
|
994
|
+
done,
|
|
995
|
+
value
|
|
996
|
+
} = await reader.read();
|
|
997
|
+
if (signal.aborted) throw signal.reason;
|
|
998
|
+
if (done) break;
|
|
999
|
+
total += value.byteLength;
|
|
1000
|
+
if (total > limit) {
|
|
1001
|
+
reader.cancel().catch(() => {});
|
|
1002
|
+
return null;
|
|
1003
|
+
}
|
|
1004
|
+
chunks.push(value);
|
|
915
1005
|
}
|
|
916
|
-
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
reader.cancel(error).catch(() => {});
|
|
1008
|
+
throw error;
|
|
1009
|
+
} finally {
|
|
1010
|
+
signal.removeEventListener("abort", onAbort);
|
|
1011
|
+
reader.releaseLock();
|
|
917
1012
|
}
|
|
918
1013
|
const body = new Uint8Array(total);
|
|
919
1014
|
let offset = 0;
|
|
@@ -940,6 +1035,7 @@ async function parseArguments(request, url, scripted, codec) {
|
|
|
940
1035
|
if (!Array.isArray(result)) {
|
|
941
1036
|
throw new TypeError("Server function arguments must encode an array");
|
|
942
1037
|
}
|
|
1038
|
+
stripUnsafeArgumentKeys(result);
|
|
943
1039
|
for (const arg of result) {
|
|
944
1040
|
parsed.push(arg);
|
|
945
1041
|
}
|
|
@@ -953,9 +1049,12 @@ async function parseArguments(request, url, scripted, codec) {
|
|
|
953
1049
|
if (!Array.isArray(decoded)) {
|
|
954
1050
|
throw new TypeError("Server function arguments must encode an array");
|
|
955
1051
|
}
|
|
956
|
-
return decoded;
|
|
1052
|
+
return stripUnsafeArgumentKeys(decoded);
|
|
957
1053
|
}
|
|
958
1054
|
if (decoded === undefined) {
|
|
1055
|
+
if (bodyFormat === null && (await request.clone().arrayBuffer()).byteLength === 0) {
|
|
1056
|
+
return parsed;
|
|
1057
|
+
}
|
|
959
1058
|
throw new TypeError("Server function body carries no usable encoding");
|
|
960
1059
|
}
|
|
961
1060
|
parsed.push(decoded);
|
|
@@ -1056,7 +1155,7 @@ function foldSetCookies(headers, setCookies) {
|
|
|
1056
1155
|
}
|
|
1057
1156
|
function mergeResponseHeaders(target, source) {
|
|
1058
1157
|
source.forEach((value, key) => {
|
|
1059
|
-
if (key !== "set-cookie") target.append(key, value);
|
|
1158
|
+
if (key !== "set-cookie" && !COMPOSED_BODY_FRAMING.has(key)) target.append(key, value);
|
|
1060
1159
|
});
|
|
1061
1160
|
if (source.getSetCookie) {
|
|
1062
1161
|
for (const cookie of source.getSetCookie()) target.append("Set-Cookie", cookie);
|
|
@@ -1073,10 +1172,6 @@ function maskRedirect(headers, response, requestUrl) {
|
|
|
1073
1172
|
headers.delete("Location");
|
|
1074
1173
|
}
|
|
1075
1174
|
const BOUNDED_COMPOSED_HEADERS = [REDIRECT_HEADER, "Location", REVALIDATE_HEADER];
|
|
1076
|
-
function refusedTargetScheme(target) {
|
|
1077
|
-
const match = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.exec(target);
|
|
1078
|
-
return match !== null && !/^https?:$/i.test(match[0]);
|
|
1079
|
-
}
|
|
1080
1175
|
function enforceComposedHeaderInvariants(response) {
|
|
1081
1176
|
for (const name of BOUNDED_COMPOSED_HEADERS) {
|
|
1082
1177
|
const value = response.headers.get(name);
|
|
@@ -1086,7 +1181,7 @@ function enforceComposedHeaderInvariants(response) {
|
|
|
1086
1181
|
}
|
|
1087
1182
|
if (name === REVALIDATE_HEADER) continue;
|
|
1088
1183
|
const target = name === REDIRECT_HEADER ? value.slice(value.indexOf(" ") + 1) : value;
|
|
1089
|
-
if (
|
|
1184
|
+
if (!isHttpNavigationTarget(target)) {
|
|
1090
1185
|
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);
|
|
1091
1186
|
}
|
|
1092
1187
|
}
|
|
@@ -1214,14 +1309,11 @@ function guardFailures(value, state) {
|
|
|
1214
1309
|
top.next.add(guarded);
|
|
1215
1310
|
if (guarded !== original) top.changed = true;
|
|
1216
1311
|
} else if (guarded !== original || top.accessorRead === i) {
|
|
1217
|
-
Object.defineProperty(top.next, items[i],
|
|
1218
|
-
|
|
1219
|
-
configurable: true,
|
|
1312
|
+
Object.defineProperty(top.next, items[i], {
|
|
1313
|
+
value: guarded,
|
|
1220
1314
|
writable: true,
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
...top.descriptors[items[i]],
|
|
1224
|
-
value: guarded
|
|
1315
|
+
configurable: true,
|
|
1316
|
+
enumerable: top.descriptors[items[i]].enumerable
|
|
1225
1317
|
});
|
|
1226
1318
|
top.changed = true;
|
|
1227
1319
|
}
|
|
@@ -1256,6 +1348,9 @@ class Frame {
|
|
|
1256
1348
|
this.pendingKey = undefined;
|
|
1257
1349
|
}
|
|
1258
1350
|
}
|
|
1351
|
+
function guardOperation(state, run) {
|
|
1352
|
+
return state.scope ? state.scope(run) : run();
|
|
1353
|
+
}
|
|
1259
1354
|
function enterGuard(value, state) {
|
|
1260
1355
|
if (value === null || typeof value !== "object") return value;
|
|
1261
1356
|
if (state.seen.has(value)) {
|
|
@@ -1270,7 +1365,7 @@ function enterGuard(value, state) {
|
|
|
1270
1365
|
if (finished) return;
|
|
1271
1366
|
finished = true;
|
|
1272
1367
|
try {
|
|
1273
|
-
const cancelled = reader ? reader.cancel() : value.cancel();
|
|
1368
|
+
const cancelled = guardOperation(state, () => reader ? reader.cancel() : value.cancel());
|
|
1274
1369
|
if (cancelled && typeof cancelled.then === "function") cancelled.then(undefined, () => {});
|
|
1275
1370
|
} catch {}
|
|
1276
1371
|
};
|
|
@@ -1282,19 +1377,19 @@ function enterGuard(value, state) {
|
|
|
1282
1377
|
controller.close();
|
|
1283
1378
|
return;
|
|
1284
1379
|
}
|
|
1285
|
-
if (!reader) reader = value.getReader();
|
|
1380
|
+
if (!reader) reader = guardOperation(state, () => value.getReader());
|
|
1286
1381
|
const {
|
|
1287
1382
|
done,
|
|
1288
1383
|
value: chunk
|
|
1289
|
-
} = await reader.read();
|
|
1290
|
-
done ? controller.close() : controller.enqueue(guardFailures(chunk, state));
|
|
1384
|
+
} = await guardOperation(state, () => reader.read());
|
|
1385
|
+
done ? controller.close() : controller.enqueue(guardOperation(state, () => guardFailures(chunk, state)));
|
|
1291
1386
|
} catch (error) {
|
|
1292
|
-
controller.error(sanitizeServerError(error));
|
|
1387
|
+
controller.error(guardOperation(state, () => sanitizeServerError(error)));
|
|
1293
1388
|
}
|
|
1294
1389
|
},
|
|
1295
1390
|
cancel(reason) {
|
|
1296
1391
|
finished = true;
|
|
1297
|
-
return reader ? reader.cancel(reason) : value.cancel(reason);
|
|
1392
|
+
return guardOperation(state, () => reader ? reader.cancel(reason) : value.cancel(reason));
|
|
1298
1393
|
}
|
|
1299
1394
|
});
|
|
1300
1395
|
if (gate) gate.onOpen(close);
|
|
@@ -1302,9 +1397,10 @@ function enterGuard(value, state) {
|
|
|
1302
1397
|
return guardedStream;
|
|
1303
1398
|
}
|
|
1304
1399
|
if (typeof value.then === "function") {
|
|
1305
|
-
const guardedPromise = Promise.resolve(value).then(resolved => guardFailures(resolved, state), error => {
|
|
1306
|
-
throw sanitizeServerError(error);
|
|
1400
|
+
const guardedPromise = Promise.resolve(value).then(resolved => guardOperation(state, () => guardFailures(resolved, state)), error => {
|
|
1401
|
+
throw guardOperation(state, () => sanitizeServerError(error));
|
|
1307
1402
|
});
|
|
1403
|
+
guardedPromise.catch(() => {});
|
|
1308
1404
|
state.seen.set(value, guardedPromise);
|
|
1309
1405
|
return guardedPromise;
|
|
1310
1406
|
}
|
|
@@ -1313,13 +1409,13 @@ function enterGuard(value, state) {
|
|
|
1313
1409
|
const gate = state.gate;
|
|
1314
1410
|
const guardedIterable = {
|
|
1315
1411
|
[Symbol.asyncIterator]() {
|
|
1316
|
-
const iterator = source[Symbol.asyncIterator]();
|
|
1412
|
+
const iterator = guardOperation(state, () => source[Symbol.asyncIterator]());
|
|
1317
1413
|
let finished = false;
|
|
1318
1414
|
const close = () => {
|
|
1319
1415
|
if (finished) return;
|
|
1320
1416
|
finished = true;
|
|
1321
1417
|
try {
|
|
1322
|
-
const returned = iterator.return && iterator.return();
|
|
1418
|
+
const returned = iterator.return && guardOperation(state, () => iterator.return());
|
|
1323
1419
|
if (returned && typeof returned.then === "function") returned.then(undefined, () => {});
|
|
1324
1420
|
} catch {}
|
|
1325
1421
|
};
|
|
@@ -1327,17 +1423,17 @@ function enterGuard(value, state) {
|
|
|
1327
1423
|
const step = () => finished ? Promise.resolve({
|
|
1328
1424
|
done: true,
|
|
1329
1425
|
value: undefined
|
|
1330
|
-
}) : iterator.next().then(step => {
|
|
1426
|
+
}) : guardOperation(state, () => iterator.next()).then(step => {
|
|
1331
1427
|
if (step.done) {
|
|
1332
1428
|
finished = true;
|
|
1333
1429
|
return step;
|
|
1334
1430
|
}
|
|
1335
1431
|
return {
|
|
1336
1432
|
done: false,
|
|
1337
|
-
value: guardFailures(step.value, state)
|
|
1433
|
+
value: guardOperation(state, () => guardFailures(step.value, state))
|
|
1338
1434
|
};
|
|
1339
1435
|
}, error => {
|
|
1340
|
-
throw sanitizeServerError(error);
|
|
1436
|
+
throw guardOperation(state, () => sanitizeServerError(error));
|
|
1341
1437
|
});
|
|
1342
1438
|
return {
|
|
1343
1439
|
next: () => finished || !gate || gate.wantsMore() ? step() : gate.awaitDemand().then(step),
|
|
@@ -1354,6 +1450,11 @@ function enterGuard(value, state) {
|
|
|
1354
1450
|
state.seen.set(value, guardedIterable);
|
|
1355
1451
|
return guardedIterable;
|
|
1356
1452
|
}
|
|
1453
|
+
if (state.scope && typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
1454
|
+
const scopedIterable = scopeDeferredResult(value, state.scope);
|
|
1455
|
+
state.seen.set(value, scopedIterable);
|
|
1456
|
+
return scopedIterable;
|
|
1457
|
+
}
|
|
1357
1458
|
if (Array.isArray(value)) {
|
|
1358
1459
|
const next = value.slice();
|
|
1359
1460
|
state.seen.set(value, next);
|
|
@@ -1377,16 +1478,20 @@ function enterGuard(value, state) {
|
|
|
1377
1478
|
return value;
|
|
1378
1479
|
}
|
|
1379
1480
|
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
1481
|
+
for (const key of Object.keys(descriptors)) {
|
|
1482
|
+
descriptors[key].configurable = true;
|
|
1483
|
+
if ("value" in descriptors[key]) descriptors[key].writable = true;
|
|
1484
|
+
}
|
|
1380
1485
|
const next = Object.create(prototype, descriptors);
|
|
1381
1486
|
state.seen.set(value, next);
|
|
1382
|
-
return new Frame(OBJECT, value, next, Object.keys(
|
|
1487
|
+
return new Frame(OBJECT, value, next, Object.keys(value), descriptors);
|
|
1383
1488
|
}
|
|
1384
1489
|
function keepGuarded(value, next, changed, state) {
|
|
1385
1490
|
if (changed || state.cyclic.has(value)) return next;
|
|
1386
1491
|
state.seen.set(value, value);
|
|
1387
1492
|
return value;
|
|
1388
1493
|
}
|
|
1389
|
-
function serializeResponseStream(value, codecOptions, signal) {
|
|
1494
|
+
function serializeResponseStream(value, codecOptions, signal, scope) {
|
|
1390
1495
|
let closed = false;
|
|
1391
1496
|
let streamController = null;
|
|
1392
1497
|
let demandWaiters = null;
|
|
@@ -1405,11 +1510,13 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
1405
1510
|
if (closed) close();else sourceClosers.add(close);
|
|
1406
1511
|
}
|
|
1407
1512
|
};
|
|
1408
|
-
|
|
1513
|
+
const guardState = {
|
|
1409
1514
|
seen: new WeakMap(),
|
|
1410
1515
|
cyclic: new WeakSet(),
|
|
1411
|
-
gate
|
|
1412
|
-
|
|
1516
|
+
gate,
|
|
1517
|
+
scope
|
|
1518
|
+
};
|
|
1519
|
+
value = guardOperation(guardState, () => guardFailures(value, guardState));
|
|
1413
1520
|
let cancelSerialize = null;
|
|
1414
1521
|
let onAbort = null;
|
|
1415
1522
|
const finishSource = () => {
|
|
@@ -1490,14 +1597,14 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
1490
1597
|
}
|
|
1491
1598
|
});
|
|
1492
1599
|
}
|
|
1493
|
-
function serializedResponse(value, headers, codec, signal) {
|
|
1600
|
+
function serializedResponse(value, headers, codec, signal, scope) {
|
|
1494
1601
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
1495
1602
|
headers.set("Content-Type", "text/plain");
|
|
1496
|
-
return new Response(serializeResponseStream(value, codec, signal), {
|
|
1603
|
+
return new Response(serializeResponseStream(value, codec, signal, scope), {
|
|
1497
1604
|
headers
|
|
1498
1605
|
});
|
|
1499
1606
|
}
|
|
1500
|
-
function encodeResult(value, headers, status, codec, signal) {
|
|
1607
|
+
function encodeResult(value, headers, status, codec, signal, scope) {
|
|
1501
1608
|
if (NULL_BODY_STATUSES.has(status)) {
|
|
1502
1609
|
if (value === undefined || value === null) {
|
|
1503
1610
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Void);
|
|
@@ -1508,7 +1615,7 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1508
1615
|
}
|
|
1509
1616
|
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.`);
|
|
1510
1617
|
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error.message));
|
|
1511
|
-
return encodeResult(error, headers, 500, codec, signal);
|
|
1618
|
+
return encodeResult(error, headers, 500, codec, signal, scope);
|
|
1512
1619
|
}
|
|
1513
1620
|
const direct = getHeadersAndBody(value);
|
|
1514
1621
|
if (direct) {
|
|
@@ -1528,10 +1635,12 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1528
1635
|
});
|
|
1529
1636
|
}
|
|
1530
1637
|
try {
|
|
1531
|
-
|
|
1638
|
+
const jsonSafe = scope ? scope(() => isJSONSafe(value)) : isJSONSafe(value);
|
|
1639
|
+
if (jsonSafe) {
|
|
1532
1640
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Json);
|
|
1533
1641
|
headers.set("Content-Type", "application/json");
|
|
1534
|
-
|
|
1642
|
+
const body = scope ? scope(() => JSON.stringify(value)) : JSON.stringify(value);
|
|
1643
|
+
return new Response(body, {
|
|
1535
1644
|
status,
|
|
1536
1645
|
headers
|
|
1537
1646
|
});
|
|
@@ -1539,7 +1648,7 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1539
1648
|
} catch {
|
|
1540
1649
|
}
|
|
1541
1650
|
try {
|
|
1542
|
-
const response = serializedResponse(value, headers, codec, signal);
|
|
1651
|
+
const response = serializedResponse(value, headers, codec, signal, scope);
|
|
1543
1652
|
return status === 200 ? response : new Response(response.body, {
|
|
1544
1653
|
status,
|
|
1545
1654
|
headers
|
|
@@ -1637,8 +1746,17 @@ function forbiddenResponse() {
|
|
|
1637
1746
|
}
|
|
1638
1747
|
}));
|
|
1639
1748
|
}
|
|
1749
|
+
function nativePromise(value) {
|
|
1750
|
+
if (value instanceof Promise) return value;
|
|
1751
|
+
try {
|
|
1752
|
+
if (Object.prototype.toString.call(value) === "[object Promise]") return Promise.prototype.then.call(value, value => value);
|
|
1753
|
+
} catch {}
|
|
1754
|
+
}
|
|
1640
1755
|
async function handleServerFunctionRequest(request, options = {}) {
|
|
1641
|
-
const codec =
|
|
1756
|
+
const codec = {
|
|
1757
|
+
...(options.codec !== undefined ? options.codec : getServerFunctionsCodec())
|
|
1758
|
+
};
|
|
1759
|
+
codec.serializeErrorStacks ??= DEV;
|
|
1642
1760
|
const url = new URL(request.url);
|
|
1643
1761
|
const method = request.method;
|
|
1644
1762
|
const address = resolveAddress(url);
|
|
@@ -1697,7 +1815,15 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1697
1815
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1698
1816
|
}
|
|
1699
1817
|
if (!(declared > 0)) {
|
|
1700
|
-
|
|
1818
|
+
let bounded;
|
|
1819
|
+
try {
|
|
1820
|
+
bounded = await bufferBodyWithin(request, bodySizeLimit);
|
|
1821
|
+
} catch {
|
|
1822
|
+
const response = new Response(DEV ? "Malformed server function arguments" : null, {
|
|
1823
|
+
status: 400
|
|
1824
|
+
});
|
|
1825
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1826
|
+
}
|
|
1701
1827
|
if (bounded === null) {
|
|
1702
1828
|
const response = new Response(DEV ? "Server function request body exceeds the configured bodySizeLimit" : null, {
|
|
1703
1829
|
status: 413
|
|
@@ -1707,16 +1833,30 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1707
1833
|
request = bounded;
|
|
1708
1834
|
}
|
|
1709
1835
|
}
|
|
1710
|
-
let event
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1836
|
+
let event;
|
|
1837
|
+
try {
|
|
1838
|
+
event = options.createEvent ? options.createEvent(request) : {
|
|
1839
|
+
request,
|
|
1840
|
+
locals: {}
|
|
1841
|
+
};
|
|
1842
|
+
const promised = nativePromise(event);
|
|
1843
|
+
if (promised) event = await promised;
|
|
1844
|
+
} catch (error) {
|
|
1845
|
+
const safe = sanitizeServerError(error);
|
|
1846
|
+
const message = safe instanceof Error ? safe.message : String(safe);
|
|
1847
|
+
const headers = new Headers();
|
|
1848
|
+
headers.set(ERROR_HEADER, boundedErrorHeaderValue(message));
|
|
1849
|
+
const response = scripted ? encodeResult(safe, headers, 500, codec, request.signal) : new Response(DEV ? message : null, {
|
|
1850
|
+
status: 500
|
|
1851
|
+
});
|
|
1852
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1853
|
+
}
|
|
1715
1854
|
const refuseCommitted = raw => {
|
|
1716
1855
|
const response = commitEventResponse(raw, event);
|
|
1717
1856
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1718
1857
|
};
|
|
1719
1858
|
const provide = options.provideEvent || provideEvent;
|
|
1859
|
+
const scope = run => provide(event, run);
|
|
1720
1860
|
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
1721
1861
|
const transformResult = options.transformResult !== undefined ? options.transformResult : config.transformResult;
|
|
1722
1862
|
const wrapInvocation = options.wrapInvocation !== undefined ? options.wrapInvocation : config.wrapInvocation;
|
|
@@ -1767,7 +1907,8 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1767
1907
|
const headers = new Headers();
|
|
1768
1908
|
const dispatch = async () => {
|
|
1769
1909
|
try {
|
|
1770
|
-
let
|
|
1910
|
+
let invocations = 0;
|
|
1911
|
+
const invokeOnce = async () => {
|
|
1771
1912
|
INVOCATIONS.set(event, {
|
|
1772
1913
|
id: functionId
|
|
1773
1914
|
});
|
|
@@ -1779,7 +1920,16 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1779
1920
|
request,
|
|
1780
1921
|
direct: false
|
|
1781
1922
|
}) : run();
|
|
1923
|
+
};
|
|
1924
|
+
let result = await provide(event, () => {
|
|
1925
|
+
if (++invocations > 1) {
|
|
1926
|
+
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.");
|
|
1927
|
+
}
|
|
1928
|
+
return invokeOnce();
|
|
1782
1929
|
});
|
|
1930
|
+
if (invocations !== 1) {
|
|
1931
|
+
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.");
|
|
1932
|
+
}
|
|
1783
1933
|
if (transformResult) {
|
|
1784
1934
|
result = await transformResult(event, result, flightContext);
|
|
1785
1935
|
}
|
|
@@ -1833,10 +1983,10 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1833
1983
|
if (!scripted) {
|
|
1834
1984
|
if (handleNoJS) return handleNoJS(result ?? metadata, request, parsed);
|
|
1835
1985
|
if (result instanceof Response) return result;
|
|
1836
|
-
return encodeResult(result, headers, status, codec, request.signal);
|
|
1986
|
+
return encodeResult(result, headers, status, codec, request.signal, scope);
|
|
1837
1987
|
}
|
|
1838
1988
|
if (status === 304) warnScripted304(functionId);
|
|
1839
|
-
return encodeResult(result, headers, status, codec, request.signal);
|
|
1989
|
+
return encodeResult(result, headers, status, codec, request.signal, scope);
|
|
1840
1990
|
} catch (x) {
|
|
1841
1991
|
const respondThrown = value => {
|
|
1842
1992
|
const safe = sanitizeServerError(value);
|
|
@@ -1849,7 +1999,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1849
1999
|
}
|
|
1850
2000
|
const error = safe instanceof Error ? safe.message : typeof safe === "string" ? safe : "true";
|
|
1851
2001
|
headers.set(ERROR_HEADER, boundedErrorHeaderValue(error));
|
|
1852
|
-
return encodeResult(safe, headers, 500, codec, request.signal);
|
|
2002
|
+
return encodeResult(safe, headers, 500, codec, request.signal, scope);
|
|
1853
2003
|
};
|
|
1854
2004
|
if (x instanceof Response || isResponseEnvelope(x)) {
|
|
1855
2005
|
if (transformResult) {
|
|
@@ -1913,7 +2063,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1913
2063
|
if (x instanceof Response) return x;
|
|
1914
2064
|
}
|
|
1915
2065
|
if (scripted && status === 304) warnScripted304(functionId);
|
|
1916
|
-
return encodeResult(x, headers, status, codec, request.signal);
|
|
2066
|
+
return encodeResult(x, headers, status, codec, request.signal, scope);
|
|
1917
2067
|
}
|
|
1918
2068
|
return respondThrown(x);
|
|
1919
2069
|
}
|