@solidjs/web 2.0.0-beta.32 → 2.0.0-beta.33
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 +51 -15
- package/dist/dev.js +47 -16
- package/dist/server.cjs +710 -71
- package/dist/server.js +707 -74
- package/dist/web.cjs +51 -15
- package/dist/web.js +47 -16
- package/frames/dist/client.cjs +181 -64
- package/frames/dist/client.dev.cjs +185 -64
- package/frames/dist/client.dev.js +183 -62
- package/frames/dist/client.js +179 -62
- package/frames/dist/server.cjs +969 -133
- package/frames/dist/server.js +971 -135
- package/package.json +17 -6
- package/serialization/decode/package.json +20 -0
- package/serialization/dist/decode.cjs +110 -0
- package/serialization/dist/decode.js +104 -0
- package/serialization/dist/serialization.cjs +98 -43
- package/serialization/dist/serialization.js +99 -44
- package/serialization/types/index.d.ts +18 -160
- package/serialization/types/serializer-decode.d.ts +182 -0
- package/serialization/types-cjs/index.d.cts +18 -160
- package/serialization/types-cjs/serializer-decode.d.cts +182 -0
- package/server-functions/dist/client.cjs +101 -105
- package/server-functions/dist/client.js +101 -105
- package/server-functions/dist/server.cjs +131 -107
- package/server-functions/dist/server.dev.cjs +131 -107
- package/server-functions/dist/server.dev.js +132 -108
- package/server-functions/dist/server.js +132 -108
- package/types/client.d.ts +23 -1
- package/types/cookies.d.ts +93 -0
- package/types/core.d.ts +1 -1
- package/types/frames/frame-client.d.ts +26 -0
- package/types/frames/frame-transport.d.ts +1 -1
- package/types/frames/serializer.d.ts +18 -160
- package/types/serializer-decode.d.ts +182 -0
- package/types/serializer.d.ts +18 -160
- package/types/server-functions/client.d.ts +1 -1
- package/types/server-functions/server.d.ts +1 -1
- package/types/server-functions/shared.d.ts +57 -1
- package/types/server.d.ts +21 -1
- package/types-cjs/client.d.cts +23 -1
- package/types-cjs/cookies.d.cts +93 -0
- package/types-cjs/core.d.cts +1 -1
- package/types-cjs/frames/frame-client.d.cts +26 -0
- package/types-cjs/frames/frame-transport.d.cts +1 -1
- package/types-cjs/frames/serializer.d.cts +18 -160
- package/types-cjs/serializer-decode.d.cts +182 -0
- package/types-cjs/serializer.d.cts +18 -160
- package/types-cjs/server-functions/client.d.cts +1 -1
- package/types-cjs/server-functions/server.d.cts +1 -1
- package/types-cjs/server-functions/shared.d.cts +57 -1
- package/types-cjs/server.d.cts +21 -1
|
@@ -1,53 +1,33 @@
|
|
|
1
|
-
import { fromCrossJSON, Feature, toCrossJSONStream } from 'seroval';
|
|
2
|
-
import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
|
|
3
|
-
|
|
4
1
|
const REVALIDATE_HEADER = "X-Revalidate";
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin]);
|
|
11
|
-
function resolveSerializerPlugins(customPlugins) {
|
|
12
|
-
return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
|
|
13
|
-
}
|
|
14
|
-
const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
|
|
15
|
-
const JSON_CODEC_DEPTH_LIMIT = 64;
|
|
16
|
-
function resolveCodecOptions({
|
|
17
|
-
plugins,
|
|
18
|
-
disabledFeatures,
|
|
19
|
-
depthLimit
|
|
20
|
-
} = {}) {
|
|
21
|
-
return {
|
|
22
|
-
plugins: resolveSerializerPlugins(plugins),
|
|
23
|
-
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
24
|
-
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
25
|
-
};
|
|
3
|
+
const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
|
|
4
|
+
function getServerFunctionMetadata(fn) {
|
|
5
|
+
if (typeof fn !== "function") return undefined;
|
|
6
|
+
return fn[SERVER_FUNCTION_METADATA] || undefined;
|
|
26
7
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
onDone,
|
|
30
|
-
onError,
|
|
31
|
-
...codecOptions
|
|
32
|
-
}) {
|
|
33
|
-
const resolved = resolveCodecOptions(codecOptions);
|
|
34
|
-
return toCrossJSONStream(value, {
|
|
35
|
-
onParse,
|
|
36
|
-
onDone,
|
|
37
|
-
onError,
|
|
38
|
-
...resolved,
|
|
39
|
-
disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
|
|
40
|
-
});
|
|
8
|
+
function isServerFunction(fn) {
|
|
9
|
+
return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
|
|
41
10
|
}
|
|
42
|
-
function
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
11
|
+
function withMeta(fn, meta) {
|
|
12
|
+
const metadata = getServerFunctionMetadata(fn);
|
|
13
|
+
if (!metadata) {
|
|
14
|
+
throw new Error("withMeta expects a server function reference");
|
|
15
|
+
}
|
|
16
|
+
Object.assign(metadata, meta);
|
|
17
|
+
return fn;
|
|
18
|
+
}
|
|
19
|
+
const SERVER_FUNCTION_RPC = Symbol.for("solid.ServerFunctionRPC");
|
|
20
|
+
function provideServerFunctionRPC(rpc) {
|
|
21
|
+
globalThis[SERVER_FUNCTION_RPC] || (globalThis[SERVER_FUNCTION_RPC] = rpc);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const FLASH_COOKIE = "flash";
|
|
25
|
+
const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
|
|
26
|
+
function hasFlashCookie(cookieHeader) {
|
|
27
|
+
return !!cookieHeader && FLASH_MATCHER.test(cookieHeader);
|
|
28
|
+
}
|
|
29
|
+
function clearFlashCookie() {
|
|
30
|
+
return `${FLASH_COOKIE}=; Max-Age=0; Path=/`;
|
|
51
31
|
}
|
|
52
32
|
|
|
53
33
|
const codecConfig = {
|
|
@@ -115,22 +95,6 @@ function stableString(value, seen) {
|
|
|
115
95
|
}
|
|
116
96
|
return out + "}";
|
|
117
97
|
}
|
|
118
|
-
const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
|
|
119
|
-
function getServerFunctionMetadata(fn) {
|
|
120
|
-
if (typeof fn !== "function") return undefined;
|
|
121
|
-
return fn[SERVER_FUNCTION_METADATA] || undefined;
|
|
122
|
-
}
|
|
123
|
-
function isServerFunction(fn) {
|
|
124
|
-
return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
|
|
125
|
-
}
|
|
126
|
-
function withMeta(fn, meta) {
|
|
127
|
-
const metadata = getServerFunctionMetadata(fn);
|
|
128
|
-
if (!metadata) {
|
|
129
|
-
throw new Error("withMeta expects a server function reference");
|
|
130
|
-
}
|
|
131
|
-
Object.assign(metadata, meta);
|
|
132
|
-
return fn;
|
|
133
|
-
}
|
|
134
98
|
const FUNCTION_HEADER = "X-Server-Function-Id";
|
|
135
99
|
const ERROR_HEADER = "X-Server-Function-Error";
|
|
136
100
|
const ERROR_HEADER_MARKER = "=?1?";
|
|
@@ -161,14 +125,6 @@ const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
|
161
125
|
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
162
126
|
const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
|
|
163
127
|
const FILE_FORM_KEY = "__server_function_file__";
|
|
164
|
-
const FLASH_COOKIE = "flash";
|
|
165
|
-
const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
|
|
166
|
-
function hasFlashCookie(cookieHeader) {
|
|
167
|
-
return !!cookieHeader && FLASH_MATCHER.test(cookieHeader);
|
|
168
|
-
}
|
|
169
|
-
function clearFlashCookie() {
|
|
170
|
-
return `${FLASH_COOKIE}=; Max-Age=0; Path=/`;
|
|
171
|
-
}
|
|
172
128
|
const BodyFormat = {
|
|
173
129
|
Serialized: "0",
|
|
174
130
|
String: "1",
|
|
@@ -180,6 +136,38 @@ const BodyFormat = {
|
|
|
180
136
|
Uint8Array: "7",
|
|
181
137
|
Json: "8"
|
|
182
138
|
};
|
|
139
|
+
const JSON_SAFE_DEPTH_LIMIT = 10000;
|
|
140
|
+
const EXIT = {};
|
|
141
|
+
function isJSONSafe(value) {
|
|
142
|
+
const stack = [value];
|
|
143
|
+
const ancestors = new Set();
|
|
144
|
+
while (stack.length) {
|
|
145
|
+
const v = stack.pop();
|
|
146
|
+
if (v === EXIT) {
|
|
147
|
+
ancestors.delete(stack.pop());
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (v === null) continue;
|
|
151
|
+
const t = typeof v;
|
|
152
|
+
if (t === "string" || t === "boolean") continue;
|
|
153
|
+
if (t === "number") {
|
|
154
|
+
if (!Number.isFinite(v)) return false;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (t !== "object") return false;
|
|
158
|
+
if (ancestors.has(v) || ancestors.size >= JSON_SAFE_DEPTH_LIMIT) return false;
|
|
159
|
+
ancestors.add(v);
|
|
160
|
+
stack.push(v, EXIT);
|
|
161
|
+
if (Array.isArray(v)) {
|
|
162
|
+
for (let i = 0; i < v.length; i++) stack.push(v[i]);
|
|
163
|
+
} else {
|
|
164
|
+
const proto = Object.getPrototypeOf(v);
|
|
165
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
166
|
+
for (const k in v) stack.push(v[k]);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
183
171
|
function getHeadersAndBody(body) {
|
|
184
172
|
switch (true) {
|
|
185
173
|
case typeof body === "string":
|
|
@@ -339,7 +327,10 @@ class ChunkReader {
|
|
|
339
327
|
}
|
|
340
328
|
function serializeStream(value, codecOptions) {
|
|
341
329
|
return new ReadableStream({
|
|
342
|
-
start(controller) {
|
|
330
|
+
async start(controller) {
|
|
331
|
+
const {
|
|
332
|
+
serializeJSON
|
|
333
|
+
} = await import('@solidjs/web/serialization');
|
|
343
334
|
serializeJSON(value, {
|
|
344
335
|
...codecOptions,
|
|
345
336
|
onParse(node) {
|
|
@@ -366,6 +357,9 @@ async function deserializeStream(source, codecOptions) {
|
|
|
366
357
|
const reader = new ChunkReader(source.body);
|
|
367
358
|
const result = await reader.next();
|
|
368
359
|
if (!result.done) {
|
|
360
|
+
const {
|
|
361
|
+
createJSONDeserializer
|
|
362
|
+
} = await import('@solidjs/web/serialization/decode');
|
|
369
363
|
const deserializeChunk = createJSONDeserializer(codecOptions);
|
|
370
364
|
function interpretChunk(chunk) {
|
|
371
365
|
return deserializeChunk(JSON.parse(chunk));
|
|
@@ -398,21 +392,6 @@ const config = {
|
|
|
398
392
|
responseHandler: undefined,
|
|
399
393
|
serializeArgs: undefined
|
|
400
394
|
};
|
|
401
|
-
function isJSONSafe(value) {
|
|
402
|
-
if (value === null) return true;
|
|
403
|
-
const t = typeof value;
|
|
404
|
-
if (t === "string" || t === "boolean") return true;
|
|
405
|
-
if (t === "number") return Number.isFinite(value);
|
|
406
|
-
if (t !== "object") return false;
|
|
407
|
-
if (Array.isArray(value)) {
|
|
408
|
-
for (const v of value) if (!isJSONSafe(v)) return false;
|
|
409
|
-
return true;
|
|
410
|
-
}
|
|
411
|
-
const proto = Object.getPrototypeOf(value);
|
|
412
|
-
if (proto !== Object.prototype && proto !== null) return false;
|
|
413
|
-
for (const k in value) if (!isJSONSafe(value[k])) return false;
|
|
414
|
-
return true;
|
|
415
|
-
}
|
|
416
395
|
function serializeArguments(args) {
|
|
417
396
|
if (!config.serializeArgs) {
|
|
418
397
|
throw new Error("Server function arguments are sent as JSON by default and these " + "arguments are not JSON-serializable. Call enableRichArguments() " + '(from "@solidjs/web/server-functions/rich-args") once at startup ' + "to send Dates, Maps, Sets, typed arrays, etc. through the codec — " + "or pass a single Blob/FormData/File argument, which has a native " + "HTTP encoding.");
|
|
@@ -433,6 +412,15 @@ function configureServerFunctionsClient({
|
|
|
433
412
|
if (serializeArgs !== undefined) config.serializeArgs = serializeArgs;
|
|
434
413
|
}
|
|
435
414
|
let INSTANCE = 0;
|
|
415
|
+
let rpcProvided = false;
|
|
416
|
+
function provideRPC() {
|
|
417
|
+
if (rpcProvided) return;
|
|
418
|
+
rpcProvided = true;
|
|
419
|
+
provideServerFunctionRPC({
|
|
420
|
+
GET,
|
|
421
|
+
decodeResponse
|
|
422
|
+
});
|
|
423
|
+
}
|
|
436
424
|
async function createRequest(base, id, instance, options, meta) {
|
|
437
425
|
const headers = {
|
|
438
426
|
...options.headers,
|
|
@@ -472,31 +460,37 @@ async function initializeResponse(base, id, instance, options, args, meta) {
|
|
|
472
460
|
}, meta);
|
|
473
461
|
}
|
|
474
462
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
body: JSON.stringify(args),
|
|
479
|
-
headers: {
|
|
480
|
-
...options.headers,
|
|
481
|
-
"Content-Type": "application/json",
|
|
482
|
-
[BODY_FORMAT_HEADER]: BodyFormat.Json
|
|
483
|
-
}
|
|
484
|
-
}, meta);
|
|
485
|
-
}
|
|
486
|
-
if (args.length > 1) {
|
|
487
|
-
const trailing = getHeadersAndBody(args[args.length - 1]);
|
|
488
|
-
const leading = args.slice(0, -1).map(arg => arg === undefined ? null : arg);
|
|
489
|
-
if (trailing && isJSONSafe(leading)) {
|
|
490
|
-
const target = base + (base.includes("?") ? "&" : "?") + "args=" + encodeURIComponent(JSON.stringify(leading));
|
|
491
|
-
return createRequest(target, id, instance, {
|
|
463
|
+
try {
|
|
464
|
+
if (isJSONSafe(args)) {
|
|
465
|
+
return createRequest(base, id, instance, {
|
|
492
466
|
...options,
|
|
493
|
-
body:
|
|
467
|
+
body: JSON.stringify(args),
|
|
494
468
|
headers: {
|
|
495
469
|
...options.headers,
|
|
496
|
-
|
|
470
|
+
"Content-Type": "application/json",
|
|
471
|
+
[BODY_FORMAT_HEADER]: BodyFormat.Json
|
|
497
472
|
}
|
|
498
473
|
}, meta);
|
|
499
474
|
}
|
|
475
|
+
} catch {
|
|
476
|
+
}
|
|
477
|
+
if (args.length > 1) {
|
|
478
|
+
try {
|
|
479
|
+
const trailing = getHeadersAndBody(args[args.length - 1]);
|
|
480
|
+
const leading = args.slice(0, -1).map(arg => arg === undefined ? null : arg);
|
|
481
|
+
if (trailing && isJSONSafe(leading)) {
|
|
482
|
+
const target = base + (base.includes("?") ? "&" : "?") + "args=" + encodeURIComponent(JSON.stringify(leading));
|
|
483
|
+
return createRequest(target, id, instance, {
|
|
484
|
+
...options,
|
|
485
|
+
body: trailing.body,
|
|
486
|
+
headers: {
|
|
487
|
+
...options.headers,
|
|
488
|
+
...trailing.headers
|
|
489
|
+
}
|
|
490
|
+
}, meta);
|
|
491
|
+
}
|
|
492
|
+
} catch {
|
|
493
|
+
}
|
|
500
494
|
}
|
|
501
495
|
return createRequest(base, id, instance, {
|
|
502
496
|
...options,
|
|
@@ -548,6 +542,7 @@ async function fetchServerFunction(base, id, options, args, meta, callArgs = arg
|
|
|
548
542
|
return result;
|
|
549
543
|
}
|
|
550
544
|
function createServerReference(id, name, base) {
|
|
545
|
+
provideRPC();
|
|
551
546
|
const metadata = name === undefined ? {} : {
|
|
552
547
|
name
|
|
553
548
|
};
|
|
@@ -578,6 +573,7 @@ function GET(fn) {
|
|
|
578
573
|
if (!isServerFunction(fn)) {
|
|
579
574
|
throw new Error("GET expects a server function reference");
|
|
580
575
|
}
|
|
576
|
+
provideRPC();
|
|
581
577
|
const id = fn.id;
|
|
582
578
|
const metadata = {
|
|
583
579
|
...getServerFunctionMetadata(fn)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var seroval = require('seroval');
|
|
4
|
-
var web = require('seroval-plugins/web');
|
|
5
3
|
var solidJs = require('solid-js');
|
|
6
4
|
|
|
7
5
|
const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
|
|
@@ -14,51 +12,70 @@ function isSafeError(value) {
|
|
|
14
12
|
}
|
|
15
13
|
const REVALIDATE_HEADER = "X-Revalidate";
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
web.FormDataPlugin, web.HeadersPlugin, web.ReadableStreamPlugin, web.RequestPlugin, web.ResponsePlugin, web.URLSearchParamsPlugin, web.URLPlugin]);
|
|
22
|
-
function resolveSerializerPlugins(customPlugins) {
|
|
23
|
-
return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
|
|
15
|
+
const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
|
|
16
|
+
function getServerFunctionMetadata(fn) {
|
|
17
|
+
if (typeof fn !== "function") return undefined;
|
|
18
|
+
return fn[SERVER_FUNCTION_METADATA] || undefined;
|
|
24
19
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
function resolveCodecOptions({
|
|
28
|
-
plugins,
|
|
29
|
-
disabledFeatures,
|
|
30
|
-
depthLimit
|
|
31
|
-
} = {}) {
|
|
32
|
-
return {
|
|
33
|
-
plugins: resolveSerializerPlugins(plugins),
|
|
34
|
-
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
35
|
-
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
36
|
-
};
|
|
20
|
+
function isServerFunction(fn) {
|
|
21
|
+
return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
|
|
37
22
|
}
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return seroval.toCrossJSONStream(value, {
|
|
46
|
-
onParse,
|
|
47
|
-
onDone,
|
|
48
|
-
onError,
|
|
49
|
-
...resolved,
|
|
50
|
-
disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
|
|
51
|
-
});
|
|
23
|
+
function withMeta(fn, meta) {
|
|
24
|
+
const metadata = getServerFunctionMetadata(fn);
|
|
25
|
+
if (!metadata) {
|
|
26
|
+
throw new Error("withMeta expects a server function reference");
|
|
27
|
+
}
|
|
28
|
+
Object.assign(metadata, meta);
|
|
29
|
+
return fn;
|
|
52
30
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
31
|
+
const SERVER_FUNCTION_RPC = Symbol.for("solid.ServerFunctionRPC");
|
|
32
|
+
function provideServerFunctionRPC(rpc) {
|
|
33
|
+
globalThis[SERVER_FUNCTION_RPC] || (globalThis[SERVER_FUNCTION_RPC] = rpc);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parseCookieHeader(header) {
|
|
37
|
+
const cookies = {};
|
|
38
|
+
if (!header) return cookies;
|
|
39
|
+
for (const part of header.split(";")) {
|
|
40
|
+
const eq = part.indexOf("=");
|
|
41
|
+
if (eq < 0) continue;
|
|
42
|
+
const name = decodeSafe(part.slice(0, eq).trim());
|
|
43
|
+
let value = part.slice(eq + 1).trim();
|
|
44
|
+
if (value.length > 1 && value[0] === '"' && value[value.length - 1] === '"') {
|
|
45
|
+
value = value.slice(1, -1);
|
|
46
|
+
}
|
|
47
|
+
cookies[name] = decodeSafe(value);
|
|
48
|
+
}
|
|
49
|
+
return cookies;
|
|
50
|
+
}
|
|
51
|
+
function decodeSafe(text) {
|
|
52
|
+
try {
|
|
53
|
+
return decodeURIComponent(text);
|
|
54
|
+
} catch {
|
|
55
|
+
return text;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function serializeCookie(name, value, options = {}) {
|
|
59
|
+
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
60
|
+
cookie += `; Path=${options.path === undefined ? "/" : options.path}`;
|
|
61
|
+
if (options.domain) cookie += `; Domain=${options.domain}`;
|
|
62
|
+
if (options.maxAge !== undefined) cookie += `; Max-Age=${Math.trunc(options.maxAge)}`;
|
|
63
|
+
if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
64
|
+
if (options.httpOnly) cookie += "; HttpOnly";
|
|
65
|
+
if (options.secure) cookie += "; Secure";
|
|
66
|
+
if (options.sameSite) {
|
|
67
|
+
const sameSite = options.sameSite.toLowerCase();
|
|
68
|
+
cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
|
|
69
|
+
}
|
|
70
|
+
return cookie;
|
|
71
|
+
}
|
|
72
|
+
const FLASH_COOKIE = "flash";
|
|
73
|
+
const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
|
|
74
|
+
function hasFlashCookie(cookieHeader) {
|
|
75
|
+
return !!cookieHeader && FLASH_MATCHER.test(cookieHeader);
|
|
76
|
+
}
|
|
77
|
+
function clearFlashCookie() {
|
|
78
|
+
return `${FLASH_COOKIE}=; Max-Age=0; Path=/`;
|
|
62
79
|
}
|
|
63
80
|
|
|
64
81
|
const codecConfig = {
|
|
@@ -74,22 +91,6 @@ function subscribeFlightData(consumer) {
|
|
|
74
91
|
return () => {
|
|
75
92
|
};
|
|
76
93
|
}
|
|
77
|
-
const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
|
|
78
|
-
function getServerFunctionMetadata(fn) {
|
|
79
|
-
if (typeof fn !== "function") return undefined;
|
|
80
|
-
return fn[SERVER_FUNCTION_METADATA] || undefined;
|
|
81
|
-
}
|
|
82
|
-
function isServerFunction(fn) {
|
|
83
|
-
return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
|
|
84
|
-
}
|
|
85
|
-
function withMeta(fn, meta) {
|
|
86
|
-
const metadata = getServerFunctionMetadata(fn);
|
|
87
|
-
if (!metadata) {
|
|
88
|
-
throw new Error("withMeta expects a server function reference");
|
|
89
|
-
}
|
|
90
|
-
Object.assign(metadata, meta);
|
|
91
|
-
return fn;
|
|
92
|
-
}
|
|
93
94
|
const FUNCTION_HEADER = "X-Server-Function-Id";
|
|
94
95
|
const ERROR_HEADER = "X-Server-Function-Error";
|
|
95
96
|
const ERROR_HEADER_MARKER = "=?1?";
|
|
@@ -120,14 +121,6 @@ const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
|
120
121
|
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
121
122
|
const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
|
|
122
123
|
const FILE_FORM_KEY = "__server_function_file__";
|
|
123
|
-
const FLASH_COOKIE = "flash";
|
|
124
|
-
const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
|
|
125
|
-
function hasFlashCookie(cookieHeader) {
|
|
126
|
-
return !!cookieHeader && FLASH_MATCHER.test(cookieHeader);
|
|
127
|
-
}
|
|
128
|
-
function clearFlashCookie() {
|
|
129
|
-
return `${FLASH_COOKIE}=; Max-Age=0; Path=/`;
|
|
130
|
-
}
|
|
131
124
|
const BodyFormat = {
|
|
132
125
|
Serialized: "0",
|
|
133
126
|
String: "1",
|
|
@@ -139,6 +132,38 @@ const BodyFormat = {
|
|
|
139
132
|
Uint8Array: "7",
|
|
140
133
|
Json: "8"
|
|
141
134
|
};
|
|
135
|
+
const JSON_SAFE_DEPTH_LIMIT = 10000;
|
|
136
|
+
const EXIT = {};
|
|
137
|
+
function isJSONSafe(value) {
|
|
138
|
+
const stack = [value];
|
|
139
|
+
const ancestors = new Set();
|
|
140
|
+
while (stack.length) {
|
|
141
|
+
const v = stack.pop();
|
|
142
|
+
if (v === EXIT) {
|
|
143
|
+
ancestors.delete(stack.pop());
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (v === null) continue;
|
|
147
|
+
const t = typeof v;
|
|
148
|
+
if (t === "string" || t === "boolean") continue;
|
|
149
|
+
if (t === "number") {
|
|
150
|
+
if (!Number.isFinite(v)) return false;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (t !== "object") return false;
|
|
154
|
+
if (ancestors.has(v) || ancestors.size >= JSON_SAFE_DEPTH_LIMIT) return false;
|
|
155
|
+
ancestors.add(v);
|
|
156
|
+
stack.push(v, EXIT);
|
|
157
|
+
if (Array.isArray(v)) {
|
|
158
|
+
for (let i = 0; i < v.length; i++) stack.push(v[i]);
|
|
159
|
+
} else {
|
|
160
|
+
const proto = Object.getPrototypeOf(v);
|
|
161
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
162
|
+
for (const k in v) stack.push(v[k]);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
142
167
|
function getHeadersAndBody(body) {
|
|
143
168
|
switch (true) {
|
|
144
169
|
case typeof body === "string":
|
|
@@ -298,7 +323,10 @@ class ChunkReader {
|
|
|
298
323
|
}
|
|
299
324
|
function serializeStream(value, codecOptions) {
|
|
300
325
|
return new ReadableStream({
|
|
301
|
-
start(controller) {
|
|
326
|
+
async start(controller) {
|
|
327
|
+
const {
|
|
328
|
+
serializeJSON
|
|
329
|
+
} = await import('@solidjs/web/serialization');
|
|
302
330
|
serializeJSON(value, {
|
|
303
331
|
...codecOptions,
|
|
304
332
|
onParse(node) {
|
|
@@ -321,6 +349,9 @@ async function deserializeStream(source, codecOptions) {
|
|
|
321
349
|
const reader = new ChunkReader(source.body);
|
|
322
350
|
const result = await reader.next();
|
|
323
351
|
if (!result.done) {
|
|
352
|
+
const {
|
|
353
|
+
createJSONDeserializer
|
|
354
|
+
} = await import('@solidjs/web/serialization/decode');
|
|
324
355
|
const deserializeChunk = createJSONDeserializer(codecOptions);
|
|
325
356
|
function interpretChunk(chunk) {
|
|
326
357
|
return deserializeChunk(JSON.parse(chunk));
|
|
@@ -350,43 +381,6 @@ async function decodeResponsePayload(response, codecOptions) {
|
|
|
350
381
|
};
|
|
351
382
|
}
|
|
352
383
|
|
|
353
|
-
function parseCookieHeader(header) {
|
|
354
|
-
const cookies = {};
|
|
355
|
-
if (!header) return cookies;
|
|
356
|
-
for (const part of header.split(";")) {
|
|
357
|
-
const eq = part.indexOf("=");
|
|
358
|
-
if (eq < 0) continue;
|
|
359
|
-
const name = decodeSafe(part.slice(0, eq).trim());
|
|
360
|
-
let value = part.slice(eq + 1).trim();
|
|
361
|
-
if (value.length > 1 && value[0] === '"' && value[value.length - 1] === '"') {
|
|
362
|
-
value = value.slice(1, -1);
|
|
363
|
-
}
|
|
364
|
-
cookies[name] = decodeSafe(value);
|
|
365
|
-
}
|
|
366
|
-
return cookies;
|
|
367
|
-
}
|
|
368
|
-
function decodeSafe(text) {
|
|
369
|
-
try {
|
|
370
|
-
return decodeURIComponent(text);
|
|
371
|
-
} catch {
|
|
372
|
-
return text;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
function serializeCookie(name, value, options = {}) {
|
|
376
|
-
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
377
|
-
cookie += `; Path=${options.path === undefined ? "/" : options.path}`;
|
|
378
|
-
if (options.domain) cookie += `; Domain=${options.domain}`;
|
|
379
|
-
if (options.maxAge !== undefined) cookie += `; Max-Age=${Math.trunc(options.maxAge)}`;
|
|
380
|
-
if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
381
|
-
if (options.httpOnly) cookie += "; HttpOnly";
|
|
382
|
-
if (options.secure) cookie += "; Secure";
|
|
383
|
-
if (options.sameSite) {
|
|
384
|
-
const sameSite = options.sameSite.toLowerCase();
|
|
385
|
-
cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
|
|
386
|
-
}
|
|
387
|
-
return cookie;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
384
|
const RequestContext = Symbol.for("solid.RequestContext");
|
|
391
385
|
function getRequestEvent() {
|
|
392
386
|
return globalThis[RequestContext] ? globalThis[RequestContext].getStore() || solidJs.sharedConfig.context && solidJs.sharedConfig.context.event || console.warn("RequestEvent is missing. This is most likely due to accessing `getRequestEvent` non-managed async scope in a partially polyfilled environment. Try moving it above all `await` calls.") : undefined;
|
|
@@ -550,7 +544,17 @@ function provideEvent(event, fn) {
|
|
|
550
544
|
const REGISTRATIONS = new Map();
|
|
551
545
|
const METHODS = new Map();
|
|
552
546
|
const INVOCATIONS = new WeakMap();
|
|
547
|
+
let rpcProvided = false;
|
|
548
|
+
function provideRPC() {
|
|
549
|
+
if (rpcProvided) return;
|
|
550
|
+
rpcProvided = true;
|
|
551
|
+
provideServerFunctionRPC({
|
|
552
|
+
GET,
|
|
553
|
+
decodeResponse
|
|
554
|
+
});
|
|
555
|
+
}
|
|
553
556
|
function registerServerFunction(id, callback) {
|
|
557
|
+
provideRPC();
|
|
554
558
|
REGISTRATIONS.set(id, callback);
|
|
555
559
|
return callback;
|
|
556
560
|
}
|
|
@@ -575,6 +579,7 @@ function createServerReference({
|
|
|
575
579
|
name
|
|
576
580
|
}) {
|
|
577
581
|
if (typeof fn !== "function") throw new Error("Export from a 'use server' module must be a function");
|
|
582
|
+
provideRPC();
|
|
578
583
|
const metadata = name === undefined ? {} : {
|
|
579
584
|
name
|
|
580
585
|
};
|
|
@@ -686,7 +691,9 @@ async function foldFlightData(hook, event, headers, outcome, context = {}) {
|
|
|
686
691
|
return transformed;
|
|
687
692
|
}
|
|
688
693
|
}
|
|
689
|
-
return {
|
|
694
|
+
return outcome.value === undefined ? {
|
|
695
|
+
data
|
|
696
|
+
} : {
|
|
690
697
|
value: outcome.value,
|
|
691
698
|
data
|
|
692
699
|
};
|
|
@@ -818,6 +825,23 @@ function encodeResult(value, headers, status, codec) {
|
|
|
818
825
|
headers
|
|
819
826
|
});
|
|
820
827
|
}
|
|
828
|
+
if (value === undefined) {
|
|
829
|
+
return new Response(null, {
|
|
830
|
+
status,
|
|
831
|
+
headers
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
try {
|
|
835
|
+
if (isJSONSafe(value)) {
|
|
836
|
+
headers.set(BODY_FORMAT_HEADER, BodyFormat.Json);
|
|
837
|
+
headers.set("Content-Type", "application/json");
|
|
838
|
+
return new Response(JSON.stringify(value), {
|
|
839
|
+
status,
|
|
840
|
+
headers
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
} catch {
|
|
844
|
+
}
|
|
821
845
|
const response = serializedResponse(value, headers, codec);
|
|
822
846
|
return status === 200 ? response : new Response(response.body, {
|
|
823
847
|
status,
|