@solidjs/web 2.0.0-experimental.9 → 2.0.0-rc.0
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/README.md +22 -4
- package/dist/dev.cjs +1585 -225
- package/dist/dev.js +1510 -201
- package/dist/server.cjs +2642 -264
- package/dist/server.js +2542 -217
- package/dist/web.cjs +1523 -218
- package/dist/web.js +1448 -194
- package/frames/dist/client.cjs +1916 -0
- package/frames/dist/client.dev.cjs +1933 -0
- package/frames/dist/client.dev.js +1921 -0
- package/frames/dist/client.js +1904 -0
- package/frames/dist/server.cjs +3667 -0
- package/frames/dist/server.js +3654 -0
- package/frames/package.json +30 -0
- package/package.json +349 -37
- 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 +232 -0
- package/serialization/dist/serialization.js +215 -0
- package/serialization/package.json +20 -0
- package/serialization/types/index.d.ts +182 -0
- package/serialization/types/serializer-decode.d.ts +182 -0
- package/serialization/types-cjs/index.d.cts +182 -0
- package/serialization/types-cjs/package.json +3 -0
- package/serialization/types-cjs/serializer-decode.d.cts +182 -0
- package/server-functions/dist/client.cjs +646 -0
- package/server-functions/dist/client.js +617 -0
- package/server-functions/dist/rich-args.cjs +11 -0
- package/server-functions/dist/rich-args.js +9 -0
- package/server-functions/dist/server.cjs +1077 -0
- package/server-functions/dist/server.dev.cjs +1077 -0
- package/server-functions/dist/server.dev.js +1045 -0
- package/server-functions/dist/server.js +1045 -0
- package/server-functions/package.json +40 -0
- package/server-functions/rich-args/package.json +20 -0
- package/storage/package.json +8 -3
- package/storage/types/index.d.ts +26 -0
- package/storage/types-cjs/index.d.cts +28 -0
- package/storage/types-cjs/package.json +3 -0
- package/types/client.d.ts +290 -27
- package/types/cookies.d.ts +93 -0
- package/types/core.d.ts +6 -2
- package/types/frames/client.d.ts +36 -0
- package/types/frames/frame-client.d.ts +338 -0
- package/types/frames/frame-sink.d.ts +194 -0
- package/types/frames/frame-transport.d.ts +222 -0
- package/types/frames/serializer.d.ts +182 -0
- package/types/frames/server.d.ts +52 -0
- package/types/index.d.ts +209 -24
- package/types/jsx-properties.d.ts +93 -0
- package/types/jsx.d.ts +4150 -1
- package/types/response.d.ts +174 -0
- package/types/serializer-decode.d.ts +182 -0
- package/types/serializer.d.ts +182 -0
- package/types/server-functions/client.d.ts +201 -0
- package/types/server-functions/flash.d.ts +38 -0
- package/types/server-functions/rich-args.d.ts +10 -0
- package/types/server-functions/server.d.ts +588 -0
- package/types/server-functions/shared.d.ts +523 -0
- package/types/server-mock.d.ts +249 -12
- package/types/server.d.ts +424 -51
- package/types-cjs/client.d.cts +337 -0
- package/types-cjs/cookies.d.cts +93 -0
- package/types-cjs/core.d.cts +6 -0
- package/types-cjs/frames/client.d.cts +36 -0
- package/types-cjs/frames/frame-client.d.cts +338 -0
- package/types-cjs/frames/frame-sink.d.cts +194 -0
- package/types-cjs/frames/frame-transport.d.cts +222 -0
- package/types-cjs/frames/serializer.d.cts +182 -0
- package/types-cjs/frames/server.d.cts +52 -0
- package/types-cjs/index.d.cts +230 -0
- package/types-cjs/jsx-properties.d.cts +93 -0
- package/types-cjs/jsx.d.cts +4150 -0
- package/types-cjs/package.json +3 -0
- package/types-cjs/response.d.cts +174 -0
- package/types-cjs/serializer-decode.d.cts +182 -0
- package/types-cjs/serializer.d.cts +182 -0
- package/types-cjs/server-functions/client.d.cts +201 -0
- package/types-cjs/server-functions/flash.d.cts +38 -0
- package/types-cjs/server-functions/rich-args.d.cts +10 -0
- package/types-cjs/server-functions/server.d.cts +588 -0
- package/types-cjs/server-functions/shared.d.cts +523 -0
- package/types-cjs/server-mock.d.cts +277 -0
- package/types-cjs/server.d.cts +523 -0
|
@@ -0,0 +1,1045 @@
|
|
|
1
|
+
import { sharedConfig } from 'solid-js';
|
|
2
|
+
|
|
3
|
+
const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
|
|
4
|
+
function isResponseEnvelope(value) {
|
|
5
|
+
return !!(value && typeof value === "object" && value[ENVELOPE]);
|
|
6
|
+
}
|
|
7
|
+
const SAFE_ERROR = Symbol.for("solid.SafeError");
|
|
8
|
+
function isSafeError(value) {
|
|
9
|
+
return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
|
|
10
|
+
}
|
|
11
|
+
const REVALIDATE_HEADER = "X-Revalidate";
|
|
12
|
+
|
|
13
|
+
const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
|
|
14
|
+
function getServerFunctionMetadata(fn) {
|
|
15
|
+
if (typeof fn !== "function") return undefined;
|
|
16
|
+
return fn[SERVER_FUNCTION_METADATA] || undefined;
|
|
17
|
+
}
|
|
18
|
+
function isServerFunction(fn) {
|
|
19
|
+
return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
|
|
20
|
+
}
|
|
21
|
+
function withMeta(fn, meta) {
|
|
22
|
+
const metadata = getServerFunctionMetadata(fn);
|
|
23
|
+
if (!metadata) {
|
|
24
|
+
throw new Error("withMeta expects a server function reference");
|
|
25
|
+
}
|
|
26
|
+
Object.assign(metadata, meta);
|
|
27
|
+
return fn;
|
|
28
|
+
}
|
|
29
|
+
const SERVER_FUNCTION_RPC = Symbol.for("solid.ServerFunctionRPC");
|
|
30
|
+
function provideServerFunctionRPC(rpc) {
|
|
31
|
+
globalThis[SERVER_FUNCTION_RPC] || (globalThis[SERVER_FUNCTION_RPC] = rpc);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseCookieHeader(header) {
|
|
35
|
+
const cookies = {};
|
|
36
|
+
if (!header) return cookies;
|
|
37
|
+
for (const part of header.split(";")) {
|
|
38
|
+
const eq = part.indexOf("=");
|
|
39
|
+
if (eq < 0) continue;
|
|
40
|
+
const name = decodeSafe(part.slice(0, eq).trim());
|
|
41
|
+
let value = part.slice(eq + 1).trim();
|
|
42
|
+
if (value.length > 1 && value[0] === '"' && value[value.length - 1] === '"') {
|
|
43
|
+
value = value.slice(1, -1);
|
|
44
|
+
}
|
|
45
|
+
cookies[name] = decodeSafe(value);
|
|
46
|
+
}
|
|
47
|
+
return cookies;
|
|
48
|
+
}
|
|
49
|
+
function decodeSafe(text) {
|
|
50
|
+
try {
|
|
51
|
+
return decodeURIComponent(text);
|
|
52
|
+
} catch {
|
|
53
|
+
return text;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function serializeCookie(name, value, options = {}) {
|
|
57
|
+
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
58
|
+
cookie += `; Path=${options.path === undefined ? "/" : options.path}`;
|
|
59
|
+
if (options.domain) cookie += `; Domain=${options.domain}`;
|
|
60
|
+
if (options.maxAge !== undefined) cookie += `; Max-Age=${Math.trunc(options.maxAge)}`;
|
|
61
|
+
if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
62
|
+
if (options.httpOnly) cookie += "; HttpOnly";
|
|
63
|
+
if (options.secure) cookie += "; Secure";
|
|
64
|
+
if (options.sameSite) {
|
|
65
|
+
const sameSite = options.sameSite.toLowerCase();
|
|
66
|
+
cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
|
|
67
|
+
}
|
|
68
|
+
return cookie;
|
|
69
|
+
}
|
|
70
|
+
const FLASH_COOKIE = "flash";
|
|
71
|
+
const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
|
|
72
|
+
function hasFlashCookie(cookieHeader) {
|
|
73
|
+
return !!cookieHeader && FLASH_MATCHER.test(cookieHeader);
|
|
74
|
+
}
|
|
75
|
+
function clearFlashCookie() {
|
|
76
|
+
return `${FLASH_COOKIE}=; Max-Age=0; Path=/`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const codecConfig = {
|
|
80
|
+
codec: undefined
|
|
81
|
+
};
|
|
82
|
+
function configureServerFunctionsCodec(codec) {
|
|
83
|
+
codecConfig.codec = codec;
|
|
84
|
+
}
|
|
85
|
+
function getServerFunctionsCodec() {
|
|
86
|
+
return codecConfig.codec;
|
|
87
|
+
}
|
|
88
|
+
function subscribeFlightData(consumer) {
|
|
89
|
+
return () => {
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const FUNCTION_HEADER = "X-Server-Function-Id";
|
|
93
|
+
const ERROR_HEADER = "X-Server-Function-Error";
|
|
94
|
+
const ERROR_HEADER_MARKER = "=?1?";
|
|
95
|
+
const NEEDS_ENCODING = /[^\x20-\x7e\xa0-\xff]/;
|
|
96
|
+
function encodeErrorHeaderValue(value) {
|
|
97
|
+
let stripped = String(value).replace(/[\r\n]+/g, "");
|
|
98
|
+
if (!NEEDS_ENCODING.test(stripped) && !stripped.startsWith(ERROR_HEADER_MARKER) && stripped === stripped.trim()) {
|
|
99
|
+
return stripped;
|
|
100
|
+
}
|
|
101
|
+
if (typeof stripped.toWellFormed === "function") {
|
|
102
|
+
stripped = stripped.toWellFormed();
|
|
103
|
+
} else {
|
|
104
|
+
stripped = stripped.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD");
|
|
105
|
+
}
|
|
106
|
+
return ERROR_HEADER_MARKER + encodeURIComponent(stripped);
|
|
107
|
+
}
|
|
108
|
+
function decodeErrorHeaderValue(value) {
|
|
109
|
+
if (typeof value !== "string" || !value.startsWith(ERROR_HEADER_MARKER)) {
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
return decodeURIComponent(value.slice(ERROR_HEADER_MARKER.length));
|
|
114
|
+
} catch {
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
119
|
+
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
120
|
+
const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
|
|
121
|
+
const FILE_FORM_KEY = "__server_function_file__";
|
|
122
|
+
const BodyFormat = {
|
|
123
|
+
Serialized: "0",
|
|
124
|
+
String: "1",
|
|
125
|
+
FormData: "2",
|
|
126
|
+
URLSearchParams: "3",
|
|
127
|
+
Blob: "4",
|
|
128
|
+
File: "5",
|
|
129
|
+
ArrayBuffer: "6",
|
|
130
|
+
Uint8Array: "7",
|
|
131
|
+
Json: "8"
|
|
132
|
+
};
|
|
133
|
+
const JSON_SAFE_DEPTH_LIMIT = 10000;
|
|
134
|
+
const EXIT = {};
|
|
135
|
+
function isJSONSafe(value) {
|
|
136
|
+
const stack = [value];
|
|
137
|
+
const ancestors = new Set();
|
|
138
|
+
while (stack.length) {
|
|
139
|
+
const v = stack.pop();
|
|
140
|
+
if (v === EXIT) {
|
|
141
|
+
ancestors.delete(stack.pop());
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (v === null) continue;
|
|
145
|
+
const t = typeof v;
|
|
146
|
+
if (t === "string" || t === "boolean") continue;
|
|
147
|
+
if (t === "number") {
|
|
148
|
+
if (!Number.isFinite(v)) return false;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (t !== "object") return false;
|
|
152
|
+
if (ancestors.has(v) || ancestors.size >= JSON_SAFE_DEPTH_LIMIT) return false;
|
|
153
|
+
ancestors.add(v);
|
|
154
|
+
stack.push(v, EXIT);
|
|
155
|
+
if (Array.isArray(v)) {
|
|
156
|
+
for (let i = 0; i < v.length; i++) stack.push(v[i]);
|
|
157
|
+
} else {
|
|
158
|
+
const proto = Object.getPrototypeOf(v);
|
|
159
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
160
|
+
for (const k in v) stack.push(v[k]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
function getHeadersAndBody(body) {
|
|
166
|
+
switch (true) {
|
|
167
|
+
case typeof body === "string":
|
|
168
|
+
return {
|
|
169
|
+
headers: {
|
|
170
|
+
"Content-Type": "text/plain",
|
|
171
|
+
[BODY_FORMAT_HEADER]: BodyFormat.String
|
|
172
|
+
},
|
|
173
|
+
body
|
|
174
|
+
};
|
|
175
|
+
case body instanceof FormData:
|
|
176
|
+
return {
|
|
177
|
+
headers: {
|
|
178
|
+
[BODY_FORMAT_HEADER]: BodyFormat.FormData
|
|
179
|
+
},
|
|
180
|
+
body
|
|
181
|
+
};
|
|
182
|
+
case body instanceof URLSearchParams:
|
|
183
|
+
return {
|
|
184
|
+
headers: {
|
|
185
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
186
|
+
[BODY_FORMAT_HEADER]: BodyFormat.URLSearchParams
|
|
187
|
+
},
|
|
188
|
+
body
|
|
189
|
+
};
|
|
190
|
+
case typeof File !== "undefined" && body instanceof File:
|
|
191
|
+
{
|
|
192
|
+
const formData = new FormData();
|
|
193
|
+
formData.append(FILE_FORM_KEY, body, body.name);
|
|
194
|
+
return {
|
|
195
|
+
headers: {
|
|
196
|
+
[BODY_FORMAT_HEADER]: BodyFormat.File
|
|
197
|
+
},
|
|
198
|
+
body: formData
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
case body instanceof Blob:
|
|
202
|
+
return {
|
|
203
|
+
headers: {
|
|
204
|
+
[BODY_FORMAT_HEADER]: BodyFormat.Blob
|
|
205
|
+
},
|
|
206
|
+
body
|
|
207
|
+
};
|
|
208
|
+
case body instanceof ArrayBuffer:
|
|
209
|
+
return {
|
|
210
|
+
headers: {
|
|
211
|
+
[BODY_FORMAT_HEADER]: BodyFormat.ArrayBuffer
|
|
212
|
+
},
|
|
213
|
+
body
|
|
214
|
+
};
|
|
215
|
+
case body instanceof Uint8Array:
|
|
216
|
+
return {
|
|
217
|
+
headers: {
|
|
218
|
+
[BODY_FORMAT_HEADER]: BodyFormat.Uint8Array
|
|
219
|
+
},
|
|
220
|
+
body: new Uint8Array(body)
|
|
221
|
+
};
|
|
222
|
+
default:
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function extractBody(source, codecOptions) {
|
|
227
|
+
const contentType = source.headers.get("content-type");
|
|
228
|
+
const format = source.headers.get(BODY_FORMAT_HEADER);
|
|
229
|
+
const clone = source.clone();
|
|
230
|
+
switch (true) {
|
|
231
|
+
case format === BodyFormat.Serialized:
|
|
232
|
+
return await deserializeStream(clone, codecOptions);
|
|
233
|
+
case format === BodyFormat.Json:
|
|
234
|
+
return JSON.parse(await clone.text());
|
|
235
|
+
case format === BodyFormat.String:
|
|
236
|
+
return await clone.text();
|
|
237
|
+
case format === BodyFormat.File:
|
|
238
|
+
{
|
|
239
|
+
const formData = await clone.formData();
|
|
240
|
+
return formData.get(FILE_FORM_KEY);
|
|
241
|
+
}
|
|
242
|
+
case format === BodyFormat.FormData:
|
|
243
|
+
case contentType && contentType.startsWith("multipart/form-data"):
|
|
244
|
+
return await clone.formData();
|
|
245
|
+
case format === BodyFormat.URLSearchParams:
|
|
246
|
+
case contentType && contentType.startsWith("application/x-www-form-urlencoded"):
|
|
247
|
+
return new URLSearchParams(await clone.text());
|
|
248
|
+
case format === BodyFormat.Blob:
|
|
249
|
+
return await clone.blob();
|
|
250
|
+
case format === BodyFormat.ArrayBuffer:
|
|
251
|
+
return await clone.arrayBuffer();
|
|
252
|
+
case format === BodyFormat.Uint8Array:
|
|
253
|
+
return new Uint8Array(await clone.arrayBuffer());
|
|
254
|
+
}
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
function createChunk(data) {
|
|
258
|
+
const encoder = new TextEncoder();
|
|
259
|
+
const encodeData = encoder.encode(data);
|
|
260
|
+
const bytes = encodeData.length;
|
|
261
|
+
const chunk = new Uint8Array(12 + bytes);
|
|
262
|
+
chunk.set(encoder.encode(`;0x${bytes.toString(16).padStart(8, "0")};`));
|
|
263
|
+
chunk.set(encodeData, 12);
|
|
264
|
+
return chunk;
|
|
265
|
+
}
|
|
266
|
+
class ChunkReader {
|
|
267
|
+
constructor(stream) {
|
|
268
|
+
this.reader = stream.getReader();
|
|
269
|
+
this.buffer = new Uint8Array(0);
|
|
270
|
+
this.done = false;
|
|
271
|
+
}
|
|
272
|
+
async readChunk() {
|
|
273
|
+
const chunk = await this.reader.read();
|
|
274
|
+
if (!chunk.done) {
|
|
275
|
+
const newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
|
|
276
|
+
newBuffer.set(this.buffer);
|
|
277
|
+
newBuffer.set(chunk.value, this.buffer.length);
|
|
278
|
+
this.buffer = newBuffer;
|
|
279
|
+
} else {
|
|
280
|
+
this.done = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
async next() {
|
|
284
|
+
while (this.buffer.length < 12) {
|
|
285
|
+
if (this.done) {
|
|
286
|
+
if (this.buffer.length === 0) return {
|
|
287
|
+
done: true,
|
|
288
|
+
value: undefined
|
|
289
|
+
};
|
|
290
|
+
throw new Error("Malformed server function stream.");
|
|
291
|
+
}
|
|
292
|
+
await this.readChunk();
|
|
293
|
+
}
|
|
294
|
+
const decoder = new TextDecoder();
|
|
295
|
+
const bytes = Number.parseInt(decoder.decode(this.buffer.subarray(1, 11)), 16);
|
|
296
|
+
if (Number.isNaN(bytes)) {
|
|
297
|
+
throw new Error("Malformed server function stream.");
|
|
298
|
+
}
|
|
299
|
+
while (bytes > this.buffer.length - 12) {
|
|
300
|
+
if (this.done) {
|
|
301
|
+
throw new Error("Malformed server function stream.");
|
|
302
|
+
}
|
|
303
|
+
await this.readChunk();
|
|
304
|
+
}
|
|
305
|
+
const partial = decoder.decode(this.buffer.subarray(12, 12 + bytes));
|
|
306
|
+
this.buffer = this.buffer.subarray(12 + bytes);
|
|
307
|
+
return {
|
|
308
|
+
done: false,
|
|
309
|
+
value: partial
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
async drain(interpret) {
|
|
313
|
+
while (true) {
|
|
314
|
+
const result = await this.next();
|
|
315
|
+
if (result.done) {
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
interpret(result.value);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function serializeStream(value, codecOptions) {
|
|
323
|
+
return new ReadableStream({
|
|
324
|
+
async start(controller) {
|
|
325
|
+
const {
|
|
326
|
+
serializeJSON
|
|
327
|
+
} = await import('@solidjs/web/serialization');
|
|
328
|
+
serializeJSON(value, {
|
|
329
|
+
...codecOptions,
|
|
330
|
+
onParse(node) {
|
|
331
|
+
controller.enqueue(createChunk(JSON.stringify(node)));
|
|
332
|
+
},
|
|
333
|
+
onDone() {
|
|
334
|
+
controller.close();
|
|
335
|
+
},
|
|
336
|
+
onError(error) {
|
|
337
|
+
controller.error(error);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
async function deserializeStream(source, codecOptions) {
|
|
344
|
+
if (!source.body) {
|
|
345
|
+
throw new Error("missing body");
|
|
346
|
+
}
|
|
347
|
+
const reader = new ChunkReader(source.body);
|
|
348
|
+
const result = await reader.next();
|
|
349
|
+
if (!result.done) {
|
|
350
|
+
const {
|
|
351
|
+
createJSONDeserializer
|
|
352
|
+
} = await import('@solidjs/web/serialization/decode');
|
|
353
|
+
const deserializeChunk = createJSONDeserializer(codecOptions);
|
|
354
|
+
function interpretChunk(chunk) {
|
|
355
|
+
return deserializeChunk(JSON.parse(chunk));
|
|
356
|
+
}
|
|
357
|
+
void reader.drain(interpretChunk);
|
|
358
|
+
return interpretChunk(result.value);
|
|
359
|
+
}
|
|
360
|
+
return undefined;
|
|
361
|
+
}
|
|
362
|
+
async function deserializeString(text, codecOptions) {
|
|
363
|
+
return await deserializeStream(new Response(text), codecOptions);
|
|
364
|
+
}
|
|
365
|
+
async function decodeResponse(response, codecOptions) {
|
|
366
|
+
if (!response.body) return undefined;
|
|
367
|
+
return await extractBody(response, codecOptions === undefined ? codecConfig.codec : codecOptions);
|
|
368
|
+
}
|
|
369
|
+
async function decodeResponsePayload(response, codecOptions) {
|
|
370
|
+
const decoded = await decodeResponse(response, codecOptions);
|
|
371
|
+
if (decoded !== undefined && response.headers.has(SINGLE_FLIGHT_HEADER)) {
|
|
372
|
+
return {
|
|
373
|
+
value: decoded.value,
|
|
374
|
+
flightData: decoded.data
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
value: decoded
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const RequestContext = Symbol.for("solid.RequestContext");
|
|
383
|
+
function getRequestEvent() {
|
|
384
|
+
return globalThis[RequestContext] ? globalThis[RequestContext].getStore() || sharedConfig.context && 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;
|
|
385
|
+
}
|
|
386
|
+
function reportLostHeaderWrite(method, name) {
|
|
387
|
+
const message = `Response header write dropped: headers.${method}(${JSON.stringify(String(name))}) ` + "ran after the response head was sent. Write headers before the shell flushes " + "(or before the handler returns).";
|
|
388
|
+
throw new Error(message);
|
|
389
|
+
}
|
|
390
|
+
function commitResponseStub(stub, {
|
|
391
|
+
allowLateLocation = false
|
|
392
|
+
} = {}) {
|
|
393
|
+
if (!stub || stub.committed) return stub;
|
|
394
|
+
stub.committed = true;
|
|
395
|
+
const headers = stub.headers;
|
|
396
|
+
if (!headers || typeof headers.set !== "function") return stub;
|
|
397
|
+
for (const method of ["set", "append", "delete"]) {
|
|
398
|
+
const original = headers[method].bind(headers);
|
|
399
|
+
headers[method] = function (name, ...rest) {
|
|
400
|
+
if (allowLateLocation && method === "set" && String(name).toLowerCase() === "location") {
|
|
401
|
+
return original(name, ...rest);
|
|
402
|
+
}
|
|
403
|
+
reportLostHeaderWrite(method, name);
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
return stub;
|
|
407
|
+
}
|
|
408
|
+
function copyInitHeaders(init) {
|
|
409
|
+
if (!init || !init.getSetCookie) return new Headers(init);
|
|
410
|
+
const headers = new Headers();
|
|
411
|
+
init.forEach((value, key) => {
|
|
412
|
+
if (key !== "set-cookie") headers.append(key, value);
|
|
413
|
+
});
|
|
414
|
+
for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
|
|
415
|
+
return headers;
|
|
416
|
+
}
|
|
417
|
+
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
|
|
418
|
+
function fillsStubGap(key, headers, response) {
|
|
419
|
+
if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
|
|
420
|
+
if (response.body === null && (key === "content-type" || key === "content-length")) return false;
|
|
421
|
+
return !headers.has(key);
|
|
422
|
+
}
|
|
423
|
+
function commitEventResponse(response, event = getRequestEvent()) {
|
|
424
|
+
const stub = event && event.response;
|
|
425
|
+
if (!stub || !stub.headers || stub.committed) return response;
|
|
426
|
+
const cookies = stub.headers.getSetCookie ? stub.headers.getSetCookie() : [];
|
|
427
|
+
commitResponseStub(stub);
|
|
428
|
+
let hasGaps = false;
|
|
429
|
+
stub.headers.forEach((value, key) => {
|
|
430
|
+
if (fillsStubGap(key, response.headers, response)) hasGaps = true;
|
|
431
|
+
});
|
|
432
|
+
if (!cookies.length && !hasGaps) return response;
|
|
433
|
+
try {
|
|
434
|
+
for (const cookie of cookies) response.headers.append("Set-Cookie", cookie);
|
|
435
|
+
stub.headers.forEach((value, key) => {
|
|
436
|
+
if (fillsStubGap(key, response.headers, response)) response.headers.set(key, value);
|
|
437
|
+
});
|
|
438
|
+
return response;
|
|
439
|
+
} catch {
|
|
440
|
+
const headers = copyInitHeaders(response.headers);
|
|
441
|
+
for (const cookie of cookies) headers.append("Set-Cookie", cookie);
|
|
442
|
+
stub.headers.forEach((value, key) => {
|
|
443
|
+
if (fillsStubGap(key, headers, response)) headers.set(key, value);
|
|
444
|
+
});
|
|
445
|
+
return new Response(response.body, {
|
|
446
|
+
status: response.status,
|
|
447
|
+
statusText: response.statusText,
|
|
448
|
+
headers
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function encodeInputValue(value) {
|
|
454
|
+
if (value instanceof FormData) return {
|
|
455
|
+
$f: [...value.entries()].filter(([, v]) => typeof v === "string")
|
|
456
|
+
};
|
|
457
|
+
if (value instanceof URLSearchParams) return {
|
|
458
|
+
$u: [...value.entries()]
|
|
459
|
+
};
|
|
460
|
+
return value;
|
|
461
|
+
}
|
|
462
|
+
function decodeInputValue(value) {
|
|
463
|
+
if (value && typeof value === "object") {
|
|
464
|
+
if (Array.isArray(value.$f)) {
|
|
465
|
+
const form = new FormData();
|
|
466
|
+
for (const [k, v] of value.$f) form.append(k, v);
|
|
467
|
+
return form;
|
|
468
|
+
}
|
|
469
|
+
if (Array.isArray(value.$u)) return new URLSearchParams(value.$u);
|
|
470
|
+
}
|
|
471
|
+
return value;
|
|
472
|
+
}
|
|
473
|
+
function encodeFlashCookie(url, result, input, thrown) {
|
|
474
|
+
const isError = result instanceof Error;
|
|
475
|
+
const payload = {
|
|
476
|
+
url,
|
|
477
|
+
result: isError ? result.message : result,
|
|
478
|
+
error: isError,
|
|
479
|
+
thrown: !!thrown,
|
|
480
|
+
input: input.map(encodeInputValue)
|
|
481
|
+
};
|
|
482
|
+
return serializeCookie(FLASH_COOKIE, JSON.stringify(payload), {
|
|
483
|
+
secure: true,
|
|
484
|
+
httpOnly: true
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
function decodeFlashCookie(cookieHeader) {
|
|
488
|
+
const match = parseCookieHeader(cookieHeader)[FLASH_COOKIE];
|
|
489
|
+
if (!match) return;
|
|
490
|
+
try {
|
|
491
|
+
const payload = JSON.parse(match);
|
|
492
|
+
if (!payload || !payload.result) return;
|
|
493
|
+
const result = payload.error ? new Error(payload.result) : payload.result;
|
|
494
|
+
return {
|
|
495
|
+
input: Array.isArray(payload.input) ? payload.input.map(decodeInputValue) : [],
|
|
496
|
+
url: payload.url,
|
|
497
|
+
result: payload.thrown ? undefined : result,
|
|
498
|
+
error: payload.thrown ? result : undefined
|
|
499
|
+
};
|
|
500
|
+
} catch (error) {
|
|
501
|
+
console.error(error);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const config = {
|
|
506
|
+
provideEvent: undefined,
|
|
507
|
+
wrapInvocation: undefined,
|
|
508
|
+
collectFlightData: undefined,
|
|
509
|
+
transformResult: undefined,
|
|
510
|
+
transformFlightResult: undefined,
|
|
511
|
+
transformDirectResult: undefined,
|
|
512
|
+
handleNoJS: undefined,
|
|
513
|
+
endpoint: "/_server"
|
|
514
|
+
};
|
|
515
|
+
function configureServerFunctionsServer({
|
|
516
|
+
provideEvent,
|
|
517
|
+
wrapInvocation,
|
|
518
|
+
collectFlightData,
|
|
519
|
+
transformResult,
|
|
520
|
+
transformFlightResult,
|
|
521
|
+
transformDirectResult,
|
|
522
|
+
handleNoJS,
|
|
523
|
+
endpoint,
|
|
524
|
+
codec
|
|
525
|
+
} = {}) {
|
|
526
|
+
if (provideEvent !== undefined) config.provideEvent = provideEvent;
|
|
527
|
+
if (wrapInvocation !== undefined) config.wrapInvocation = wrapInvocation;
|
|
528
|
+
if (collectFlightData !== undefined) config.collectFlightData = collectFlightData;
|
|
529
|
+
if (transformResult !== undefined) config.transformResult = transformResult;
|
|
530
|
+
if (transformFlightResult !== undefined) config.transformFlightResult = transformFlightResult;
|
|
531
|
+
if (transformDirectResult !== undefined) config.transformDirectResult = transformDirectResult;
|
|
532
|
+
if (handleNoJS !== undefined) config.handleNoJS = handleNoJS;
|
|
533
|
+
if (endpoint !== undefined) config.endpoint = endpoint;
|
|
534
|
+
if (codec !== undefined) configureServerFunctionsCodec(codec);
|
|
535
|
+
}
|
|
536
|
+
function provideEvent(event, fn) {
|
|
537
|
+
if (config.provideEvent) return config.provideEvent(event, fn);
|
|
538
|
+
const ctx = globalThis[RequestContext];
|
|
539
|
+
if (ctx) return ctx.run(event, fn);
|
|
540
|
+
throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
|
|
541
|
+
}
|
|
542
|
+
const REGISTRATIONS = new Map();
|
|
543
|
+
const METHODS = new Map();
|
|
544
|
+
const INVOCATIONS = new WeakMap();
|
|
545
|
+
let rpcProvided = false;
|
|
546
|
+
function provideRPC() {
|
|
547
|
+
if (rpcProvided) return;
|
|
548
|
+
rpcProvided = true;
|
|
549
|
+
provideServerFunctionRPC({
|
|
550
|
+
GET,
|
|
551
|
+
decodeResponse
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
function registerServerFunction(id, callback) {
|
|
555
|
+
provideRPC();
|
|
556
|
+
REGISTRATIONS.set(id, callback);
|
|
557
|
+
return callback;
|
|
558
|
+
}
|
|
559
|
+
function getServerFunction(id) {
|
|
560
|
+
const fn = REGISTRATIONS.get(id);
|
|
561
|
+
if (fn) {
|
|
562
|
+
return fn;
|
|
563
|
+
}
|
|
564
|
+
throw new Error("invalid server function: " + id);
|
|
565
|
+
}
|
|
566
|
+
function registerServerReference(id, fn, name) {
|
|
567
|
+
registerServerFunction(id, fn);
|
|
568
|
+
return {
|
|
569
|
+
id,
|
|
570
|
+
fn,
|
|
571
|
+
name
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
function createServerReference({
|
|
575
|
+
id,
|
|
576
|
+
fn,
|
|
577
|
+
name
|
|
578
|
+
}) {
|
|
579
|
+
if (typeof fn !== "function") throw new Error("Export from a 'use server' module must be a function");
|
|
580
|
+
provideRPC();
|
|
581
|
+
const metadata = name === undefined ? {} : {
|
|
582
|
+
name
|
|
583
|
+
};
|
|
584
|
+
return new Proxy(fn, {
|
|
585
|
+
get(target, prop) {
|
|
586
|
+
if (prop === "id") return id;
|
|
587
|
+
if (prop === "url") {
|
|
588
|
+
return `${config.endpoint}?id=${encodeURIComponent(id)}`;
|
|
589
|
+
}
|
|
590
|
+
if (prop === SERVER_FUNCTION_METADATA) return metadata;
|
|
591
|
+
return target[prop];
|
|
592
|
+
},
|
|
593
|
+
apply(target, thisArg, args) {
|
|
594
|
+
const ogEvt = getRequestEvent();
|
|
595
|
+
if (!ogEvt) throw new Error("Cannot call server function outside of a request");
|
|
596
|
+
const evt = {
|
|
597
|
+
...ogEvt
|
|
598
|
+
};
|
|
599
|
+
INVOCATIONS.set(evt, {
|
|
600
|
+
id
|
|
601
|
+
});
|
|
602
|
+
evt.serverOnly = true;
|
|
603
|
+
const result = provideEvent(evt, () => {
|
|
604
|
+
const run = () => fn.apply(thisArg, args);
|
|
605
|
+
return config.wrapInvocation ? config.wrapInvocation(run, {
|
|
606
|
+
id,
|
|
607
|
+
args,
|
|
608
|
+
event: evt,
|
|
609
|
+
direct: true
|
|
610
|
+
}) : run();
|
|
611
|
+
});
|
|
612
|
+
const transform = config.transformDirectResult;
|
|
613
|
+
if (transform && result && typeof result.then === "function") {
|
|
614
|
+
return result.then(value => transform(value, {
|
|
615
|
+
id,
|
|
616
|
+
args,
|
|
617
|
+
event: evt
|
|
618
|
+
}));
|
|
619
|
+
}
|
|
620
|
+
return transform ? transform(result, {
|
|
621
|
+
id,
|
|
622
|
+
args,
|
|
623
|
+
event: evt
|
|
624
|
+
}) : result;
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
function GET(fn) {
|
|
629
|
+
if (!isServerFunction(fn) || typeof fn.id !== "string") {
|
|
630
|
+
throw new Error("GET expects a server function reference");
|
|
631
|
+
}
|
|
632
|
+
METHODS.set(fn.id, "GET");
|
|
633
|
+
return withMeta(fn, {
|
|
634
|
+
method: "GET"
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
function getServerFunctionInvocation() {
|
|
638
|
+
return getEventServerFunctionInvocation(getRequestEvent());
|
|
639
|
+
}
|
|
640
|
+
function getEventServerFunctionInvocation(event) {
|
|
641
|
+
return event && INVOCATIONS.get(event);
|
|
642
|
+
}
|
|
643
|
+
function resolveFunctionId(request, url) {
|
|
644
|
+
const reference = request.headers.get(FUNCTION_HEADER);
|
|
645
|
+
if (reference) {
|
|
646
|
+
return reference.split("#")[0];
|
|
647
|
+
}
|
|
648
|
+
return url.searchParams.get("id");
|
|
649
|
+
}
|
|
650
|
+
async function parseArguments(request, url, instance, codec) {
|
|
651
|
+
const parsed = [];
|
|
652
|
+
const bodyFormat = request.method === "POST" ? request.headers.get(BODY_FORMAT_HEADER) : null;
|
|
653
|
+
if (!instance || request.method === "GET" || bodyFormat !== BodyFormat.Serialized) {
|
|
654
|
+
const args = url.searchParams.get("args");
|
|
655
|
+
if (args) {
|
|
656
|
+
const result = args.startsWith(";0x") ? await deserializeString(args, codec) : JSON.parse(args);
|
|
657
|
+
for (const arg of result) {
|
|
658
|
+
parsed.push(arg);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
if (request.method === "POST" && request.body !== null) {
|
|
663
|
+
const decoded = await extractBody(request.clone(), codec);
|
|
664
|
+
if (bodyFormat === BodyFormat.Serialized || bodyFormat === BodyFormat.Json) {
|
|
665
|
+
return decoded;
|
|
666
|
+
}
|
|
667
|
+
parsed.push(decoded);
|
|
668
|
+
}
|
|
669
|
+
return parsed;
|
|
670
|
+
}
|
|
671
|
+
async function foldFlightData(hook, event, headers, outcome, context = {}) {
|
|
672
|
+
if (outcome.value instanceof Response && outcome.value.body) return outcome.value;
|
|
673
|
+
digestOutcome(event, outcome);
|
|
674
|
+
const data = await hook(event, outcome);
|
|
675
|
+
if (data === undefined) return outcome.value;
|
|
676
|
+
headers.set(SINGLE_FLIGHT_HEADER, "true");
|
|
677
|
+
if (context.transformFlightResult) {
|
|
678
|
+
const transformed = await context.transformFlightResult(event, {
|
|
679
|
+
value: outcome.value,
|
|
680
|
+
data
|
|
681
|
+
}, context);
|
|
682
|
+
if (transformed !== undefined) {
|
|
683
|
+
for (const cookie of headers.getSetCookie()) transformed.headers.append("Set-Cookie", cookie);
|
|
684
|
+
headers.forEach((value, key) => {
|
|
685
|
+
if (key !== "set-cookie" && !transformed.headers.has(key)) {
|
|
686
|
+
transformed.headers.set(key, value);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
return transformed;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return outcome.value === undefined ? {
|
|
693
|
+
data
|
|
694
|
+
} : {
|
|
695
|
+
value: outcome.value,
|
|
696
|
+
data
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
function digestOutcome(event, outcome) {
|
|
700
|
+
const {
|
|
701
|
+
request,
|
|
702
|
+
response
|
|
703
|
+
} = outcome;
|
|
704
|
+
outcome.revalidateKeys = response?.headers.get(REVALIDATE_HEADER)?.split(",");
|
|
705
|
+
outcome.foldedHeaders = foldSetCookies(request.headers, [...(event.response?.headers?.getSetCookie() ?? []), ...(response?.headers?.getSetCookie() ?? [])]);
|
|
706
|
+
try {
|
|
707
|
+
const referrer = request.headers.get("referer");
|
|
708
|
+
if (referrer) {
|
|
709
|
+
const location = response?.headers.get("Location");
|
|
710
|
+
const target = location ? new URL(location, request.url) : new URL(referrer);
|
|
711
|
+
if (target.origin === new URL(request.url).origin) outcome.targetUrl = target.toString();
|
|
712
|
+
}
|
|
713
|
+
} catch {
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
function parseSetCookie(setCookie) {
|
|
717
|
+
const [pair, ...attributes] = setCookie.split(";");
|
|
718
|
+
const eq = pair.indexOf("=");
|
|
719
|
+
if (eq < 0) return undefined;
|
|
720
|
+
const parsed = {
|
|
721
|
+
name: pair.slice(0, eq).trim(),
|
|
722
|
+
value: pair.slice(eq + 1).trim()
|
|
723
|
+
};
|
|
724
|
+
for (const attribute of attributes) {
|
|
725
|
+
const attrEq = attribute.indexOf("=");
|
|
726
|
+
const key = (attrEq < 0 ? attribute : attribute.slice(0, attrEq)).trim().toLowerCase();
|
|
727
|
+
const value = attrEq < 0 ? "" : attribute.slice(attrEq + 1).trim();
|
|
728
|
+
if (key === "max-age") parsed.maxAge = Number(value);else if (key === "expires") parsed.expires = new Date(value);
|
|
729
|
+
}
|
|
730
|
+
return parsed;
|
|
731
|
+
}
|
|
732
|
+
function foldSetCookies(headers, setCookies) {
|
|
733
|
+
const folded = new Headers(headers);
|
|
734
|
+
if (!setCookies.length) return folded;
|
|
735
|
+
const cookies = {};
|
|
736
|
+
for (const pair of folded.get("cookie")?.split(";") ?? []) {
|
|
737
|
+
const eq = pair.indexOf("=");
|
|
738
|
+
if (eq > -1) cookies[pair.slice(0, eq).trim()] = pair.slice(eq + 1).trim();
|
|
739
|
+
}
|
|
740
|
+
for (const setCookie of setCookies) {
|
|
741
|
+
const parsed = parseSetCookie(setCookie);
|
|
742
|
+
if (!parsed) continue;
|
|
743
|
+
if (parsed.maxAge != null && parsed.maxAge <= 0 || parsed.expires != null && parsed.expires.getTime() <= Date.now()) {
|
|
744
|
+
delete cookies[parsed.name];
|
|
745
|
+
} else {
|
|
746
|
+
cookies[parsed.name] = parsed.value;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
folded.delete("cookie");
|
|
750
|
+
const serialized = Object.entries(cookies).map(([name, value]) => `${name}=${value}`).join("; ");
|
|
751
|
+
if (serialized) folded.set("cookie", serialized);
|
|
752
|
+
return folded;
|
|
753
|
+
}
|
|
754
|
+
function mergeResponseHeaders(target, source) {
|
|
755
|
+
source.forEach((value, key) => {
|
|
756
|
+
if (key !== "set-cookie") target.append(key, value);
|
|
757
|
+
});
|
|
758
|
+
if (source.getSetCookie) {
|
|
759
|
+
for (const cookie of source.getSetCookie()) target.append("Set-Cookie", cookie);
|
|
760
|
+
} else if (source.has("set-cookie")) {
|
|
761
|
+
target.append("Set-Cookie", source.get("set-cookie"));
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const validRedirectStatuses = new Set([301, 302, 303, 307, 308]);
|
|
765
|
+
function createNoJSHandler({
|
|
766
|
+
base = ""
|
|
767
|
+
} = {}) {
|
|
768
|
+
return function handleNoJS(result, request, args, thrown) {
|
|
769
|
+
const url = new URL(request.url);
|
|
770
|
+
let back = new URL(base || "/", url.origin).toString();
|
|
771
|
+
try {
|
|
772
|
+
const referer = request.headers.get("referer");
|
|
773
|
+
if (referer) back = new URL(referer).toString();
|
|
774
|
+
} catch {}
|
|
775
|
+
let status = 303;
|
|
776
|
+
let headers;
|
|
777
|
+
if (result instanceof Response) {
|
|
778
|
+
headers = new Headers();
|
|
779
|
+
mergeResponseHeaders(headers, result.headers);
|
|
780
|
+
if (result.headers.has("Location")) {
|
|
781
|
+
headers.set("Location", new URL(result.headers.get("Location"), url.origin + base).toString());
|
|
782
|
+
if (validRedirectStatuses.has(result.status)) status = result.status;
|
|
783
|
+
} else {
|
|
784
|
+
headers.set("Location", back);
|
|
785
|
+
}
|
|
786
|
+
headers.delete("Content-Type");
|
|
787
|
+
headers.delete("Content-Length");
|
|
788
|
+
} else {
|
|
789
|
+
headers = new Headers({
|
|
790
|
+
Location: back
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
if (result && !(result instanceof Response)) {
|
|
794
|
+
headers.append("Set-Cookie", encodeFlashCookie(url.pathname + url.search, result, args, thrown));
|
|
795
|
+
}
|
|
796
|
+
return new Response(null, {
|
|
797
|
+
status,
|
|
798
|
+
headers
|
|
799
|
+
});
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
let defaultNoJSHandler;
|
|
803
|
+
function isFormPost(request) {
|
|
804
|
+
if (request.method !== "POST" || request.headers.has(BODY_FORMAT_HEADER)) return false;
|
|
805
|
+
const type = request.headers.get("content-type") || "";
|
|
806
|
+
return type.startsWith("application/x-www-form-urlencoded") || type.startsWith("multipart/form-data");
|
|
807
|
+
}
|
|
808
|
+
function serializedResponse(value, headers, codec) {
|
|
809
|
+
headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
|
|
810
|
+
headers.set("Content-Type", "text/plain");
|
|
811
|
+
return new Response(serializeStream(value, codec), {
|
|
812
|
+
headers
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
function encodeResult(value, headers, status, codec) {
|
|
816
|
+
const direct = getHeadersAndBody(value);
|
|
817
|
+
if (direct) {
|
|
818
|
+
for (const [key, val] of Object.entries(direct.headers || {})) {
|
|
819
|
+
headers.set(key, val);
|
|
820
|
+
}
|
|
821
|
+
return new Response(direct.body, {
|
|
822
|
+
status,
|
|
823
|
+
headers
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
if (value === undefined) {
|
|
827
|
+
return new Response(null, {
|
|
828
|
+
status,
|
|
829
|
+
headers
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
try {
|
|
833
|
+
if (isJSONSafe(value)) {
|
|
834
|
+
headers.set(BODY_FORMAT_HEADER, BodyFormat.Json);
|
|
835
|
+
headers.set("Content-Type", "application/json");
|
|
836
|
+
return new Response(JSON.stringify(value), {
|
|
837
|
+
status,
|
|
838
|
+
headers
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
} catch {
|
|
842
|
+
}
|
|
843
|
+
const response = serializedResponse(value, headers, codec);
|
|
844
|
+
return status === 200 ? response : new Response(response.body, {
|
|
845
|
+
status,
|
|
846
|
+
headers
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
const GENERIC_SERVER_ERROR_MESSAGE = "Internal Server Error";
|
|
850
|
+
let DEV = true === true;
|
|
851
|
+
function setServerFunctionsDev(dev) {
|
|
852
|
+
DEV = !!dev;
|
|
853
|
+
}
|
|
854
|
+
function sanitizeServerError(value) {
|
|
855
|
+
if (DEV) return value;
|
|
856
|
+
if (isSafeError(value)) return value;
|
|
857
|
+
return new Error(GENERIC_SERVER_ERROR_MESSAGE);
|
|
858
|
+
}
|
|
859
|
+
async function handleServerFunctionRequest(request, options = {}) {
|
|
860
|
+
const codec = options.codec !== undefined ? options.codec : getServerFunctionsCodec();
|
|
861
|
+
const url = new URL(request.url);
|
|
862
|
+
const instance = request.headers.get(INSTANCE_HEADER);
|
|
863
|
+
const functionId = resolveFunctionId(request, url);
|
|
864
|
+
if (!functionId) {
|
|
865
|
+
return new Response(DEV ? "Server function not found" : null, {
|
|
866
|
+
status: 404
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
let serverFunction;
|
|
870
|
+
try {
|
|
871
|
+
serverFunction = getServerFunction(functionId);
|
|
872
|
+
} catch {
|
|
873
|
+
return new Response(DEV ? `Unknown server function: ${functionId}` : null, {
|
|
874
|
+
status: 404
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
if (request.method === "GET" && METHODS.get(functionId) !== "GET") {
|
|
878
|
+
return new Response(DEV ? `Method not allowed for server function: ${functionId}` : null, {
|
|
879
|
+
status: 405,
|
|
880
|
+
headers: {
|
|
881
|
+
Allow: "POST"
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
const event = options.createEvent ? options.createEvent(request) : {
|
|
886
|
+
request,
|
|
887
|
+
locals: {}
|
|
888
|
+
};
|
|
889
|
+
const provide = options.provideEvent || provideEvent;
|
|
890
|
+
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
891
|
+
const transformResult = options.transformResult !== undefined ? options.transformResult : config.transformResult;
|
|
892
|
+
const wrapInvocation = options.wrapInvocation !== undefined ? options.wrapInvocation : config.wrapInvocation;
|
|
893
|
+
const transformFlightResult = options.transformFlightResult !== undefined ? options.transformFlightResult : config.transformFlightResult;
|
|
894
|
+
const handleNoJS = options.handleNoJS !== undefined ? options.handleNoJS : config.handleNoJS !== undefined ? config.handleNoJS : isFormPost(request) ? defaultNoJSHandler || (defaultNoJSHandler = createNoJSHandler()) : undefined;
|
|
895
|
+
const collectsFlight = !!(flightHook && instance && request.headers.has(SINGLE_FLIGHT_HEADER));
|
|
896
|
+
const parsed = await parseArguments(request, url, instance, codec);
|
|
897
|
+
const flightContext = {
|
|
898
|
+
id: functionId,
|
|
899
|
+
args: parsed,
|
|
900
|
+
instance,
|
|
901
|
+
request,
|
|
902
|
+
collectsFlight,
|
|
903
|
+
codec,
|
|
904
|
+
transformFlightResult
|
|
905
|
+
};
|
|
906
|
+
const headers = new Headers();
|
|
907
|
+
const dispatch = async () => {
|
|
908
|
+
try {
|
|
909
|
+
let result = await provide(event, async () => {
|
|
910
|
+
INVOCATIONS.set(event, {
|
|
911
|
+
id: functionId
|
|
912
|
+
});
|
|
913
|
+
const run = () => serverFunction(...parsed);
|
|
914
|
+
return wrapInvocation ? wrapInvocation(run, {
|
|
915
|
+
id: functionId,
|
|
916
|
+
args: parsed,
|
|
917
|
+
event,
|
|
918
|
+
request,
|
|
919
|
+
direct: false
|
|
920
|
+
}) : run();
|
|
921
|
+
});
|
|
922
|
+
if (transformResult) {
|
|
923
|
+
result = await transformResult(event, result, flightContext);
|
|
924
|
+
}
|
|
925
|
+
let status = 200;
|
|
926
|
+
let metadata;
|
|
927
|
+
if (isResponseEnvelope(result)) {
|
|
928
|
+
const {
|
|
929
|
+
response,
|
|
930
|
+
value
|
|
931
|
+
} = result;
|
|
932
|
+
if (!instance && !handleNoJS && response && response.body) {
|
|
933
|
+
return response;
|
|
934
|
+
}
|
|
935
|
+
if (response && response.headers) {
|
|
936
|
+
mergeResponseHeaders(headers, response.headers);
|
|
937
|
+
}
|
|
938
|
+
if (response && response.status && (response.status < 300 || response.status >= 400)) {
|
|
939
|
+
status = response.status;
|
|
940
|
+
}
|
|
941
|
+
metadata = response;
|
|
942
|
+
result = value;
|
|
943
|
+
} else if (result instanceof Response) {
|
|
944
|
+
if (result.headers && result.headers.has("X-Content-Raw")) return result;
|
|
945
|
+
if (instance) {
|
|
946
|
+
if (result.headers) {
|
|
947
|
+
mergeResponseHeaders(headers, result.headers);
|
|
948
|
+
}
|
|
949
|
+
if (result.status && (result.status < 300 || result.status >= 400)) {
|
|
950
|
+
status = result.status;
|
|
951
|
+
}
|
|
952
|
+
metadata = result;
|
|
953
|
+
if (result.body == null) {
|
|
954
|
+
result = null;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
if (collectsFlight) {
|
|
959
|
+
result = await foldFlightData(flightHook, event, headers, {
|
|
960
|
+
id: functionId,
|
|
961
|
+
value: result,
|
|
962
|
+
response: metadata,
|
|
963
|
+
request,
|
|
964
|
+
thrown: false
|
|
965
|
+
}, flightContext);
|
|
966
|
+
if (result instanceof Response && result.headers.has("X-Content-Raw")) return result;
|
|
967
|
+
}
|
|
968
|
+
if (!instance) {
|
|
969
|
+
if (handleNoJS) return handleNoJS(result, request, parsed);
|
|
970
|
+
if (result instanceof Response) return result;
|
|
971
|
+
return encodeResult(result, headers, 200, codec);
|
|
972
|
+
}
|
|
973
|
+
return encodeResult(result, headers, status, codec);
|
|
974
|
+
} catch (x) {
|
|
975
|
+
if (x instanceof Response || isResponseEnvelope(x)) {
|
|
976
|
+
if (transformResult) {
|
|
977
|
+
x = await transformResult(event, x, {
|
|
978
|
+
...flightContext,
|
|
979
|
+
thrown: true
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
let status = 200;
|
|
983
|
+
let metadata;
|
|
984
|
+
if (isResponseEnvelope(x)) {
|
|
985
|
+
const {
|
|
986
|
+
response,
|
|
987
|
+
value
|
|
988
|
+
} = x;
|
|
989
|
+
if (response && response.headers) {
|
|
990
|
+
mergeResponseHeaders(headers, response.headers);
|
|
991
|
+
}
|
|
992
|
+
if (response && response.status && (!instance || response.status < 300 || response.status >= 400)) {
|
|
993
|
+
status = response.status;
|
|
994
|
+
}
|
|
995
|
+
metadata = response;
|
|
996
|
+
x = value;
|
|
997
|
+
} else if (x instanceof Response) {
|
|
998
|
+
if (x.headers) {
|
|
999
|
+
mergeResponseHeaders(headers, x.headers);
|
|
1000
|
+
}
|
|
1001
|
+
if (x.status && (!instance || x.status < 300 || x.status >= 400)) {
|
|
1002
|
+
status = x.status;
|
|
1003
|
+
}
|
|
1004
|
+
metadata = x;
|
|
1005
|
+
if (x.body == null) {
|
|
1006
|
+
x = null;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (collectsFlight) {
|
|
1010
|
+
x = await foldFlightData(flightHook, event, headers, {
|
|
1011
|
+
id: functionId,
|
|
1012
|
+
value: x,
|
|
1013
|
+
response: metadata,
|
|
1014
|
+
request,
|
|
1015
|
+
thrown: true
|
|
1016
|
+
}, flightContext);
|
|
1017
|
+
if (x instanceof Response && x.headers.has("X-Content-Raw")) {
|
|
1018
|
+
x.headers.set(ERROR_HEADER, "true");
|
|
1019
|
+
return x;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
headers.set(ERROR_HEADER, "true");
|
|
1023
|
+
if (!instance) {
|
|
1024
|
+
if (handleNoJS) return handleNoJS(x ?? metadata, request, parsed, true);
|
|
1025
|
+
if (x instanceof Response) return x;
|
|
1026
|
+
}
|
|
1027
|
+
return encodeResult(x, headers, status, codec);
|
|
1028
|
+
}
|
|
1029
|
+
const safe = sanitizeServerError(x);
|
|
1030
|
+
if (!instance) {
|
|
1031
|
+
if (handleNoJS) return handleNoJS(safe, request, parsed, true);
|
|
1032
|
+
const message = safe instanceof Error ? safe.message : String(safe);
|
|
1033
|
+
return new Response(DEV ? message : null, {
|
|
1034
|
+
status: 500
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
const error = safe instanceof Error ? safe.message : typeof safe === "string" ? safe : "true";
|
|
1038
|
+
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error));
|
|
1039
|
+
return encodeResult(safe, headers, 200, codec);
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
return commitEventResponse(await dispatch(), event);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
export { ERROR_HEADER, FLASH_COOKIE, FUNCTION_HEADER, GENERIC_SERVER_ERROR_MESSAGE, GET, INSTANCE_HEADER, SINGLE_FLIGHT_HEADER, clearFlashCookie, configureServerFunctionsServer, createNoJSHandler, createServerReference, decodeErrorHeaderValue, decodeFlashCookie, decodeResponse, decodeResponsePayload, encodeErrorHeaderValue, encodeFlashCookie, foldSetCookies, getEventServerFunctionInvocation, getServerFunction, getServerFunctionInvocation, getServerFunctionMetadata, handleServerFunctionRequest, hasFlashCookie, isServerFunction, registerServerFunction, registerServerReference, sanitizeServerError, setServerFunctionsDev, subscribeFlightData, withMeta };
|