@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]);
|
|
@@ -534,7 +544,8 @@ function copyInitHeaders(init) {
|
|
|
534
544
|
for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
|
|
535
545
|
return headers;
|
|
536
546
|
}
|
|
537
|
-
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location"
|
|
547
|
+
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location",
|
|
548
|
+
...COMPOSED_BODY_FRAMING].map(header => header.toLowerCase()));
|
|
538
549
|
function fillsStubGap(key, headers, response) {
|
|
539
550
|
if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
|
|
540
551
|
if (response.body === null && (key === "content-type" || key === "content-length")) return false;
|
|
@@ -694,6 +705,52 @@ function provideEvent(event, fn) {
|
|
|
694
705
|
if (ctx) return ctx.run(event, fn);
|
|
695
706
|
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
696
707
|
}
|
|
708
|
+
function scopeDeferredResult(value, scope) {
|
|
709
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
710
|
+
const promised = scope(() => nativePromise(value));
|
|
711
|
+
if (promised) {
|
|
712
|
+
return promised.then(result => scope(() => scopeDeferredResult(result, scope)));
|
|
713
|
+
}
|
|
714
|
+
if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) {
|
|
715
|
+
let reader;
|
|
716
|
+
return new ReadableStream({
|
|
717
|
+
async pull(controller) {
|
|
718
|
+
try {
|
|
719
|
+
const step = await scope(() => {
|
|
720
|
+
if (!reader) reader = value.getReader();
|
|
721
|
+
return reader.read();
|
|
722
|
+
});
|
|
723
|
+
if (step.done) controller.close();else controller.enqueue(step.value);
|
|
724
|
+
} catch (error) {
|
|
725
|
+
controller.error(error);
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
cancel(reason) {
|
|
729
|
+
return scope(() => reader ? reader.cancel(reason) : value.cancel(reason));
|
|
730
|
+
}
|
|
731
|
+
}, {
|
|
732
|
+
highWaterMark: 0
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
const scopedIterator = symbol => ({
|
|
736
|
+
[symbol]() {
|
|
737
|
+
const iterator = scope(() => value[symbol]());
|
|
738
|
+
return new Proxy(iterator, {
|
|
739
|
+
get(target, property) {
|
|
740
|
+
const member = Reflect.get(target, property, target);
|
|
741
|
+
return typeof member === "function" && (property === "next" || property === "return" || property === "throw") ? (...args) => scope(() => member.apply(target, args)) : member;
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
if (typeof value[Symbol.asyncIterator] === "function") {
|
|
747
|
+
return scopedIterator(Symbol.asyncIterator);
|
|
748
|
+
}
|
|
749
|
+
if (typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
750
|
+
return scopedIterator(Symbol.iterator);
|
|
751
|
+
}
|
|
752
|
+
return value;
|
|
753
|
+
}
|
|
697
754
|
const REGISTRATIONS = new Map();
|
|
698
755
|
const METHODS = new Map();
|
|
699
756
|
const INVOCATIONS = new WeakMap();
|
|
@@ -791,7 +848,8 @@ function createServerReference({
|
|
|
791
848
|
id
|
|
792
849
|
});
|
|
793
850
|
evt.serverOnly = true;
|
|
794
|
-
const
|
|
851
|
+
const scope = run => provideEvent(evt, run);
|
|
852
|
+
let result = provideEvent(evt, () => {
|
|
795
853
|
const run = () => fn.apply(thisArg, args);
|
|
796
854
|
return config.wrapInvocation ? config.wrapInvocation(run, {
|
|
797
855
|
id,
|
|
@@ -800,19 +858,20 @@ function createServerReference({
|
|
|
800
858
|
direct: true
|
|
801
859
|
}) : run();
|
|
802
860
|
});
|
|
861
|
+
result = scopeDeferredResult(result, scope);
|
|
803
862
|
const transform = config.transformDirectResult;
|
|
804
863
|
if (transform && result && typeof result.then === "function") {
|
|
805
|
-
return result.then(value => transform(value, {
|
|
864
|
+
return result.then(value => scopeDeferredResult(transform(value, {
|
|
806
865
|
id,
|
|
807
866
|
args,
|
|
808
867
|
event: evt
|
|
809
|
-
}));
|
|
868
|
+
}), scope));
|
|
810
869
|
}
|
|
811
|
-
return transform ? transform(result, {
|
|
870
|
+
return transform ? scopeDeferredResult(transform(result, {
|
|
812
871
|
id,
|
|
813
872
|
args,
|
|
814
873
|
event: evt
|
|
815
|
-
}) : result;
|
|
874
|
+
}), scope) : result;
|
|
816
875
|
}
|
|
817
876
|
});
|
|
818
877
|
return proxy;
|
|
@@ -878,22 +937,58 @@ function assertDecodeDepth(value) {
|
|
|
878
937
|
level = next;
|
|
879
938
|
}
|
|
880
939
|
}
|
|
940
|
+
const UNSAFE_ARGUMENT_KEYS = ["__proto__", "constructor", "prototype"];
|
|
941
|
+
function stripUnsafeArgumentKeys(value) {
|
|
942
|
+
const stack = [value];
|
|
943
|
+
const seen = new Set();
|
|
944
|
+
while (stack.length) {
|
|
945
|
+
const v = stack.pop();
|
|
946
|
+
if (v === null || typeof v !== "object" || seen.has(v)) continue;
|
|
947
|
+
seen.add(v);
|
|
948
|
+
for (const key of UNSAFE_ARGUMENT_KEYS) {
|
|
949
|
+
delete v[key];
|
|
950
|
+
}
|
|
951
|
+
for (const key of Object.keys(v)) stack.push(v[key]);
|
|
952
|
+
if (v instanceof Map) {
|
|
953
|
+
for (const [k, entry] of v) stack.push(k, entry);
|
|
954
|
+
} else if (v instanceof Set) {
|
|
955
|
+
for (const member of v) stack.push(member);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return value;
|
|
959
|
+
}
|
|
881
960
|
async function bufferBodyWithin(request, limit) {
|
|
882
|
-
const reader = request.
|
|
961
|
+
const reader = request.body.getReader();
|
|
962
|
+
const signal = request.signal;
|
|
883
963
|
const chunks = [];
|
|
884
964
|
let total = 0;
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
965
|
+
const onAbort = () => {
|
|
966
|
+
reader.cancel(signal.reason).catch(() => {});
|
|
967
|
+
};
|
|
968
|
+
if (signal.aborted) onAbort();else signal.addEventListener("abort", onAbort, {
|
|
969
|
+
once: true
|
|
970
|
+
});
|
|
971
|
+
try {
|
|
972
|
+
for (;;) {
|
|
973
|
+
const {
|
|
974
|
+
done,
|
|
975
|
+
value
|
|
976
|
+
} = await reader.read();
|
|
977
|
+
if (signal.aborted) throw signal.reason;
|
|
978
|
+
if (done) break;
|
|
979
|
+
total += value.byteLength;
|
|
980
|
+
if (total > limit) {
|
|
981
|
+
reader.cancel().catch(() => {});
|
|
982
|
+
return null;
|
|
983
|
+
}
|
|
984
|
+
chunks.push(value);
|
|
895
985
|
}
|
|
896
|
-
|
|
986
|
+
} catch (error) {
|
|
987
|
+
reader.cancel(error).catch(() => {});
|
|
988
|
+
throw error;
|
|
989
|
+
} finally {
|
|
990
|
+
signal.removeEventListener("abort", onAbort);
|
|
991
|
+
reader.releaseLock();
|
|
897
992
|
}
|
|
898
993
|
const body = new Uint8Array(total);
|
|
899
994
|
let offset = 0;
|
|
@@ -920,6 +1015,7 @@ async function parseArguments(request, url, scripted, codec) {
|
|
|
920
1015
|
if (!Array.isArray(result)) {
|
|
921
1016
|
throw new TypeError("Server function arguments must encode an array");
|
|
922
1017
|
}
|
|
1018
|
+
stripUnsafeArgumentKeys(result);
|
|
923
1019
|
for (const arg of result) {
|
|
924
1020
|
parsed.push(arg);
|
|
925
1021
|
}
|
|
@@ -933,9 +1029,12 @@ async function parseArguments(request, url, scripted, codec) {
|
|
|
933
1029
|
if (!Array.isArray(decoded)) {
|
|
934
1030
|
throw new TypeError("Server function arguments must encode an array");
|
|
935
1031
|
}
|
|
936
|
-
return decoded;
|
|
1032
|
+
return stripUnsafeArgumentKeys(decoded);
|
|
937
1033
|
}
|
|
938
1034
|
if (decoded === undefined) {
|
|
1035
|
+
if (bodyFormat === null && (await request.clone().arrayBuffer()).byteLength === 0) {
|
|
1036
|
+
return parsed;
|
|
1037
|
+
}
|
|
939
1038
|
throw new TypeError("Server function body carries no usable encoding");
|
|
940
1039
|
}
|
|
941
1040
|
parsed.push(decoded);
|
|
@@ -1036,7 +1135,7 @@ function foldSetCookies(headers, setCookies) {
|
|
|
1036
1135
|
}
|
|
1037
1136
|
function mergeResponseHeaders(target, source) {
|
|
1038
1137
|
source.forEach((value, key) => {
|
|
1039
|
-
if (key !== "set-cookie") target.append(key, value);
|
|
1138
|
+
if (key !== "set-cookie" && !COMPOSED_BODY_FRAMING.has(key)) target.append(key, value);
|
|
1040
1139
|
});
|
|
1041
1140
|
if (source.getSetCookie) {
|
|
1042
1141
|
for (const cookie of source.getSetCookie()) target.append("Set-Cookie", cookie);
|
|
@@ -1053,10 +1152,6 @@ function maskRedirect(headers, response, requestUrl) {
|
|
|
1053
1152
|
headers.delete("Location");
|
|
1054
1153
|
}
|
|
1055
1154
|
const BOUNDED_COMPOSED_HEADERS = [REDIRECT_HEADER, "Location", REVALIDATE_HEADER];
|
|
1056
|
-
function refusedTargetScheme(target) {
|
|
1057
|
-
const match = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.exec(target);
|
|
1058
|
-
return match !== null && !/^https?:$/i.test(match[0]);
|
|
1059
|
-
}
|
|
1060
1155
|
function enforceComposedHeaderInvariants(response) {
|
|
1061
1156
|
for (const name of BOUNDED_COMPOSED_HEADERS) {
|
|
1062
1157
|
const value = response.headers.get(name);
|
|
@@ -1066,7 +1161,7 @@ function enforceComposedHeaderInvariants(response) {
|
|
|
1066
1161
|
}
|
|
1067
1162
|
if (name === REVALIDATE_HEADER) continue;
|
|
1068
1163
|
const target = name === REDIRECT_HEADER ? value.slice(value.indexOf(" ") + 1) : value;
|
|
1069
|
-
if (
|
|
1164
|
+
if (!isHttpNavigationTarget(target)) {
|
|
1070
1165
|
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);
|
|
1071
1166
|
}
|
|
1072
1167
|
}
|
|
@@ -1194,14 +1289,11 @@ function guardFailures(value, state) {
|
|
|
1194
1289
|
top.next.add(guarded);
|
|
1195
1290
|
if (guarded !== original) top.changed = true;
|
|
1196
1291
|
} else if (guarded !== original || top.accessorRead === i) {
|
|
1197
|
-
Object.defineProperty(top.next, items[i],
|
|
1198
|
-
|
|
1199
|
-
configurable: true,
|
|
1292
|
+
Object.defineProperty(top.next, items[i], {
|
|
1293
|
+
value: guarded,
|
|
1200
1294
|
writable: true,
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
...top.descriptors[items[i]],
|
|
1204
|
-
value: guarded
|
|
1295
|
+
configurable: true,
|
|
1296
|
+
enumerable: top.descriptors[items[i]].enumerable
|
|
1205
1297
|
});
|
|
1206
1298
|
top.changed = true;
|
|
1207
1299
|
}
|
|
@@ -1236,6 +1328,9 @@ class Frame {
|
|
|
1236
1328
|
this.pendingKey = undefined;
|
|
1237
1329
|
}
|
|
1238
1330
|
}
|
|
1331
|
+
function guardOperation(state, run) {
|
|
1332
|
+
return state.scope ? state.scope(run) : run();
|
|
1333
|
+
}
|
|
1239
1334
|
function enterGuard(value, state) {
|
|
1240
1335
|
if (value === null || typeof value !== "object") return value;
|
|
1241
1336
|
if (state.seen.has(value)) {
|
|
@@ -1250,7 +1345,7 @@ function enterGuard(value, state) {
|
|
|
1250
1345
|
if (finished) return;
|
|
1251
1346
|
finished = true;
|
|
1252
1347
|
try {
|
|
1253
|
-
const cancelled = reader ? reader.cancel() : value.cancel();
|
|
1348
|
+
const cancelled = guardOperation(state, () => reader ? reader.cancel() : value.cancel());
|
|
1254
1349
|
if (cancelled && typeof cancelled.then === "function") cancelled.then(undefined, () => {});
|
|
1255
1350
|
} catch {}
|
|
1256
1351
|
};
|
|
@@ -1262,19 +1357,19 @@ function enterGuard(value, state) {
|
|
|
1262
1357
|
controller.close();
|
|
1263
1358
|
return;
|
|
1264
1359
|
}
|
|
1265
|
-
if (!reader) reader = value.getReader();
|
|
1360
|
+
if (!reader) reader = guardOperation(state, () => value.getReader());
|
|
1266
1361
|
const {
|
|
1267
1362
|
done,
|
|
1268
1363
|
value: chunk
|
|
1269
|
-
} = await reader.read();
|
|
1270
|
-
done ? controller.close() : controller.enqueue(guardFailures(chunk, state));
|
|
1364
|
+
} = await guardOperation(state, () => reader.read());
|
|
1365
|
+
done ? controller.close() : controller.enqueue(guardOperation(state, () => guardFailures(chunk, state)));
|
|
1271
1366
|
} catch (error) {
|
|
1272
|
-
controller.error(sanitizeServerError(error));
|
|
1367
|
+
controller.error(guardOperation(state, () => sanitizeServerError(error)));
|
|
1273
1368
|
}
|
|
1274
1369
|
},
|
|
1275
1370
|
cancel(reason) {
|
|
1276
1371
|
finished = true;
|
|
1277
|
-
return reader ? reader.cancel(reason) : value.cancel(reason);
|
|
1372
|
+
return guardOperation(state, () => reader ? reader.cancel(reason) : value.cancel(reason));
|
|
1278
1373
|
}
|
|
1279
1374
|
});
|
|
1280
1375
|
if (gate) gate.onOpen(close);
|
|
@@ -1282,9 +1377,10 @@ function enterGuard(value, state) {
|
|
|
1282
1377
|
return guardedStream;
|
|
1283
1378
|
}
|
|
1284
1379
|
if (typeof value.then === "function") {
|
|
1285
|
-
const guardedPromise = Promise.resolve(value).then(resolved => guardFailures(resolved, state), error => {
|
|
1286
|
-
throw sanitizeServerError(error);
|
|
1380
|
+
const guardedPromise = Promise.resolve(value).then(resolved => guardOperation(state, () => guardFailures(resolved, state)), error => {
|
|
1381
|
+
throw guardOperation(state, () => sanitizeServerError(error));
|
|
1287
1382
|
});
|
|
1383
|
+
guardedPromise.catch(() => {});
|
|
1288
1384
|
state.seen.set(value, guardedPromise);
|
|
1289
1385
|
return guardedPromise;
|
|
1290
1386
|
}
|
|
@@ -1293,13 +1389,13 @@ function enterGuard(value, state) {
|
|
|
1293
1389
|
const gate = state.gate;
|
|
1294
1390
|
const guardedIterable = {
|
|
1295
1391
|
[Symbol.asyncIterator]() {
|
|
1296
|
-
const iterator = source[Symbol.asyncIterator]();
|
|
1392
|
+
const iterator = guardOperation(state, () => source[Symbol.asyncIterator]());
|
|
1297
1393
|
let finished = false;
|
|
1298
1394
|
const close = () => {
|
|
1299
1395
|
if (finished) return;
|
|
1300
1396
|
finished = true;
|
|
1301
1397
|
try {
|
|
1302
|
-
const returned = iterator.return && iterator.return();
|
|
1398
|
+
const returned = iterator.return && guardOperation(state, () => iterator.return());
|
|
1303
1399
|
if (returned && typeof returned.then === "function") returned.then(undefined, () => {});
|
|
1304
1400
|
} catch {}
|
|
1305
1401
|
};
|
|
@@ -1307,17 +1403,17 @@ function enterGuard(value, state) {
|
|
|
1307
1403
|
const step = () => finished ? Promise.resolve({
|
|
1308
1404
|
done: true,
|
|
1309
1405
|
value: undefined
|
|
1310
|
-
}) : iterator.next().then(step => {
|
|
1406
|
+
}) : guardOperation(state, () => iterator.next()).then(step => {
|
|
1311
1407
|
if (step.done) {
|
|
1312
1408
|
finished = true;
|
|
1313
1409
|
return step;
|
|
1314
1410
|
}
|
|
1315
1411
|
return {
|
|
1316
1412
|
done: false,
|
|
1317
|
-
value: guardFailures(step.value, state)
|
|
1413
|
+
value: guardOperation(state, () => guardFailures(step.value, state))
|
|
1318
1414
|
};
|
|
1319
1415
|
}, error => {
|
|
1320
|
-
throw sanitizeServerError(error);
|
|
1416
|
+
throw guardOperation(state, () => sanitizeServerError(error));
|
|
1321
1417
|
});
|
|
1322
1418
|
return {
|
|
1323
1419
|
next: () => finished || !gate || gate.wantsMore() ? step() : gate.awaitDemand().then(step),
|
|
@@ -1334,6 +1430,11 @@ function enterGuard(value, state) {
|
|
|
1334
1430
|
state.seen.set(value, guardedIterable);
|
|
1335
1431
|
return guardedIterable;
|
|
1336
1432
|
}
|
|
1433
|
+
if (state.scope && typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
1434
|
+
const scopedIterable = scopeDeferredResult(value, state.scope);
|
|
1435
|
+
state.seen.set(value, scopedIterable);
|
|
1436
|
+
return scopedIterable;
|
|
1437
|
+
}
|
|
1337
1438
|
if (Array.isArray(value)) {
|
|
1338
1439
|
const next = value.slice();
|
|
1339
1440
|
state.seen.set(value, next);
|
|
@@ -1357,16 +1458,20 @@ function enterGuard(value, state) {
|
|
|
1357
1458
|
return value;
|
|
1358
1459
|
}
|
|
1359
1460
|
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
1461
|
+
for (const key of Object.keys(descriptors)) {
|
|
1462
|
+
descriptors[key].configurable = true;
|
|
1463
|
+
if ("value" in descriptors[key]) descriptors[key].writable = true;
|
|
1464
|
+
}
|
|
1360
1465
|
const next = Object.create(prototype, descriptors);
|
|
1361
1466
|
state.seen.set(value, next);
|
|
1362
|
-
return new Frame(OBJECT, value, next, Object.keys(
|
|
1467
|
+
return new Frame(OBJECT, value, next, Object.keys(value), descriptors);
|
|
1363
1468
|
}
|
|
1364
1469
|
function keepGuarded(value, next, changed, state) {
|
|
1365
1470
|
if (changed || state.cyclic.has(value)) return next;
|
|
1366
1471
|
state.seen.set(value, value);
|
|
1367
1472
|
return value;
|
|
1368
1473
|
}
|
|
1369
|
-
function serializeResponseStream(value, codecOptions, signal) {
|
|
1474
|
+
function serializeResponseStream(value, codecOptions, signal, scope) {
|
|
1370
1475
|
let closed = false;
|
|
1371
1476
|
let streamController = null;
|
|
1372
1477
|
let demandWaiters = null;
|
|
@@ -1385,11 +1490,13 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
1385
1490
|
if (closed) close();else sourceClosers.add(close);
|
|
1386
1491
|
}
|
|
1387
1492
|
};
|
|
1388
|
-
|
|
1493
|
+
const guardState = {
|
|
1389
1494
|
seen: new WeakMap(),
|
|
1390
1495
|
cyclic: new WeakSet(),
|
|
1391
|
-
gate
|
|
1392
|
-
|
|
1496
|
+
gate,
|
|
1497
|
+
scope
|
|
1498
|
+
};
|
|
1499
|
+
value = guardOperation(guardState, () => guardFailures(value, guardState));
|
|
1393
1500
|
let cancelSerialize = null;
|
|
1394
1501
|
let onAbort = null;
|
|
1395
1502
|
const finishSource = () => {
|
|
@@ -1470,14 +1577,14 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
1470
1577
|
}
|
|
1471
1578
|
});
|
|
1472
1579
|
}
|
|
1473
|
-
function serializedResponse(value, headers, codec, signal) {
|
|
1580
|
+
function serializedResponse(value, headers, codec, signal, scope) {
|
|
1474
1581
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
1475
1582
|
headers.set("Content-Type", "text/plain");
|
|
1476
|
-
return new Response(serializeResponseStream(value, codec, signal), {
|
|
1583
|
+
return new Response(serializeResponseStream(value, codec, signal, scope), {
|
|
1477
1584
|
headers
|
|
1478
1585
|
});
|
|
1479
1586
|
}
|
|
1480
|
-
function encodeResult(value, headers, status, codec, signal) {
|
|
1587
|
+
function encodeResult(value, headers, status, codec, signal, scope) {
|
|
1481
1588
|
if (NULL_BODY_STATUSES.has(status)) {
|
|
1482
1589
|
if (value === undefined || value === null) {
|
|
1483
1590
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Void);
|
|
@@ -1488,7 +1595,7 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1488
1595
|
}
|
|
1489
1596
|
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.`);
|
|
1490
1597
|
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error.message));
|
|
1491
|
-
return encodeResult(error, headers, 500, codec, signal);
|
|
1598
|
+
return encodeResult(error, headers, 500, codec, signal, scope);
|
|
1492
1599
|
}
|
|
1493
1600
|
const direct = getHeadersAndBody(value);
|
|
1494
1601
|
if (direct) {
|
|
@@ -1508,10 +1615,12 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1508
1615
|
});
|
|
1509
1616
|
}
|
|
1510
1617
|
try {
|
|
1511
|
-
|
|
1618
|
+
const jsonSafe = scope ? scope(() => isJSONSafe(value)) : isJSONSafe(value);
|
|
1619
|
+
if (jsonSafe) {
|
|
1512
1620
|
headers.set(BODY_FORMAT_HEADER, BodyFormat.Json);
|
|
1513
1621
|
headers.set("Content-Type", "application/json");
|
|
1514
|
-
|
|
1622
|
+
const body = scope ? scope(() => JSON.stringify(value)) : JSON.stringify(value);
|
|
1623
|
+
return new Response(body, {
|
|
1515
1624
|
status,
|
|
1516
1625
|
headers
|
|
1517
1626
|
});
|
|
@@ -1519,7 +1628,7 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1519
1628
|
} catch {
|
|
1520
1629
|
}
|
|
1521
1630
|
try {
|
|
1522
|
-
const response = serializedResponse(value, headers, codec, signal);
|
|
1631
|
+
const response = serializedResponse(value, headers, codec, signal, scope);
|
|
1523
1632
|
return status === 200 ? response : new Response(response.body, {
|
|
1524
1633
|
status,
|
|
1525
1634
|
headers
|
|
@@ -1617,8 +1726,17 @@ function forbiddenResponse() {
|
|
|
1617
1726
|
}
|
|
1618
1727
|
}));
|
|
1619
1728
|
}
|
|
1729
|
+
function nativePromise(value) {
|
|
1730
|
+
if (value instanceof Promise) return value;
|
|
1731
|
+
try {
|
|
1732
|
+
if (Object.prototype.toString.call(value) === "[object Promise]") return Promise.prototype.then.call(value, value => value);
|
|
1733
|
+
} catch {}
|
|
1734
|
+
}
|
|
1620
1735
|
async function handleServerFunctionRequest(request, options = {}) {
|
|
1621
|
-
const codec =
|
|
1736
|
+
const codec = {
|
|
1737
|
+
...(options.codec !== undefined ? options.codec : getServerFunctionsCodec())
|
|
1738
|
+
};
|
|
1739
|
+
codec.serializeErrorStacks ??= DEV;
|
|
1622
1740
|
const url = new URL(request.url);
|
|
1623
1741
|
const method = request.method;
|
|
1624
1742
|
const address = resolveAddress(url);
|
|
@@ -1677,7 +1795,15 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1677
1795
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1678
1796
|
}
|
|
1679
1797
|
if (!(declared > 0)) {
|
|
1680
|
-
|
|
1798
|
+
let bounded;
|
|
1799
|
+
try {
|
|
1800
|
+
bounded = await bufferBodyWithin(request, bodySizeLimit);
|
|
1801
|
+
} catch {
|
|
1802
|
+
const response = new Response(DEV ? "Malformed server function arguments" : null, {
|
|
1803
|
+
status: 400
|
|
1804
|
+
});
|
|
1805
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1806
|
+
}
|
|
1681
1807
|
if (bounded === null) {
|
|
1682
1808
|
const response = new Response(DEV ? "Server function request body exceeds the configured bodySizeLimit" : null, {
|
|
1683
1809
|
status: 413
|
|
@@ -1687,16 +1813,30 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1687
1813
|
request = bounded;
|
|
1688
1814
|
}
|
|
1689
1815
|
}
|
|
1690
|
-
let event
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1816
|
+
let event;
|
|
1817
|
+
try {
|
|
1818
|
+
event = options.createEvent ? options.createEvent(request) : {
|
|
1819
|
+
request,
|
|
1820
|
+
locals: {}
|
|
1821
|
+
};
|
|
1822
|
+
const promised = nativePromise(event);
|
|
1823
|
+
if (promised) event = await promised;
|
|
1824
|
+
} catch (error) {
|
|
1825
|
+
const safe = sanitizeServerError(error);
|
|
1826
|
+
const message = safe instanceof Error ? safe.message : String(safe);
|
|
1827
|
+
const headers = new Headers();
|
|
1828
|
+
headers.set(ERROR_HEADER, boundedErrorHeaderValue(message));
|
|
1829
|
+
const response = scripted ? encodeResult(safe, headers, 500, codec, request.signal) : new Response(DEV ? message : null, {
|
|
1830
|
+
status: 500
|
|
1831
|
+
});
|
|
1832
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1833
|
+
}
|
|
1695
1834
|
const refuseCommitted = raw => {
|
|
1696
1835
|
const response = commitEventResponse(raw, event);
|
|
1697
1836
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1698
1837
|
};
|
|
1699
1838
|
const provide = options.provideEvent || provideEvent;
|
|
1839
|
+
const scope = run => provide(event, run);
|
|
1700
1840
|
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
1701
1841
|
const transformResult = options.transformResult !== undefined ? options.transformResult : config.transformResult;
|
|
1702
1842
|
const wrapInvocation = options.wrapInvocation !== undefined ? options.wrapInvocation : config.wrapInvocation;
|
|
@@ -1747,7 +1887,8 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1747
1887
|
const headers = new Headers();
|
|
1748
1888
|
const dispatch = async () => {
|
|
1749
1889
|
try {
|
|
1750
|
-
let
|
|
1890
|
+
let invocations = 0;
|
|
1891
|
+
const invokeOnce = async () => {
|
|
1751
1892
|
INVOCATIONS.set(event, {
|
|
1752
1893
|
id: functionId
|
|
1753
1894
|
});
|
|
@@ -1759,7 +1900,16 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1759
1900
|
request,
|
|
1760
1901
|
direct: false
|
|
1761
1902
|
}) : run();
|
|
1903
|
+
};
|
|
1904
|
+
let result = await provide(event, () => {
|
|
1905
|
+
if (++invocations > 1) {
|
|
1906
|
+
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.");
|
|
1907
|
+
}
|
|
1908
|
+
return invokeOnce();
|
|
1762
1909
|
});
|
|
1910
|
+
if (invocations !== 1) {
|
|
1911
|
+
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.");
|
|
1912
|
+
}
|
|
1763
1913
|
if (transformResult) {
|
|
1764
1914
|
result = await transformResult(event, result, flightContext);
|
|
1765
1915
|
}
|
|
@@ -1813,10 +1963,10 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1813
1963
|
if (!scripted) {
|
|
1814
1964
|
if (handleNoJS) return handleNoJS(result ?? metadata, request, parsed);
|
|
1815
1965
|
if (result instanceof Response) return result;
|
|
1816
|
-
return encodeResult(result, headers, status, codec, request.signal);
|
|
1966
|
+
return encodeResult(result, headers, status, codec, request.signal, scope);
|
|
1817
1967
|
}
|
|
1818
1968
|
if (status === 304) warnScripted304(functionId);
|
|
1819
|
-
return encodeResult(result, headers, status, codec, request.signal);
|
|
1969
|
+
return encodeResult(result, headers, status, codec, request.signal, scope);
|
|
1820
1970
|
} catch (x) {
|
|
1821
1971
|
const respondThrown = value => {
|
|
1822
1972
|
const safe = sanitizeServerError(value);
|
|
@@ -1829,7 +1979,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1829
1979
|
}
|
|
1830
1980
|
const error = safe instanceof Error ? safe.message : typeof safe === "string" ? safe : "true";
|
|
1831
1981
|
headers.set(ERROR_HEADER, boundedErrorHeaderValue(error));
|
|
1832
|
-
return encodeResult(safe, headers, 500, codec, request.signal);
|
|
1982
|
+
return encodeResult(safe, headers, 500, codec, request.signal, scope);
|
|
1833
1983
|
};
|
|
1834
1984
|
if (x instanceof Response || isResponseEnvelope(x)) {
|
|
1835
1985
|
if (transformResult) {
|
|
@@ -1893,7 +2043,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1893
2043
|
if (x instanceof Response) return x;
|
|
1894
2044
|
}
|
|
1895
2045
|
if (scripted && status === 304) warnScripted304(functionId);
|
|
1896
|
-
return encodeResult(x, headers, status, codec, request.signal);
|
|
2046
|
+
return encodeResult(x, headers, status, codec, request.signal, scope);
|
|
1897
2047
|
}
|
|
1898
2048
|
return respondThrown(x);
|
|
1899
2049
|
}
|
package/types/client.d.ts
CHANGED
|
@@ -136,7 +136,7 @@ export declare function claimElement<T extends Element>(node: T): T;
|
|
|
136
136
|
export declare function setAttribute(node: Element, name: string, value: string): void;
|
|
137
137
|
export declare function setAttributeNS(node: Element, namespace: string, name: string, value: string): void;
|
|
138
138
|
export declare function className(node: Element, value: JSX.ClassValue, prev?: JSX.ClassValue): void;
|
|
139
|
-
export declare function addEvent(node: Element, name: string, handler: EventListener | EventListenerObject | (EventListenerObject & AddEventListenerOptions), delegate: boolean): void;
|
|
139
|
+
export declare function addEvent(node: Element, name: string, handler: EventListener | EventListenerObject | (EventListenerObject & AddEventListenerOptions), delegate: boolean): EventListener | EventListenerObject | void;
|
|
140
140
|
export declare function style(node: Element, value: {
|
|
141
141
|
[k: string]: string;
|
|
142
142
|
}, prev?: {
|
|
@@ -149,6 +149,7 @@ export declare function applyRef<T extends Element = Element>(r: ((element: NoIn
|
|
|
149
149
|
export declare function ref(fn: () => ((element: Element) => void) | ((element: Element) => void)[], element: Element): void;
|
|
150
150
|
/** Compiler-emitted primitive; not for hand-written code. @internal */
|
|
151
151
|
export declare function scope<T extends () => any>(fn: T): T;
|
|
152
|
+
export declare function getInsertionParent(): Node | undefined;
|
|
152
153
|
export declare function installHydrationRuntime(): void;
|
|
153
154
|
/**
|
|
154
155
|
* Compiler-emitted primitive; not for hand-written code.
|
package/types/constants.d.ts
CHANGED
|
@@ -15,4 +15,6 @@ declare const Namespaces: Record<string, string>;
|
|
|
15
15
|
declare const VoidElements: Set<string>;
|
|
16
16
|
declare const RawTextElements: Set<string>;
|
|
17
17
|
declare const DOMElements: Set<string>;
|
|
18
|
-
|
|
18
|
+
declare const COMPOSED_BODY_FRAMING: ReadonlySet<string>;
|
|
19
|
+
declare function isHttpNavigationTarget(target: string): boolean;
|
|
20
|
+
export { DOMWithState, ChildProperties, DelegatedEvents, SVGElements, MathMLElements, VoidElements, RawTextElements, Namespaces, DOMElements, $$SLOT, $$HOST, COMPOSED_BODY_FRAMING, isHttpNavigationTarget };
|