@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]);
|
|
@@ -536,7 +546,8 @@ function copyInitHeaders(init) {
|
|
|
536
546
|
for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
|
|
537
547
|
return headers;
|
|
538
548
|
}
|
|
539
|
-
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location"
|
|
549
|
+
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location",
|
|
550
|
+
...COMPOSED_BODY_FRAMING].map(header => header.toLowerCase()));
|
|
540
551
|
function fillsStubGap(key, headers, response) {
|
|
541
552
|
if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
|
|
542
553
|
if (response.body === null && (key === "content-type" || key === "content-length")) return false;
|
|
@@ -696,6 +707,52 @@ function provideEvent(event, fn) {
|
|
|
696
707
|
if (ctx) return ctx.run(event, fn);
|
|
697
708
|
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
698
709
|
}
|
|
710
|
+
function scopeDeferredResult(value, scope) {
|
|
711
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
712
|
+
const promised = scope(() => nativePromise(value));
|
|
713
|
+
if (promised) {
|
|
714
|
+
return promised.then(result => scope(() => scopeDeferredResult(result, scope)));
|
|
715
|
+
}
|
|
716
|
+
if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) {
|
|
717
|
+
let reader;
|
|
718
|
+
return new ReadableStream({
|
|
719
|
+
async pull(controller) {
|
|
720
|
+
try {
|
|
721
|
+
const step = await scope(() => {
|
|
722
|
+
if (!reader) reader = value.getReader();
|
|
723
|
+
return reader.read();
|
|
724
|
+
});
|
|
725
|
+
if (step.done) controller.close();else controller.enqueue(step.value);
|
|
726
|
+
} catch (error) {
|
|
727
|
+
controller.error(error);
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
cancel(reason) {
|
|
731
|
+
return scope(() => reader ? reader.cancel(reason) : value.cancel(reason));
|
|
732
|
+
}
|
|
733
|
+
}, {
|
|
734
|
+
highWaterMark: 0
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
const scopedIterator = symbol => ({
|
|
738
|
+
[symbol]() {
|
|
739
|
+
const iterator = scope(() => value[symbol]());
|
|
740
|
+
return new Proxy(iterator, {
|
|
741
|
+
get(target, property) {
|
|
742
|
+
const member = Reflect.get(target, property, target);
|
|
743
|
+
return typeof member === "function" && (property === "next" || property === "return" || property === "throw") ? (...args) => scope(() => member.apply(target, args)) : member;
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
if (typeof value[Symbol.asyncIterator] === "function") {
|
|
749
|
+
return scopedIterator(Symbol.asyncIterator);
|
|
750
|
+
}
|
|
751
|
+
if (typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
752
|
+
return scopedIterator(Symbol.iterator);
|
|
753
|
+
}
|
|
754
|
+
return value;
|
|
755
|
+
}
|
|
699
756
|
const REGISTRATIONS = new Map();
|
|
700
757
|
const METHODS = new Map();
|
|
701
758
|
const INVOCATIONS = new WeakMap();
|
|
@@ -793,7 +850,8 @@ function createServerReference({
|
|
|
793
850
|
id
|
|
794
851
|
});
|
|
795
852
|
evt.serverOnly = true;
|
|
796
|
-
const
|
|
853
|
+
const scope = run => provideEvent(evt, run);
|
|
854
|
+
let result = provideEvent(evt, () => {
|
|
797
855
|
const run = () => fn.apply(thisArg, args);
|
|
798
856
|
return config.wrapInvocation ? config.wrapInvocation(run, {
|
|
799
857
|
id,
|
|
@@ -802,19 +860,20 @@ function createServerReference({
|
|
|
802
860
|
direct: true
|
|
803
861
|
}) : run();
|
|
804
862
|
});
|
|
863
|
+
result = scopeDeferredResult(result, scope);
|
|
805
864
|
const transform = config.transformDirectResult;
|
|
806
865
|
if (transform && result && typeof result.then === "function") {
|
|
807
|
-
return result.then(value => transform(value, {
|
|
866
|
+
return result.then(value => scopeDeferredResult(transform(value, {
|
|
808
867
|
id,
|
|
809
868
|
args,
|
|
810
869
|
event: evt
|
|
811
|
-
}));
|
|
870
|
+
}), scope));
|
|
812
871
|
}
|
|
813
|
-
return transform ? transform(result, {
|
|
872
|
+
return transform ? scopeDeferredResult(transform(result, {
|
|
814
873
|
id,
|
|
815
874
|
args,
|
|
816
875
|
event: evt
|
|
817
|
-
}) : result;
|
|
876
|
+
}), scope) : result;
|
|
818
877
|
}
|
|
819
878
|
});
|
|
820
879
|
return proxy;
|
|
@@ -880,22 +939,58 @@ function assertDecodeDepth(value) {
|
|
|
880
939
|
level = next;
|
|
881
940
|
}
|
|
882
941
|
}
|
|
942
|
+
const UNSAFE_ARGUMENT_KEYS = ["__proto__", "constructor", "prototype"];
|
|
943
|
+
function stripUnsafeArgumentKeys(value) {
|
|
944
|
+
const stack = [value];
|
|
945
|
+
const seen = new Set();
|
|
946
|
+
while (stack.length) {
|
|
947
|
+
const v = stack.pop();
|
|
948
|
+
if (v === null || typeof v !== "object" || seen.has(v)) continue;
|
|
949
|
+
seen.add(v);
|
|
950
|
+
for (const key of UNSAFE_ARGUMENT_KEYS) {
|
|
951
|
+
delete v[key];
|
|
952
|
+
}
|
|
953
|
+
for (const key of Object.keys(v)) stack.push(v[key]);
|
|
954
|
+
if (v instanceof Map) {
|
|
955
|
+
for (const [k, entry] of v) stack.push(k, entry);
|
|
956
|
+
} else if (v instanceof Set) {
|
|
957
|
+
for (const member of v) stack.push(member);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return value;
|
|
961
|
+
}
|
|
883
962
|
async function bufferBodyWithin(request, limit) {
|
|
884
|
-
const reader = request.
|
|
963
|
+
const reader = request.body.getReader();
|
|
964
|
+
const signal = request.signal;
|
|
885
965
|
const chunks = [];
|
|
886
966
|
let total = 0;
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
967
|
+
const onAbort = () => {
|
|
968
|
+
reader.cancel(signal.reason).catch(() => {});
|
|
969
|
+
};
|
|
970
|
+
if (signal.aborted) onAbort();else signal.addEventListener("abort", onAbort, {
|
|
971
|
+
once: true
|
|
972
|
+
});
|
|
973
|
+
try {
|
|
974
|
+
for (;;) {
|
|
975
|
+
const {
|
|
976
|
+
done,
|
|
977
|
+
value
|
|
978
|
+
} = await reader.read();
|
|
979
|
+
if (signal.aborted) throw signal.reason;
|
|
980
|
+
if (done) break;
|
|
981
|
+
total += value.byteLength;
|
|
982
|
+
if (total > limit) {
|
|
983
|
+
reader.cancel().catch(() => {});
|
|
984
|
+
return null;
|
|
985
|
+
}
|
|
986
|
+
chunks.push(value);
|
|
897
987
|
}
|
|
898
|
-
|
|
988
|
+
} catch (error) {
|
|
989
|
+
reader.cancel(error).catch(() => {});
|
|
990
|
+
throw error;
|
|
991
|
+
} finally {
|
|
992
|
+
signal.removeEventListener("abort", onAbort);
|
|
993
|
+
reader.releaseLock();
|
|
899
994
|
}
|
|
900
995
|
const body = new Uint8Array(total);
|
|
901
996
|
let offset = 0;
|
|
@@ -922,6 +1017,7 @@ async function parseArguments(request, url, scripted, codec) {
|
|
|
922
1017
|
if (!Array.isArray(result)) {
|
|
923
1018
|
throw new TypeError("Server function arguments must encode an array");
|
|
924
1019
|
}
|
|
1020
|
+
stripUnsafeArgumentKeys(result);
|
|
925
1021
|
for (const arg of result) {
|
|
926
1022
|
parsed.push(arg);
|
|
927
1023
|
}
|
|
@@ -935,9 +1031,12 @@ async function parseArguments(request, url, scripted, codec) {
|
|
|
935
1031
|
if (!Array.isArray(decoded)) {
|
|
936
1032
|
throw new TypeError("Server function arguments must encode an array");
|
|
937
1033
|
}
|
|
938
|
-
return decoded;
|
|
1034
|
+
return stripUnsafeArgumentKeys(decoded);
|
|
939
1035
|
}
|
|
940
1036
|
if (decoded === undefined) {
|
|
1037
|
+
if (bodyFormat === null && (await request.clone().arrayBuffer()).byteLength === 0) {
|
|
1038
|
+
return parsed;
|
|
1039
|
+
}
|
|
941
1040
|
throw new TypeError("Server function body carries no usable encoding");
|
|
942
1041
|
}
|
|
943
1042
|
parsed.push(decoded);
|
|
@@ -1038,7 +1137,7 @@ function foldSetCookies(headers, setCookies) {
|
|
|
1038
1137
|
}
|
|
1039
1138
|
function mergeResponseHeaders(target, source) {
|
|
1040
1139
|
source.forEach((value, key) => {
|
|
1041
|
-
if (key !== "set-cookie") target.append(key, value);
|
|
1140
|
+
if (key !== "set-cookie" && !COMPOSED_BODY_FRAMING.has(key)) target.append(key, value);
|
|
1042
1141
|
});
|
|
1043
1142
|
if (source.getSetCookie) {
|
|
1044
1143
|
for (const cookie of source.getSetCookie()) target.append("Set-Cookie", cookie);
|
|
@@ -1055,10 +1154,6 @@ function maskRedirect(headers, response, requestUrl) {
|
|
|
1055
1154
|
headers.delete("Location");
|
|
1056
1155
|
}
|
|
1057
1156
|
const BOUNDED_COMPOSED_HEADERS = [REDIRECT_HEADER, "Location", REVALIDATE_HEADER];
|
|
1058
|
-
function refusedTargetScheme(target) {
|
|
1059
|
-
const match = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.exec(target);
|
|
1060
|
-
return match !== null && !/^https?:$/i.test(match[0]);
|
|
1061
|
-
}
|
|
1062
1157
|
function enforceComposedHeaderInvariants(response) {
|
|
1063
1158
|
for (const name of BOUNDED_COMPOSED_HEADERS) {
|
|
1064
1159
|
const value = response.headers.get(name);
|
|
@@ -1068,7 +1163,7 @@ function enforceComposedHeaderInvariants(response) {
|
|
|
1068
1163
|
}
|
|
1069
1164
|
if (name === REVALIDATE_HEADER) continue;
|
|
1070
1165
|
const target = name === REDIRECT_HEADER ? value.slice(value.indexOf(" ") + 1) : value;
|
|
1071
|
-
if (
|
|
1166
|
+
if (!isHttpNavigationTarget(target)) {
|
|
1072
1167
|
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);
|
|
1073
1168
|
}
|
|
1074
1169
|
}
|
|
@@ -1196,14 +1291,11 @@ function guardFailures(value, state) {
|
|
|
1196
1291
|
top.next.add(guarded);
|
|
1197
1292
|
if (guarded !== original) top.changed = true;
|
|
1198
1293
|
} else if (guarded !== original || top.accessorRead === i) {
|
|
1199
|
-
Object.defineProperty(top.next, items[i],
|
|
1200
|
-
|
|
1201
|
-
configurable: true,
|
|
1294
|
+
Object.defineProperty(top.next, items[i], {
|
|
1295
|
+
value: guarded,
|
|
1202
1296
|
writable: true,
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
...top.descriptors[items[i]],
|
|
1206
|
-
value: guarded
|
|
1297
|
+
configurable: true,
|
|
1298
|
+
enumerable: top.descriptors[items[i]].enumerable
|
|
1207
1299
|
});
|
|
1208
1300
|
top.changed = true;
|
|
1209
1301
|
}
|
|
@@ -1238,6 +1330,9 @@ class Frame {
|
|
|
1238
1330
|
this.pendingKey = undefined;
|
|
1239
1331
|
}
|
|
1240
1332
|
}
|
|
1333
|
+
function guardOperation(state, run) {
|
|
1334
|
+
return state.scope ? state.scope(run) : run();
|
|
1335
|
+
}
|
|
1241
1336
|
function enterGuard(value, state) {
|
|
1242
1337
|
if (value === null || typeof value !== "object") return value;
|
|
1243
1338
|
if (state.seen.has(value)) {
|
|
@@ -1252,7 +1347,7 @@ function enterGuard(value, state) {
|
|
|
1252
1347
|
if (finished) return;
|
|
1253
1348
|
finished = true;
|
|
1254
1349
|
try {
|
|
1255
|
-
const cancelled = reader ? reader.cancel() : value.cancel();
|
|
1350
|
+
const cancelled = guardOperation(state, () => reader ? reader.cancel() : value.cancel());
|
|
1256
1351
|
if (cancelled && typeof cancelled.then === "function") cancelled.then(undefined, () => {});
|
|
1257
1352
|
} catch {}
|
|
1258
1353
|
};
|
|
@@ -1264,19 +1359,19 @@ function enterGuard(value, state) {
|
|
|
1264
1359
|
controller.close();
|
|
1265
1360
|
return;
|
|
1266
1361
|
}
|
|
1267
|
-
if (!reader) reader = value.getReader();
|
|
1362
|
+
if (!reader) reader = guardOperation(state, () => value.getReader());
|
|
1268
1363
|
const {
|
|
1269
1364
|
done,
|
|
1270
1365
|
value: chunk
|
|
1271
|
-
} = await reader.read();
|
|
1272
|
-
done ? controller.close() : controller.enqueue(guardFailures(chunk, state));
|
|
1366
|
+
} = await guardOperation(state, () => reader.read());
|
|
1367
|
+
done ? controller.close() : controller.enqueue(guardOperation(state, () => guardFailures(chunk, state)));
|
|
1273
1368
|
} catch (error) {
|
|
1274
|
-
controller.error(sanitizeServerError(error));
|
|
1369
|
+
controller.error(guardOperation(state, () => sanitizeServerError(error)));
|
|
1275
1370
|
}
|
|
1276
1371
|
},
|
|
1277
1372
|
cancel(reason) {
|
|
1278
1373
|
finished = true;
|
|
1279
|
-
return reader ? reader.cancel(reason) : value.cancel(reason);
|
|
1374
|
+
return guardOperation(state, () => reader ? reader.cancel(reason) : value.cancel(reason));
|
|
1280
1375
|
}
|
|
1281
1376
|
});
|
|
1282
1377
|
if (gate) gate.onOpen(close);
|
|
@@ -1284,9 +1379,10 @@ function enterGuard(value, state) {
|
|
|
1284
1379
|
return guardedStream;
|
|
1285
1380
|
}
|
|
1286
1381
|
if (typeof value.then === "function") {
|
|
1287
|
-
const guardedPromise = Promise.resolve(value).then(resolved => guardFailures(resolved, state), error => {
|
|
1288
|
-
throw sanitizeServerError(error);
|
|
1382
|
+
const guardedPromise = Promise.resolve(value).then(resolved => guardOperation(state, () => guardFailures(resolved, state)), error => {
|
|
1383
|
+
throw guardOperation(state, () => sanitizeServerError(error));
|
|
1289
1384
|
});
|
|
1385
|
+
guardedPromise.catch(() => {});
|
|
1290
1386
|
state.seen.set(value, guardedPromise);
|
|
1291
1387
|
return guardedPromise;
|
|
1292
1388
|
}
|
|
@@ -1295,13 +1391,13 @@ function enterGuard(value, state) {
|
|
|
1295
1391
|
const gate = state.gate;
|
|
1296
1392
|
const guardedIterable = {
|
|
1297
1393
|
[Symbol.asyncIterator]() {
|
|
1298
|
-
const iterator = source[Symbol.asyncIterator]();
|
|
1394
|
+
const iterator = guardOperation(state, () => source[Symbol.asyncIterator]());
|
|
1299
1395
|
let finished = false;
|
|
1300
1396
|
const close = () => {
|
|
1301
1397
|
if (finished) return;
|
|
1302
1398
|
finished = true;
|
|
1303
1399
|
try {
|
|
1304
|
-
const returned = iterator.return && iterator.return();
|
|
1400
|
+
const returned = iterator.return && guardOperation(state, () => iterator.return());
|
|
1305
1401
|
if (returned && typeof returned.then === "function") returned.then(undefined, () => {});
|
|
1306
1402
|
} catch {}
|
|
1307
1403
|
};
|
|
@@ -1309,17 +1405,17 @@ function enterGuard(value, state) {
|
|
|
1309
1405
|
const step = () => finished ? Promise.resolve({
|
|
1310
1406
|
done: true,
|
|
1311
1407
|
value: undefined
|
|
1312
|
-
}) : iterator.next().then(step => {
|
|
1408
|
+
}) : guardOperation(state, () => iterator.next()).then(step => {
|
|
1313
1409
|
if (step.done) {
|
|
1314
1410
|
finished = true;
|
|
1315
1411
|
return step;
|
|
1316
1412
|
}
|
|
1317
1413
|
return {
|
|
1318
1414
|
done: false,
|
|
1319
|
-
value: guardFailures(step.value, state)
|
|
1415
|
+
value: guardOperation(state, () => guardFailures(step.value, state))
|
|
1320
1416
|
};
|
|
1321
1417
|
}, error => {
|
|
1322
|
-
throw sanitizeServerError(error);
|
|
1418
|
+
throw guardOperation(state, () => sanitizeServerError(error));
|
|
1323
1419
|
});
|
|
1324
1420
|
return {
|
|
1325
1421
|
next: () => finished || !gate || gate.wantsMore() ? step() : gate.awaitDemand().then(step),
|
|
@@ -1336,6 +1432,11 @@ function enterGuard(value, state) {
|
|
|
1336
1432
|
state.seen.set(value, guardedIterable);
|
|
1337
1433
|
return guardedIterable;
|
|
1338
1434
|
}
|
|
1435
|
+
if (state.scope && typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
1436
|
+
const scopedIterable = scopeDeferredResult(value, state.scope);
|
|
1437
|
+
state.seen.set(value, scopedIterable);
|
|
1438
|
+
return scopedIterable;
|
|
1439
|
+
}
|
|
1339
1440
|
if (Array.isArray(value)) {
|
|
1340
1441
|
const next = value.slice();
|
|
1341
1442
|
state.seen.set(value, next);
|
|
@@ -1359,16 +1460,20 @@ function enterGuard(value, state) {
|
|
|
1359
1460
|
return value;
|
|
1360
1461
|
}
|
|
1361
1462
|
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
1463
|
+
for (const key of Object.keys(descriptors)) {
|
|
1464
|
+
descriptors[key].configurable = true;
|
|
1465
|
+
if ("value" in descriptors[key]) descriptors[key].writable = true;
|
|
1466
|
+
}
|
|
1362
1467
|
const next = Object.create(prototype, descriptors);
|
|
1363
1468
|
state.seen.set(value, next);
|
|
1364
|
-
return new Frame(OBJECT, value, next, Object.keys(
|
|
1469
|
+
return new Frame(OBJECT, value, next, Object.keys(value), descriptors);
|
|
1365
1470
|
}
|
|
1366
1471
|
function keepGuarded(value, next, changed, state) {
|
|
1367
1472
|
if (changed || state.cyclic.has(value)) return next;
|
|
1368
1473
|
state.seen.set(value, value);
|
|
1369
1474
|
return value;
|
|
1370
1475
|
}
|
|
1371
|
-
function serializeResponseStream(value, codecOptions, signal) {
|
|
1476
|
+
function serializeResponseStream(value, codecOptions, signal, scope) {
|
|
1372
1477
|
let closed = false;
|
|
1373
1478
|
let streamController = null;
|
|
1374
1479
|
let demandWaiters = null;
|
|
@@ -1387,11 +1492,13 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
1387
1492
|
if (closed) close();else sourceClosers.add(close);
|
|
1388
1493
|
}
|
|
1389
1494
|
};
|
|
1390
|
-
|
|
1495
|
+
const guardState = {
|
|
1391
1496
|
seen: new WeakMap(),
|
|
1392
1497
|
cyclic: new WeakSet(),
|
|
1393
|
-
gate
|
|
1394
|
-
|
|
1498
|
+
gate,
|
|
1499
|
+
scope
|
|
1500
|
+
};
|
|
1501
|
+
value = guardOperation(guardState, () => guardFailures(value, guardState));
|
|
1395
1502
|
let cancelSerialize = null;
|
|
1396
1503
|
let onAbort = null;
|
|
1397
1504
|
const finishSource = () => {
|
|
@@ -1472,14 +1579,14 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
1472
1579
|
}
|
|
1473
1580
|
});
|
|
1474
1581
|
}
|
|
1475
|
-
function serializedResponse(value, headers, codec, signal) {
|
|
1582
|
+
function serializedResponse(value, headers, codec, signal, scope) {
|
|
1476
1583
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
1477
1584
|
headers.set("Content-Type", "text/plain");
|
|
1478
|
-
return new Response(serializeResponseStream(value, codec, signal), {
|
|
1585
|
+
return new Response(serializeResponseStream(value, codec, signal, scope), {
|
|
1479
1586
|
headers
|
|
1480
1587
|
});
|
|
1481
1588
|
}
|
|
1482
|
-
function encodeResult(value, headers, status, codec, signal) {
|
|
1589
|
+
function encodeResult(value, headers, status, codec, signal, scope) {
|
|
1483
1590
|
if (NULL_BODY_STATUSES.has(status)) {
|
|
1484
1591
|
if (value === undefined || value === null) {
|
|
1485
1592
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Void);
|
|
@@ -1490,7 +1597,7 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1490
1597
|
}
|
|
1491
1598
|
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.`);
|
|
1492
1599
|
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error.message));
|
|
1493
|
-
return encodeResult(error, headers, 500, codec, signal);
|
|
1600
|
+
return encodeResult(error, headers, 500, codec, signal, scope);
|
|
1494
1601
|
}
|
|
1495
1602
|
const direct = getHeadersAndBody(value);
|
|
1496
1603
|
if (direct) {
|
|
@@ -1510,10 +1617,12 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1510
1617
|
});
|
|
1511
1618
|
}
|
|
1512
1619
|
try {
|
|
1513
|
-
|
|
1620
|
+
const jsonSafe = scope ? scope(() => isJSONSafe(value)) : isJSONSafe(value);
|
|
1621
|
+
if (jsonSafe) {
|
|
1514
1622
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Json);
|
|
1515
1623
|
headers.set("Content-Type", "application/json");
|
|
1516
|
-
|
|
1624
|
+
const body = scope ? scope(() => JSON.stringify(value)) : JSON.stringify(value);
|
|
1625
|
+
return new Response(body, {
|
|
1517
1626
|
status,
|
|
1518
1627
|
headers
|
|
1519
1628
|
});
|
|
@@ -1521,7 +1630,7 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1521
1630
|
} catch {
|
|
1522
1631
|
}
|
|
1523
1632
|
try {
|
|
1524
|
-
const response = serializedResponse(value, headers, codec, signal);
|
|
1633
|
+
const response = serializedResponse(value, headers, codec, signal, scope);
|
|
1525
1634
|
return status === 200 ? response : new Response(response.body, {
|
|
1526
1635
|
status,
|
|
1527
1636
|
headers
|
|
@@ -1619,8 +1728,17 @@ function forbiddenResponse() {
|
|
|
1619
1728
|
}
|
|
1620
1729
|
}));
|
|
1621
1730
|
}
|
|
1731
|
+
function nativePromise(value) {
|
|
1732
|
+
if (value instanceof Promise) return value;
|
|
1733
|
+
try {
|
|
1734
|
+
if (Object.prototype.toString.call(value) === "[object Promise]") return Promise.prototype.then.call(value, value => value);
|
|
1735
|
+
} catch {}
|
|
1736
|
+
}
|
|
1622
1737
|
async function handleServerFunctionRequest(request, options = {}) {
|
|
1623
|
-
const codec =
|
|
1738
|
+
const codec = {
|
|
1739
|
+
...(options.codec !== undefined ? options.codec : getServerFunctionsCodec())
|
|
1740
|
+
};
|
|
1741
|
+
codec.serializeErrorStacks ??= DEV;
|
|
1624
1742
|
const url = new URL(request.url);
|
|
1625
1743
|
const method = request.method;
|
|
1626
1744
|
const address = resolveAddress(url);
|
|
@@ -1679,7 +1797,15 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1679
1797
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1680
1798
|
}
|
|
1681
1799
|
if (!(declared > 0)) {
|
|
1682
|
-
|
|
1800
|
+
let bounded;
|
|
1801
|
+
try {
|
|
1802
|
+
bounded = await bufferBodyWithin(request, bodySizeLimit);
|
|
1803
|
+
} catch {
|
|
1804
|
+
const response = new Response(DEV ? "Malformed server function arguments" : null, {
|
|
1805
|
+
status: 400
|
|
1806
|
+
});
|
|
1807
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1808
|
+
}
|
|
1683
1809
|
if (bounded === null) {
|
|
1684
1810
|
const response = new Response(DEV ? "Server function request body exceeds the configured bodySizeLimit" : null, {
|
|
1685
1811
|
status: 413
|
|
@@ -1689,16 +1815,30 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1689
1815
|
request = bounded;
|
|
1690
1816
|
}
|
|
1691
1817
|
}
|
|
1692
|
-
let event
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1818
|
+
let event;
|
|
1819
|
+
try {
|
|
1820
|
+
event = options.createEvent ? options.createEvent(request) : {
|
|
1821
|
+
request,
|
|
1822
|
+
locals: {}
|
|
1823
|
+
};
|
|
1824
|
+
const promised = nativePromise(event);
|
|
1825
|
+
if (promised) event = await promised;
|
|
1826
|
+
} catch (error) {
|
|
1827
|
+
const safe = sanitizeServerError(error);
|
|
1828
|
+
const message = safe instanceof Error ? safe.message : String(safe);
|
|
1829
|
+
const headers = new Headers();
|
|
1830
|
+
headers.set(ERROR_HEADER, boundedErrorHeaderValue(message));
|
|
1831
|
+
const response = scripted ? encodeResult(safe, headers, 500, codec, request.signal) : new Response(DEV ? message : null, {
|
|
1832
|
+
status: 500
|
|
1833
|
+
});
|
|
1834
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1835
|
+
}
|
|
1697
1836
|
const refuseCommitted = raw => {
|
|
1698
1837
|
const response = commitEventResponse(raw, event);
|
|
1699
1838
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1700
1839
|
};
|
|
1701
1840
|
const provide = options.provideEvent || provideEvent;
|
|
1841
|
+
const scope = run => provide(event, run);
|
|
1702
1842
|
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
1703
1843
|
const transformResult = options.transformResult !== undefined ? options.transformResult : config.transformResult;
|
|
1704
1844
|
const wrapInvocation = options.wrapInvocation !== undefined ? options.wrapInvocation : config.wrapInvocation;
|
|
@@ -1749,7 +1889,8 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1749
1889
|
const headers = new Headers();
|
|
1750
1890
|
const dispatch = async () => {
|
|
1751
1891
|
try {
|
|
1752
|
-
let
|
|
1892
|
+
let invocations = 0;
|
|
1893
|
+
const invokeOnce = async () => {
|
|
1753
1894
|
INVOCATIONS.set(event, {
|
|
1754
1895
|
id: functionId
|
|
1755
1896
|
});
|
|
@@ -1761,7 +1902,16 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1761
1902
|
request,
|
|
1762
1903
|
direct: false
|
|
1763
1904
|
}) : run();
|
|
1905
|
+
};
|
|
1906
|
+
let result = await provide(event, () => {
|
|
1907
|
+
if (++invocations > 1) {
|
|
1908
|
+
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.");
|
|
1909
|
+
}
|
|
1910
|
+
return invokeOnce();
|
|
1764
1911
|
});
|
|
1912
|
+
if (invocations !== 1) {
|
|
1913
|
+
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.");
|
|
1914
|
+
}
|
|
1765
1915
|
if (transformResult) {
|
|
1766
1916
|
result = await transformResult(event, result, flightContext);
|
|
1767
1917
|
}
|
|
@@ -1815,10 +1965,10 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1815
1965
|
if (!scripted) {
|
|
1816
1966
|
if (handleNoJS) return handleNoJS(result ?? metadata, request, parsed);
|
|
1817
1967
|
if (result instanceof Response) return result;
|
|
1818
|
-
return encodeResult(result, headers, status, codec, request.signal);
|
|
1968
|
+
return encodeResult(result, headers, status, codec, request.signal, scope);
|
|
1819
1969
|
}
|
|
1820
1970
|
if (status === 304) warnScripted304(functionId);
|
|
1821
|
-
return encodeResult(result, headers, status, codec, request.signal);
|
|
1971
|
+
return encodeResult(result, headers, status, codec, request.signal, scope);
|
|
1822
1972
|
} catch (x) {
|
|
1823
1973
|
const respondThrown = value => {
|
|
1824
1974
|
const safe = sanitizeServerError(value);
|
|
@@ -1831,7 +1981,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1831
1981
|
}
|
|
1832
1982
|
const error = safe instanceof Error ? safe.message : typeof safe === "string" ? safe : "true";
|
|
1833
1983
|
headers.set(ERROR_HEADER, boundedErrorHeaderValue(error));
|
|
1834
|
-
return encodeResult(safe, headers, 500, codec, request.signal);
|
|
1984
|
+
return encodeResult(safe, headers, 500, codec, request.signal, scope);
|
|
1835
1985
|
};
|
|
1836
1986
|
if (x instanceof Response || isResponseEnvelope(x)) {
|
|
1837
1987
|
if (transformResult) {
|
|
@@ -1895,7 +2045,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1895
2045
|
if (x instanceof Response) return x;
|
|
1896
2046
|
}
|
|
1897
2047
|
if (scripted && status === 304) warnScripted304(functionId);
|
|
1898
|
-
return encodeResult(x, headers, status, codec, request.signal);
|
|
2048
|
+
return encodeResult(x, headers, status, codec, request.signal, scope);
|
|
1899
2049
|
}
|
|
1900
2050
|
return respondThrown(x);
|
|
1901
2051
|
}
|