@sveltejs/kit 1.0.0-next.99 → 1.0.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 +5 -1
- package/package.json +91 -77
- package/postinstall.js +47 -0
- package/src/cli.js +44 -0
- package/src/constants.js +5 -0
- package/src/core/adapt/builder.js +221 -0
- package/src/core/adapt/index.js +31 -0
- package/src/core/config/default-error.html +56 -0
- package/src/core/config/index.js +100 -0
- package/src/core/config/options.js +387 -0
- package/src/core/config/types.d.ts +1 -0
- package/src/core/env.js +138 -0
- package/src/core/generate_manifest/index.js +116 -0
- package/src/core/prerender/crawl.js +207 -0
- package/src/core/prerender/entities.js +2252 -0
- package/src/core/prerender/fallback.js +43 -0
- package/src/core/prerender/prerender.js +459 -0
- package/src/core/prerender/queue.js +80 -0
- package/src/core/sync/create_manifest_data/conflict.js +0 -0
- package/src/core/sync/create_manifest_data/index.js +523 -0
- package/src/core/sync/create_manifest_data/sort.js +161 -0
- package/src/core/sync/create_manifest_data/types.d.ts +37 -0
- package/src/core/sync/sync.js +59 -0
- package/src/core/sync/utils.js +33 -0
- package/src/core/sync/write_ambient.js +58 -0
- package/src/core/sync/write_client_manifest.js +107 -0
- package/src/core/sync/write_matchers.js +25 -0
- package/src/core/sync/write_root.js +91 -0
- package/src/core/sync/write_tsconfig.js +195 -0
- package/src/core/sync/write_types/index.js +809 -0
- package/src/core/utils.js +67 -0
- package/src/exports/hooks/index.js +1 -0
- package/src/exports/hooks/sequence.js +44 -0
- package/src/exports/index.js +55 -0
- package/src/exports/node/index.js +172 -0
- package/src/exports/node/polyfills.js +28 -0
- package/src/exports/vite/build/build_server.js +359 -0
- package/src/exports/vite/build/build_service_worker.js +85 -0
- package/src/exports/vite/build/utils.js +230 -0
- package/src/exports/vite/dev/index.js +597 -0
- package/src/exports/vite/graph_analysis/index.js +99 -0
- package/src/exports/vite/graph_analysis/types.d.ts +5 -0
- package/src/exports/vite/graph_analysis/utils.js +6 -0
- package/src/exports/vite/index.js +708 -0
- package/src/exports/vite/preview/index.js +194 -0
- package/src/exports/vite/types.d.ts +3 -0
- package/src/exports/vite/utils.js +184 -0
- package/src/runtime/app/env.js +1 -0
- package/src/runtime/app/environment.js +13 -0
- package/src/runtime/app/forms.js +135 -0
- package/src/runtime/app/navigation.js +22 -0
- package/src/runtime/app/paths.js +1 -0
- package/src/runtime/app/stores.js +57 -0
- package/src/runtime/client/ambient.d.ts +30 -0
- package/src/runtime/client/client.js +1725 -0
- package/src/runtime/client/constants.js +10 -0
- package/src/runtime/client/fetcher.js +127 -0
- package/src/runtime/client/parse.js +60 -0
- package/src/runtime/client/singletons.js +21 -0
- package/src/runtime/client/start.js +45 -0
- package/src/runtime/client/types.d.ts +86 -0
- package/src/runtime/client/utils.js +257 -0
- package/src/runtime/components/error.svelte +6 -0
- package/{assets → src/runtime}/components/layout.svelte +0 -0
- package/src/runtime/control.js +45 -0
- package/src/runtime/env/dynamic/private.js +1 -0
- package/src/runtime/env/dynamic/public.js +1 -0
- package/src/runtime/env-private.js +6 -0
- package/src/runtime/env-public.js +6 -0
- package/src/runtime/env.js +12 -0
- package/src/runtime/hash.js +20 -0
- package/src/runtime/paths.js +11 -0
- package/src/runtime/server/cookie.js +228 -0
- package/src/runtime/server/data/index.js +158 -0
- package/src/runtime/server/endpoint.js +86 -0
- package/src/runtime/server/fetch.js +175 -0
- package/src/runtime/server/index.js +405 -0
- package/src/runtime/server/page/actions.js +267 -0
- package/src/runtime/server/page/crypto.js +239 -0
- package/src/runtime/server/page/csp.js +250 -0
- package/src/runtime/server/page/index.js +326 -0
- package/src/runtime/server/page/load_data.js +270 -0
- package/src/runtime/server/page/render.js +393 -0
- package/src/runtime/server/page/respond_with_error.js +103 -0
- package/src/runtime/server/page/serialize_data.js +87 -0
- package/src/runtime/server/page/types.d.ts +35 -0
- package/src/runtime/server/utils.js +179 -0
- package/src/utils/array.js +9 -0
- package/src/utils/error.js +22 -0
- package/src/utils/escape.js +46 -0
- package/src/utils/exports.js +54 -0
- package/src/utils/filesystem.js +178 -0
- package/src/utils/functions.js +16 -0
- package/src/utils/http.js +72 -0
- package/src/utils/misc.js +1 -0
- package/src/utils/promises.js +17 -0
- package/src/utils/routing.js +201 -0
- package/src/utils/unit_test.js +11 -0
- package/src/utils/url.js +161 -0
- package/svelte-kit.js +1 -1
- package/types/ambient.d.ts +451 -0
- package/types/index.d.ts +1168 -5
- package/types/internal.d.ts +348 -159
- package/types/private.d.ts +237 -0
- package/types/synthetic/$env+dynamic+private.md +10 -0
- package/types/synthetic/$env+dynamic+public.md +8 -0
- package/types/synthetic/$env+static+private.md +19 -0
- package/types/synthetic/$env+static+public.md +7 -0
- package/types/synthetic/$lib.md +5 -0
- package/CHANGELOG.md +0 -825
- package/assets/components/error.svelte +0 -21
- package/assets/runtime/app/env.js +0 -16
- package/assets/runtime/app/navigation.js +0 -53
- package/assets/runtime/app/paths.js +0 -1
- package/assets/runtime/app/stores.js +0 -87
- package/assets/runtime/chunks/utils.js +0 -13
- package/assets/runtime/env.js +0 -8
- package/assets/runtime/internal/singletons.js +0 -20
- package/assets/runtime/internal/start.js +0 -1061
- package/assets/runtime/paths.js +0 -12
- package/dist/chunks/_commonjsHelpers.js +0 -8
- package/dist/chunks/cert.js +0 -29079
- package/dist/chunks/constants.js +0 -3
- package/dist/chunks/index.js +0 -3532
- package/dist/chunks/index2.js +0 -583
- package/dist/chunks/index3.js +0 -31
- package/dist/chunks/index4.js +0 -1004
- package/dist/chunks/index5.js +0 -327
- package/dist/chunks/index6.js +0 -325
- package/dist/chunks/standard.js +0 -99
- package/dist/chunks/utils.js +0 -149
- package/dist/cli.js +0 -711
- package/dist/http.js +0 -66
- package/dist/install-fetch.js +0 -1699
- package/dist/ssr.js +0 -1523
- package/types/ambient-modules.d.ts +0 -115
- package/types/config.d.ts +0 -101
- package/types/endpoint.d.ts +0 -23
- package/types/helper.d.ts +0 -19
- package/types/hooks.d.ts +0 -21
- package/types/page.d.ts +0 -30
package/dist/ssr.js
DELETED
|
@@ -1,1523 +0,0 @@
|
|
|
1
|
-
var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
|
|
2
|
-
var unsafeChars = /[<>\b\f\n\r\t\0\u2028\u2029]/g;
|
|
3
|
-
var reserved = /^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/;
|
|
4
|
-
var escaped$1 = {
|
|
5
|
-
'<': '\\u003C',
|
|
6
|
-
'>': '\\u003E',
|
|
7
|
-
'/': '\\u002F',
|
|
8
|
-
'\\': '\\\\',
|
|
9
|
-
'\b': '\\b',
|
|
10
|
-
'\f': '\\f',
|
|
11
|
-
'\n': '\\n',
|
|
12
|
-
'\r': '\\r',
|
|
13
|
-
'\t': '\\t',
|
|
14
|
-
'\0': '\\0',
|
|
15
|
-
'\u2028': '\\u2028',
|
|
16
|
-
'\u2029': '\\u2029'
|
|
17
|
-
};
|
|
18
|
-
var objectProtoOwnPropertyNames = Object.getOwnPropertyNames(Object.prototype).sort().join('\0');
|
|
19
|
-
function devalue(value) {
|
|
20
|
-
var counts = new Map();
|
|
21
|
-
function walk(thing) {
|
|
22
|
-
if (typeof thing === 'function') {
|
|
23
|
-
throw new Error("Cannot stringify a function");
|
|
24
|
-
}
|
|
25
|
-
if (counts.has(thing)) {
|
|
26
|
-
counts.set(thing, counts.get(thing) + 1);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
counts.set(thing, 1);
|
|
30
|
-
if (!isPrimitive(thing)) {
|
|
31
|
-
var type = getType(thing);
|
|
32
|
-
switch (type) {
|
|
33
|
-
case 'Number':
|
|
34
|
-
case 'String':
|
|
35
|
-
case 'Boolean':
|
|
36
|
-
case 'Date':
|
|
37
|
-
case 'RegExp':
|
|
38
|
-
return;
|
|
39
|
-
case 'Array':
|
|
40
|
-
thing.forEach(walk);
|
|
41
|
-
break;
|
|
42
|
-
case 'Set':
|
|
43
|
-
case 'Map':
|
|
44
|
-
Array.from(thing).forEach(walk);
|
|
45
|
-
break;
|
|
46
|
-
default:
|
|
47
|
-
var proto = Object.getPrototypeOf(thing);
|
|
48
|
-
if (proto !== Object.prototype &&
|
|
49
|
-
proto !== null &&
|
|
50
|
-
Object.getOwnPropertyNames(proto).sort().join('\0') !== objectProtoOwnPropertyNames) {
|
|
51
|
-
throw new Error("Cannot stringify arbitrary non-POJOs");
|
|
52
|
-
}
|
|
53
|
-
if (Object.getOwnPropertySymbols(thing).length > 0) {
|
|
54
|
-
throw new Error("Cannot stringify POJOs with symbolic keys");
|
|
55
|
-
}
|
|
56
|
-
Object.keys(thing).forEach(function (key) { return walk(thing[key]); });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
walk(value);
|
|
61
|
-
var names = new Map();
|
|
62
|
-
Array.from(counts)
|
|
63
|
-
.filter(function (entry) { return entry[1] > 1; })
|
|
64
|
-
.sort(function (a, b) { return b[1] - a[1]; })
|
|
65
|
-
.forEach(function (entry, i) {
|
|
66
|
-
names.set(entry[0], getName(i));
|
|
67
|
-
});
|
|
68
|
-
function stringify(thing) {
|
|
69
|
-
if (names.has(thing)) {
|
|
70
|
-
return names.get(thing);
|
|
71
|
-
}
|
|
72
|
-
if (isPrimitive(thing)) {
|
|
73
|
-
return stringifyPrimitive(thing);
|
|
74
|
-
}
|
|
75
|
-
var type = getType(thing);
|
|
76
|
-
switch (type) {
|
|
77
|
-
case 'Number':
|
|
78
|
-
case 'String':
|
|
79
|
-
case 'Boolean':
|
|
80
|
-
return "Object(" + stringify(thing.valueOf()) + ")";
|
|
81
|
-
case 'RegExp':
|
|
82
|
-
return "new RegExp(" + stringifyString(thing.source) + ", \"" + thing.flags + "\")";
|
|
83
|
-
case 'Date':
|
|
84
|
-
return "new Date(" + thing.getTime() + ")";
|
|
85
|
-
case 'Array':
|
|
86
|
-
var members = thing.map(function (v, i) { return i in thing ? stringify(v) : ''; });
|
|
87
|
-
var tail = thing.length === 0 || (thing.length - 1 in thing) ? '' : ',';
|
|
88
|
-
return "[" + members.join(',') + tail + "]";
|
|
89
|
-
case 'Set':
|
|
90
|
-
case 'Map':
|
|
91
|
-
return "new " + type + "([" + Array.from(thing).map(stringify).join(',') + "])";
|
|
92
|
-
default:
|
|
93
|
-
var obj = "{" + Object.keys(thing).map(function (key) { return safeKey(key) + ":" + stringify(thing[key]); }).join(',') + "}";
|
|
94
|
-
var proto = Object.getPrototypeOf(thing);
|
|
95
|
-
if (proto === null) {
|
|
96
|
-
return Object.keys(thing).length > 0
|
|
97
|
-
? "Object.assign(Object.create(null)," + obj + ")"
|
|
98
|
-
: "Object.create(null)";
|
|
99
|
-
}
|
|
100
|
-
return obj;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
var str = stringify(value);
|
|
104
|
-
if (names.size) {
|
|
105
|
-
var params_1 = [];
|
|
106
|
-
var statements_1 = [];
|
|
107
|
-
var values_1 = [];
|
|
108
|
-
names.forEach(function (name, thing) {
|
|
109
|
-
params_1.push(name);
|
|
110
|
-
if (isPrimitive(thing)) {
|
|
111
|
-
values_1.push(stringifyPrimitive(thing));
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
var type = getType(thing);
|
|
115
|
-
switch (type) {
|
|
116
|
-
case 'Number':
|
|
117
|
-
case 'String':
|
|
118
|
-
case 'Boolean':
|
|
119
|
-
values_1.push("Object(" + stringify(thing.valueOf()) + ")");
|
|
120
|
-
break;
|
|
121
|
-
case 'RegExp':
|
|
122
|
-
values_1.push(thing.toString());
|
|
123
|
-
break;
|
|
124
|
-
case 'Date':
|
|
125
|
-
values_1.push("new Date(" + thing.getTime() + ")");
|
|
126
|
-
break;
|
|
127
|
-
case 'Array':
|
|
128
|
-
values_1.push("Array(" + thing.length + ")");
|
|
129
|
-
thing.forEach(function (v, i) {
|
|
130
|
-
statements_1.push(name + "[" + i + "]=" + stringify(v));
|
|
131
|
-
});
|
|
132
|
-
break;
|
|
133
|
-
case 'Set':
|
|
134
|
-
values_1.push("new Set");
|
|
135
|
-
statements_1.push(name + "." + Array.from(thing).map(function (v) { return "add(" + stringify(v) + ")"; }).join('.'));
|
|
136
|
-
break;
|
|
137
|
-
case 'Map':
|
|
138
|
-
values_1.push("new Map");
|
|
139
|
-
statements_1.push(name + "." + Array.from(thing).map(function (_a) {
|
|
140
|
-
var k = _a[0], v = _a[1];
|
|
141
|
-
return "set(" + stringify(k) + ", " + stringify(v) + ")";
|
|
142
|
-
}).join('.'));
|
|
143
|
-
break;
|
|
144
|
-
default:
|
|
145
|
-
values_1.push(Object.getPrototypeOf(thing) === null ? 'Object.create(null)' : '{}');
|
|
146
|
-
Object.keys(thing).forEach(function (key) {
|
|
147
|
-
statements_1.push("" + name + safeProp(key) + "=" + stringify(thing[key]));
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
statements_1.push("return " + str);
|
|
152
|
-
return "(function(" + params_1.join(',') + "){" + statements_1.join(';') + "}(" + values_1.join(',') + "))";
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
return str;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
function getName(num) {
|
|
159
|
-
var name = '';
|
|
160
|
-
do {
|
|
161
|
-
name = chars[num % chars.length] + name;
|
|
162
|
-
num = ~~(num / chars.length) - 1;
|
|
163
|
-
} while (num >= 0);
|
|
164
|
-
return reserved.test(name) ? name + "_" : name;
|
|
165
|
-
}
|
|
166
|
-
function isPrimitive(thing) {
|
|
167
|
-
return Object(thing) !== thing;
|
|
168
|
-
}
|
|
169
|
-
function stringifyPrimitive(thing) {
|
|
170
|
-
if (typeof thing === 'string')
|
|
171
|
-
return stringifyString(thing);
|
|
172
|
-
if (thing === void 0)
|
|
173
|
-
return 'void 0';
|
|
174
|
-
if (thing === 0 && 1 / thing < 0)
|
|
175
|
-
return '-0';
|
|
176
|
-
var str = String(thing);
|
|
177
|
-
if (typeof thing === 'number')
|
|
178
|
-
return str.replace(/^(-)?0\./, '$1.');
|
|
179
|
-
return str;
|
|
180
|
-
}
|
|
181
|
-
function getType(thing) {
|
|
182
|
-
return Object.prototype.toString.call(thing).slice(8, -1);
|
|
183
|
-
}
|
|
184
|
-
function escapeUnsafeChar(c) {
|
|
185
|
-
return escaped$1[c] || c;
|
|
186
|
-
}
|
|
187
|
-
function escapeUnsafeChars(str) {
|
|
188
|
-
return str.replace(unsafeChars, escapeUnsafeChar);
|
|
189
|
-
}
|
|
190
|
-
function safeKey(key) {
|
|
191
|
-
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : escapeUnsafeChars(JSON.stringify(key));
|
|
192
|
-
}
|
|
193
|
-
function safeProp(key) {
|
|
194
|
-
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? "." + key : "[" + escapeUnsafeChars(JSON.stringify(key)) + "]";
|
|
195
|
-
}
|
|
196
|
-
function stringifyString(str) {
|
|
197
|
-
var result = '"';
|
|
198
|
-
for (var i = 0; i < str.length; i += 1) {
|
|
199
|
-
var char = str.charAt(i);
|
|
200
|
-
var code = char.charCodeAt(0);
|
|
201
|
-
if (char === '"') {
|
|
202
|
-
result += '\\"';
|
|
203
|
-
}
|
|
204
|
-
else if (char in escaped$1) {
|
|
205
|
-
result += escaped$1[char];
|
|
206
|
-
}
|
|
207
|
-
else if (code >= 0xd800 && code <= 0xdfff) {
|
|
208
|
-
var next = str.charCodeAt(i + 1);
|
|
209
|
-
// If this is the beginning of a [high, low] surrogate pair,
|
|
210
|
-
// add the next two characters, otherwise escape
|
|
211
|
-
if (code <= 0xdbff && (next >= 0xdc00 && next <= 0xdfff)) {
|
|
212
|
-
result += char + str[++i];
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
result += "\\u" + code.toString(16).toUpperCase();
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
result += char;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
result += '"';
|
|
223
|
-
return result;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function noop() { }
|
|
227
|
-
function safe_not_equal(a, b) {
|
|
228
|
-
return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const subscriber_queue = [];
|
|
232
|
-
/**
|
|
233
|
-
* Create a `Writable` store that allows both updating and reading by subscription.
|
|
234
|
-
* @param {*=}value initial value
|
|
235
|
-
* @param {StartStopNotifier=}start start and stop notifications for subscriptions
|
|
236
|
-
*/
|
|
237
|
-
function writable(value, start = noop) {
|
|
238
|
-
let stop;
|
|
239
|
-
const subscribers = [];
|
|
240
|
-
function set(new_value) {
|
|
241
|
-
if (safe_not_equal(value, new_value)) {
|
|
242
|
-
value = new_value;
|
|
243
|
-
if (stop) { // store is ready
|
|
244
|
-
const run_queue = !subscriber_queue.length;
|
|
245
|
-
for (let i = 0; i < subscribers.length; i += 1) {
|
|
246
|
-
const s = subscribers[i];
|
|
247
|
-
s[1]();
|
|
248
|
-
subscriber_queue.push(s, value);
|
|
249
|
-
}
|
|
250
|
-
if (run_queue) {
|
|
251
|
-
for (let i = 0; i < subscriber_queue.length; i += 2) {
|
|
252
|
-
subscriber_queue[i][0](subscriber_queue[i + 1]);
|
|
253
|
-
}
|
|
254
|
-
subscriber_queue.length = 0;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
function update(fn) {
|
|
260
|
-
set(fn(value));
|
|
261
|
-
}
|
|
262
|
-
function subscribe(run, invalidate = noop) {
|
|
263
|
-
const subscriber = [run, invalidate];
|
|
264
|
-
subscribers.push(subscriber);
|
|
265
|
-
if (subscribers.length === 1) {
|
|
266
|
-
stop = start(set) || noop;
|
|
267
|
-
}
|
|
268
|
-
run(value);
|
|
269
|
-
return () => {
|
|
270
|
-
const index = subscribers.indexOf(subscriber);
|
|
271
|
-
if (index !== -1) {
|
|
272
|
-
subscribers.splice(index, 1);
|
|
273
|
-
}
|
|
274
|
-
if (subscribers.length === 0) {
|
|
275
|
-
stop();
|
|
276
|
-
stop = null;
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
return { set, update, subscribe };
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const s$1 = JSON.stringify;
|
|
284
|
-
|
|
285
|
-
// TODO rename this function/module
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* @param {{
|
|
289
|
-
* options: import('types/internal').SSRRenderOptions;
|
|
290
|
-
* $session: any;
|
|
291
|
-
* page_config: { hydrate: boolean, router: boolean, ssr: boolean };
|
|
292
|
-
* status: number;
|
|
293
|
-
* error: Error,
|
|
294
|
-
* branch: import('./types').Loaded[];
|
|
295
|
-
* page: import('types/page').Page
|
|
296
|
-
* }} opts
|
|
297
|
-
*/
|
|
298
|
-
async function render_response({
|
|
299
|
-
options,
|
|
300
|
-
$session,
|
|
301
|
-
page_config,
|
|
302
|
-
status,
|
|
303
|
-
error,
|
|
304
|
-
branch,
|
|
305
|
-
page
|
|
306
|
-
}) {
|
|
307
|
-
const css = new Set(options.entry.css);
|
|
308
|
-
const js = new Set(options.entry.js);
|
|
309
|
-
const styles = new Set();
|
|
310
|
-
|
|
311
|
-
/** @type {Array<{ url: string, json: string }>} */
|
|
312
|
-
const serialized_data = [];
|
|
313
|
-
|
|
314
|
-
let rendered;
|
|
315
|
-
|
|
316
|
-
let is_private = false;
|
|
317
|
-
let maxage;
|
|
318
|
-
|
|
319
|
-
if (error) {
|
|
320
|
-
error.stack = options.get_stack(error);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
if (branch) {
|
|
324
|
-
branch.forEach(({ node, loaded, fetched, uses_credentials }) => {
|
|
325
|
-
if (node.css) node.css.forEach((url) => css.add(url));
|
|
326
|
-
if (node.js) node.js.forEach((url) => js.add(url));
|
|
327
|
-
if (node.styles) node.styles.forEach((content) => styles.add(content));
|
|
328
|
-
|
|
329
|
-
// TODO probably better if `fetched` wasn't populated unless `hydrate`
|
|
330
|
-
if (fetched && page_config.hydrate) serialized_data.push(...fetched);
|
|
331
|
-
|
|
332
|
-
if (uses_credentials) is_private = true;
|
|
333
|
-
|
|
334
|
-
maxage = loaded.maxage;
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
const session = writable($session);
|
|
338
|
-
|
|
339
|
-
/** @type {Record<string, any>} */
|
|
340
|
-
const props = {
|
|
341
|
-
stores: {
|
|
342
|
-
page: writable(null),
|
|
343
|
-
navigating: writable(null),
|
|
344
|
-
session
|
|
345
|
-
},
|
|
346
|
-
page,
|
|
347
|
-
components: branch.map(({ node }) => node.module.default)
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
// props_n (instead of props[n]) makes it easy to avoid
|
|
351
|
-
// unnecessary updates for layout components
|
|
352
|
-
for (let i = 0; i < branch.length; i += 1) {
|
|
353
|
-
props[`props_${i}`] = await branch[i].loaded.props;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
let session_tracking_active = false;
|
|
357
|
-
const unsubscribe = session.subscribe(() => {
|
|
358
|
-
if (session_tracking_active) is_private = true;
|
|
359
|
-
});
|
|
360
|
-
session_tracking_active = true;
|
|
361
|
-
|
|
362
|
-
try {
|
|
363
|
-
rendered = options.root.render(props);
|
|
364
|
-
} finally {
|
|
365
|
-
unsubscribe();
|
|
366
|
-
}
|
|
367
|
-
} else {
|
|
368
|
-
rendered = { head: '', html: '', css: '' };
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const include_js = page_config.router || page_config.hydrate;
|
|
372
|
-
if (!include_js) js.clear();
|
|
373
|
-
|
|
374
|
-
// TODO strip the AMP stuff out of the build if not relevant
|
|
375
|
-
const links = options.amp
|
|
376
|
-
? styles.size > 0
|
|
377
|
-
? `<style amp-custom>${Array.from(styles).join('\n')}</style>`
|
|
378
|
-
: ''
|
|
379
|
-
: [
|
|
380
|
-
...Array.from(js).map((dep) => `<link rel="modulepreload" href="${dep}">`),
|
|
381
|
-
...Array.from(css).map((dep) => `<link rel="stylesheet" href="${dep}">`)
|
|
382
|
-
].join('\n\t\t');
|
|
383
|
-
|
|
384
|
-
/** @type {string} */
|
|
385
|
-
let init = '';
|
|
386
|
-
|
|
387
|
-
if (options.amp) {
|
|
388
|
-
init = `
|
|
389
|
-
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
|
|
390
|
-
<noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
|
|
391
|
-
<script async src="https://cdn.ampproject.org/v0.js"></script>`;
|
|
392
|
-
} else if (include_js) {
|
|
393
|
-
// prettier-ignore
|
|
394
|
-
init = `<script type="module">
|
|
395
|
-
import { start } from ${s$1(options.entry.file)};
|
|
396
|
-
start({
|
|
397
|
-
target: ${options.target ? `document.querySelector(${s$1(options.target)})` : 'document.body'},
|
|
398
|
-
paths: ${s$1(options.paths)},
|
|
399
|
-
session: ${try_serialize($session, (error) => {
|
|
400
|
-
throw new Error(`Failed to serialize session data: ${error.message}`);
|
|
401
|
-
})},
|
|
402
|
-
host: ${page && page.host ? s$1(page.host) : 'location.host'},
|
|
403
|
-
route: ${!!page_config.router},
|
|
404
|
-
spa: ${!page_config.ssr},
|
|
405
|
-
hydrate: ${page_config.ssr && page_config.hydrate? `{
|
|
406
|
-
status: ${status},
|
|
407
|
-
error: ${serialize_error(error)},
|
|
408
|
-
nodes: [
|
|
409
|
-
${branch
|
|
410
|
-
.map(({ node }) => `import(${s$1(node.entry)})`)
|
|
411
|
-
.join(',\n\t\t\t\t\t\t')}
|
|
412
|
-
],
|
|
413
|
-
page: {
|
|
414
|
-
host: ${page.host ? s$1(page.host) : 'location.host'}, // TODO this is redundant
|
|
415
|
-
path: ${s$1(page.path)},
|
|
416
|
-
query: new URLSearchParams(${s$1(page.query.toString())}),
|
|
417
|
-
params: ${s$1(page.params)}
|
|
418
|
-
}
|
|
419
|
-
}` : 'null'}
|
|
420
|
-
});
|
|
421
|
-
</script>`;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
const head = [
|
|
425
|
-
rendered.head,
|
|
426
|
-
styles.size && !options.amp
|
|
427
|
-
? `<style data-svelte>${Array.from(styles).join('\n')}</style>`
|
|
428
|
-
: '',
|
|
429
|
-
links,
|
|
430
|
-
init
|
|
431
|
-
].join('\n\n\t\t');
|
|
432
|
-
|
|
433
|
-
const body = options.amp
|
|
434
|
-
? rendered.html
|
|
435
|
-
: `${rendered.html}
|
|
436
|
-
|
|
437
|
-
${serialized_data
|
|
438
|
-
.map(({ url, json }) => `<script type="svelte-data" url="${url}">${json}</script>`)
|
|
439
|
-
.join('\n\n\t\t\t')}
|
|
440
|
-
`.replace(/^\t{2}/gm, '');
|
|
441
|
-
|
|
442
|
-
/** @type {import('types/helper').Headers} */
|
|
443
|
-
const headers = {
|
|
444
|
-
'content-type': 'text/html'
|
|
445
|
-
};
|
|
446
|
-
|
|
447
|
-
if (maxage) {
|
|
448
|
-
headers['cache-control'] = `${is_private ? 'private' : 'public'}, max-age=${maxage}`;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
if (!options.floc) {
|
|
452
|
-
headers['permissions-policy'] = 'interest-cohort=()';
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
return {
|
|
456
|
-
status,
|
|
457
|
-
headers,
|
|
458
|
-
body: options.template({ head, body })
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* @param {any} data
|
|
464
|
-
* @param {(error: Error) => void} [fail]
|
|
465
|
-
*/
|
|
466
|
-
function try_serialize(data, fail) {
|
|
467
|
-
try {
|
|
468
|
-
return devalue(data);
|
|
469
|
-
} catch (err) {
|
|
470
|
-
if (fail) fail(err);
|
|
471
|
-
return null;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Ensure we return something truthy so the client will not re-render the page over the error
|
|
476
|
-
|
|
477
|
-
/** @param {Error} error */
|
|
478
|
-
function serialize_error(error) {
|
|
479
|
-
if (!error) return null;
|
|
480
|
-
let serialized = try_serialize(error);
|
|
481
|
-
if (!serialized) {
|
|
482
|
-
const { name, message, stack } = error;
|
|
483
|
-
serialized = try_serialize({ name, message, stack });
|
|
484
|
-
}
|
|
485
|
-
if (!serialized) {
|
|
486
|
-
serialized = '{}';
|
|
487
|
-
}
|
|
488
|
-
return serialized;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
/**
|
|
492
|
-
* @param {import('types/page').LoadOutput} loaded
|
|
493
|
-
* @returns {import('types/page').LoadOutput}
|
|
494
|
-
*/
|
|
495
|
-
function normalize(loaded) {
|
|
496
|
-
// TODO should this behaviour be dev-only?
|
|
497
|
-
|
|
498
|
-
if (loaded.error) {
|
|
499
|
-
const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error;
|
|
500
|
-
const status = loaded.status;
|
|
501
|
-
|
|
502
|
-
if (!(error instanceof Error)) {
|
|
503
|
-
return {
|
|
504
|
-
status: 500,
|
|
505
|
-
error: new Error(
|
|
506
|
-
`"error" property returned from load() must be a string or instance of Error, received type "${typeof error}"`
|
|
507
|
-
)
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
if (!status || status < 400 || status > 599) {
|
|
512
|
-
console.warn('"error" returned from load() without a valid status code — defaulting to 500');
|
|
513
|
-
return { status: 500, error };
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
return { status, error };
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (loaded.redirect) {
|
|
520
|
-
if (!loaded.status || Math.floor(loaded.status / 100) !== 3) {
|
|
521
|
-
return {
|
|
522
|
-
status: 500,
|
|
523
|
-
error: new Error(
|
|
524
|
-
'"redirect" property returned from load() must be accompanied by a 3xx status code'
|
|
525
|
-
)
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
if (typeof loaded.redirect !== 'string') {
|
|
530
|
-
return {
|
|
531
|
-
status: 500,
|
|
532
|
-
error: new Error('"redirect" property returned from load() must be a string')
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
return loaded;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* @param {string} base
|
|
542
|
-
* @param {string} path
|
|
543
|
-
*/
|
|
544
|
-
function resolve(base, path) {
|
|
545
|
-
const baseparts = path[0] === '/' ? [] : base.slice(1).split('/');
|
|
546
|
-
const pathparts = path[0] === '/' ? path.slice(1).split('/') : path.split('/');
|
|
547
|
-
|
|
548
|
-
baseparts.pop();
|
|
549
|
-
|
|
550
|
-
for (let i = 0; i < pathparts.length; i += 1) {
|
|
551
|
-
const part = pathparts[i];
|
|
552
|
-
if (part === '.') continue;
|
|
553
|
-
else if (part === '..') baseparts.pop();
|
|
554
|
-
else baseparts.push(part);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
return `/${baseparts.join('/')}`;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
const s = JSON.stringify;
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
*
|
|
564
|
-
* @param {{
|
|
565
|
-
* request: import('types/endpoint').ServerRequest;
|
|
566
|
-
* options: import('types/internal').SSRRenderOptions;
|
|
567
|
-
* state: import('types/internal').SSRRenderState;
|
|
568
|
-
* route: import('types/internal').SSRPage;
|
|
569
|
-
* page: import('types/page').Page;
|
|
570
|
-
* node: import('types/internal').SSRNode;
|
|
571
|
-
* $session: any;
|
|
572
|
-
* context: Record<string, any>;
|
|
573
|
-
* is_leaf: boolean;
|
|
574
|
-
* is_error: boolean;
|
|
575
|
-
* status?: number;
|
|
576
|
-
* error?: Error;
|
|
577
|
-
* }} opts
|
|
578
|
-
* @returns {Promise<import('./types').Loaded>}
|
|
579
|
-
*/
|
|
580
|
-
async function load_node({
|
|
581
|
-
request,
|
|
582
|
-
options,
|
|
583
|
-
state,
|
|
584
|
-
route,
|
|
585
|
-
page,
|
|
586
|
-
node,
|
|
587
|
-
$session,
|
|
588
|
-
context,
|
|
589
|
-
is_leaf,
|
|
590
|
-
is_error,
|
|
591
|
-
status,
|
|
592
|
-
error
|
|
593
|
-
}) {
|
|
594
|
-
const { module } = node;
|
|
595
|
-
|
|
596
|
-
let uses_credentials = false;
|
|
597
|
-
|
|
598
|
-
/** @type {Array<{
|
|
599
|
-
* url: string;
|
|
600
|
-
* json: string;
|
|
601
|
-
* }>} */
|
|
602
|
-
const fetched = [];
|
|
603
|
-
|
|
604
|
-
let loaded;
|
|
605
|
-
|
|
606
|
-
if (module.load) {
|
|
607
|
-
/** @type {import('types/page').LoadInput | import('types/page').ErrorLoadInput} */
|
|
608
|
-
const load_input = {
|
|
609
|
-
page,
|
|
610
|
-
get session() {
|
|
611
|
-
uses_credentials = true;
|
|
612
|
-
return $session;
|
|
613
|
-
},
|
|
614
|
-
/**
|
|
615
|
-
* @param {RequestInfo} resource
|
|
616
|
-
* @param {RequestInit} opts
|
|
617
|
-
*/
|
|
618
|
-
fetch: async (resource, opts = {}) => {
|
|
619
|
-
/** @type {string} */
|
|
620
|
-
let url;
|
|
621
|
-
|
|
622
|
-
if (typeof resource === 'string') {
|
|
623
|
-
url = resource;
|
|
624
|
-
} else {
|
|
625
|
-
url = resource.url;
|
|
626
|
-
|
|
627
|
-
opts = {
|
|
628
|
-
method: resource.method,
|
|
629
|
-
headers: resource.headers,
|
|
630
|
-
body: resource.body,
|
|
631
|
-
mode: resource.mode,
|
|
632
|
-
credentials: resource.credentials,
|
|
633
|
-
cache: resource.cache,
|
|
634
|
-
redirect: resource.redirect,
|
|
635
|
-
referrer: resource.referrer,
|
|
636
|
-
integrity: resource.integrity,
|
|
637
|
-
...opts
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
if (options.read && url.startsWith(options.paths.assets)) {
|
|
642
|
-
// when running `start`, or prerendering, `assets` should be
|
|
643
|
-
// config.kit.paths.assets, but we should still be able to fetch
|
|
644
|
-
// assets directly from `static`
|
|
645
|
-
url = url.replace(options.paths.assets, '');
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
if (url.startsWith('//')) {
|
|
649
|
-
throw new Error(`Cannot request protocol-relative URL (${url}) in server-side fetch`);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
let response;
|
|
653
|
-
|
|
654
|
-
if (/^[a-zA-Z]+:/.test(url)) {
|
|
655
|
-
// external fetch
|
|
656
|
-
response = await fetch(url, /** @type {RequestInit} */ (opts));
|
|
657
|
-
} else {
|
|
658
|
-
const [path, search] = url.split('?');
|
|
659
|
-
|
|
660
|
-
// otherwise we're dealing with an internal fetch
|
|
661
|
-
const resolved = resolve(request.path, path);
|
|
662
|
-
|
|
663
|
-
// handle fetch requests for static assets. e.g. prebaked data, etc.
|
|
664
|
-
// we need to support everything the browser's fetch supports
|
|
665
|
-
const filename = resolved.slice(1);
|
|
666
|
-
const filename_html = `${filename}/index.html`; // path may also match path/index.html
|
|
667
|
-
const asset = options.manifest.assets.find(
|
|
668
|
-
(d) => d.file === filename || d.file === filename_html
|
|
669
|
-
);
|
|
670
|
-
|
|
671
|
-
if (asset) {
|
|
672
|
-
// we don't have a running server while prerendering because jumping between
|
|
673
|
-
// processes would be inefficient so we have options.read instead
|
|
674
|
-
if (options.read) {
|
|
675
|
-
response = new Response(options.read(asset.file), {
|
|
676
|
-
headers: {
|
|
677
|
-
'content-type': asset.type
|
|
678
|
-
}
|
|
679
|
-
});
|
|
680
|
-
} else {
|
|
681
|
-
// TODO we need to know what protocol to use
|
|
682
|
-
response = await fetch(
|
|
683
|
-
`http://${page.host}/${asset.file}`,
|
|
684
|
-
/** @type {RequestInit} */ (opts)
|
|
685
|
-
);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
if (!response) {
|
|
690
|
-
const headers = /** @type {import('types/helper').Headers} */ ({ ...opts.headers });
|
|
691
|
-
|
|
692
|
-
// TODO: fix type https://github.com/node-fetch/node-fetch/issues/1113
|
|
693
|
-
if (opts.credentials !== 'omit') {
|
|
694
|
-
uses_credentials = true;
|
|
695
|
-
|
|
696
|
-
headers.cookie = request.headers.cookie;
|
|
697
|
-
|
|
698
|
-
if (!headers.authorization) {
|
|
699
|
-
headers.authorization = request.headers.authorization;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
const rendered = await respond(
|
|
704
|
-
{
|
|
705
|
-
host: request.host,
|
|
706
|
-
method: opts.method || 'GET',
|
|
707
|
-
headers,
|
|
708
|
-
path: resolved,
|
|
709
|
-
// TODO per https://developer.mozilla.org/en-US/docs/Web/API/Request/Request, this can be a
|
|
710
|
-
// Blob, BufferSource, FormData, URLSearchParams, USVString, or ReadableStream object
|
|
711
|
-
// @ts-ignore
|
|
712
|
-
rawBody: opts.body,
|
|
713
|
-
query: new URLSearchParams(search)
|
|
714
|
-
},
|
|
715
|
-
options,
|
|
716
|
-
{
|
|
717
|
-
fetched: url,
|
|
718
|
-
initiator: route
|
|
719
|
-
}
|
|
720
|
-
);
|
|
721
|
-
|
|
722
|
-
if (rendered) {
|
|
723
|
-
if (state.prerender) {
|
|
724
|
-
state.prerender.dependencies.set(resolved, rendered);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
response = new Response(rendered.body, {
|
|
728
|
-
status: rendered.status,
|
|
729
|
-
headers: rendered.headers
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
if (response) {
|
|
736
|
-
const proxy = new Proxy(response, {
|
|
737
|
-
get(response, key, receiver) {
|
|
738
|
-
async function text() {
|
|
739
|
-
const body = await response.text();
|
|
740
|
-
|
|
741
|
-
/** @type {import('types/helper').Headers} */
|
|
742
|
-
const headers = {};
|
|
743
|
-
for (const [key, value] of response.headers) {
|
|
744
|
-
if (key !== 'etag' && key !== 'set-cookie') headers[key] = value;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
// prettier-ignore
|
|
748
|
-
fetched.push({
|
|
749
|
-
url,
|
|
750
|
-
json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":${escape(body)}}`
|
|
751
|
-
});
|
|
752
|
-
|
|
753
|
-
return body;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
if (key === 'text') {
|
|
757
|
-
return text;
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
if (key === 'json') {
|
|
761
|
-
return async () => {
|
|
762
|
-
return JSON.parse(await text());
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// TODO arrayBuffer?
|
|
767
|
-
|
|
768
|
-
return Reflect.get(response, key, response);
|
|
769
|
-
}
|
|
770
|
-
});
|
|
771
|
-
|
|
772
|
-
return proxy;
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
return (
|
|
776
|
-
response ||
|
|
777
|
-
new Response('Not found', {
|
|
778
|
-
status: 404
|
|
779
|
-
})
|
|
780
|
-
);
|
|
781
|
-
},
|
|
782
|
-
context: { ...context }
|
|
783
|
-
};
|
|
784
|
-
|
|
785
|
-
if (is_error) {
|
|
786
|
-
/** @type {import('types/page').ErrorLoadInput} */ (load_input).status = status;
|
|
787
|
-
/** @type {import('types/page').ErrorLoadInput} */ (load_input).error = error;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
loaded = await module.load.call(null, load_input);
|
|
791
|
-
} else {
|
|
792
|
-
loaded = {};
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
// if leaf node (i.e. page component) has a load function
|
|
796
|
-
// that returns nothing, we fall through to the next one
|
|
797
|
-
if (!loaded && is_leaf && !is_error) return;
|
|
798
|
-
|
|
799
|
-
return {
|
|
800
|
-
node,
|
|
801
|
-
loaded: normalize(loaded),
|
|
802
|
-
context: loaded.context || context,
|
|
803
|
-
fetched,
|
|
804
|
-
uses_credentials
|
|
805
|
-
};
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
/** @type {Record<string, string>} */
|
|
809
|
-
const escaped = {
|
|
810
|
-
'<': '\\u003C',
|
|
811
|
-
'>': '\\u003E',
|
|
812
|
-
'/': '\\u002F',
|
|
813
|
-
'\\': '\\\\',
|
|
814
|
-
'\b': '\\b',
|
|
815
|
-
'\f': '\\f',
|
|
816
|
-
'\n': '\\n',
|
|
817
|
-
'\r': '\\r',
|
|
818
|
-
'\t': '\\t',
|
|
819
|
-
'\0': '\\0',
|
|
820
|
-
'\u2028': '\\u2028',
|
|
821
|
-
'\u2029': '\\u2029'
|
|
822
|
-
};
|
|
823
|
-
|
|
824
|
-
/** @param {string} str */
|
|
825
|
-
function escape(str) {
|
|
826
|
-
let result = '"';
|
|
827
|
-
|
|
828
|
-
for (let i = 0; i < str.length; i += 1) {
|
|
829
|
-
const char = str.charAt(i);
|
|
830
|
-
const code = char.charCodeAt(0);
|
|
831
|
-
|
|
832
|
-
if (char === '"') {
|
|
833
|
-
result += '\\"';
|
|
834
|
-
} else if (char in escaped) {
|
|
835
|
-
result += escaped[char];
|
|
836
|
-
} else if (code >= 0xd800 && code <= 0xdfff) {
|
|
837
|
-
const next = str.charCodeAt(i + 1);
|
|
838
|
-
|
|
839
|
-
// If this is the beginning of a [high, low] surrogate pair,
|
|
840
|
-
// add the next two characters, otherwise escape
|
|
841
|
-
if (code <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) {
|
|
842
|
-
result += char + str[++i];
|
|
843
|
-
} else {
|
|
844
|
-
result += `\\u${code.toString(16).toUpperCase()}`;
|
|
845
|
-
}
|
|
846
|
-
} else {
|
|
847
|
-
result += char;
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
result += '"';
|
|
852
|
-
return result;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
/**
|
|
856
|
-
* @param {{
|
|
857
|
-
* request: import('types/endpoint').ServerRequest;
|
|
858
|
-
* options: import('types/internal').SSRRenderOptions;
|
|
859
|
-
* state: import('types/internal').SSRRenderState;
|
|
860
|
-
* $session: any;
|
|
861
|
-
* status: number;
|
|
862
|
-
* error: Error;
|
|
863
|
-
* }} opts
|
|
864
|
-
*/
|
|
865
|
-
async function respond_with_error({ request, options, state, $session, status, error }) {
|
|
866
|
-
const default_layout = await options.load_component(options.manifest.layout);
|
|
867
|
-
const default_error = await options.load_component(options.manifest.error);
|
|
868
|
-
|
|
869
|
-
const page = {
|
|
870
|
-
host: request.host,
|
|
871
|
-
path: request.path,
|
|
872
|
-
query: request.query,
|
|
873
|
-
params: {}
|
|
874
|
-
};
|
|
875
|
-
|
|
876
|
-
const loaded = await load_node({
|
|
877
|
-
request,
|
|
878
|
-
options,
|
|
879
|
-
state,
|
|
880
|
-
route: null,
|
|
881
|
-
page,
|
|
882
|
-
node: default_layout,
|
|
883
|
-
$session,
|
|
884
|
-
context: {},
|
|
885
|
-
is_leaf: false,
|
|
886
|
-
is_error: false
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
const branch = [
|
|
890
|
-
loaded,
|
|
891
|
-
await load_node({
|
|
892
|
-
request,
|
|
893
|
-
options,
|
|
894
|
-
state,
|
|
895
|
-
route: null,
|
|
896
|
-
page,
|
|
897
|
-
node: default_error,
|
|
898
|
-
$session,
|
|
899
|
-
context: loaded.context,
|
|
900
|
-
is_leaf: false,
|
|
901
|
-
is_error: true,
|
|
902
|
-
status,
|
|
903
|
-
error
|
|
904
|
-
})
|
|
905
|
-
];
|
|
906
|
-
|
|
907
|
-
try {
|
|
908
|
-
return await render_response({
|
|
909
|
-
options,
|
|
910
|
-
$session,
|
|
911
|
-
page_config: {
|
|
912
|
-
hydrate: options.hydrate,
|
|
913
|
-
router: options.router,
|
|
914
|
-
ssr: options.ssr
|
|
915
|
-
},
|
|
916
|
-
status,
|
|
917
|
-
error,
|
|
918
|
-
branch,
|
|
919
|
-
page
|
|
920
|
-
});
|
|
921
|
-
} catch (error) {
|
|
922
|
-
options.handle_error(error);
|
|
923
|
-
|
|
924
|
-
return {
|
|
925
|
-
status: 500,
|
|
926
|
-
headers: {},
|
|
927
|
-
body: error.stack
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
/** @typedef {import('./types.js').Loaded} Loaded */
|
|
933
|
-
|
|
934
|
-
/**
|
|
935
|
-
* @param {{
|
|
936
|
-
* request: import('types/endpoint').ServerRequest;
|
|
937
|
-
* options: import('types/internal').SSRRenderOptions;
|
|
938
|
-
* state: import('types/internal').SSRRenderState;
|
|
939
|
-
* $session: any;
|
|
940
|
-
* route: import('types/internal').SSRPage;
|
|
941
|
-
* }} opts
|
|
942
|
-
* @returns {Promise<import('types/endpoint').ServerResponse>}
|
|
943
|
-
*/
|
|
944
|
-
async function respond$1({ request, options, state, $session, route }) {
|
|
945
|
-
const match = route.pattern.exec(request.path);
|
|
946
|
-
const params = route.params(match);
|
|
947
|
-
|
|
948
|
-
const page = {
|
|
949
|
-
host: request.host,
|
|
950
|
-
path: request.path,
|
|
951
|
-
query: request.query,
|
|
952
|
-
params
|
|
953
|
-
};
|
|
954
|
-
|
|
955
|
-
let nodes;
|
|
956
|
-
|
|
957
|
-
try {
|
|
958
|
-
nodes = await Promise.all(route.a.map((id) => id && options.load_component(id)));
|
|
959
|
-
} catch (error) {
|
|
960
|
-
options.handle_error(error);
|
|
961
|
-
|
|
962
|
-
return await respond_with_error({
|
|
963
|
-
request,
|
|
964
|
-
options,
|
|
965
|
-
state,
|
|
966
|
-
$session,
|
|
967
|
-
status: 500,
|
|
968
|
-
error
|
|
969
|
-
});
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
const leaf = nodes[nodes.length - 1].module;
|
|
973
|
-
|
|
974
|
-
const page_config = {
|
|
975
|
-
ssr: 'ssr' in leaf ? leaf.ssr : options.ssr,
|
|
976
|
-
router: 'router' in leaf ? leaf.router : options.router,
|
|
977
|
-
hydrate: 'hydrate' in leaf ? leaf.hydrate : options.hydrate
|
|
978
|
-
};
|
|
979
|
-
|
|
980
|
-
if (!leaf.prerender && state.prerender && !state.prerender.all) {
|
|
981
|
-
// if the page has `export const prerender = true`, continue,
|
|
982
|
-
// otherwise bail out at this point
|
|
983
|
-
return {
|
|
984
|
-
status: 204,
|
|
985
|
-
headers: {},
|
|
986
|
-
body: null
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
/** @type {Loaded[]} */
|
|
991
|
-
let branch;
|
|
992
|
-
|
|
993
|
-
/** @type {number} */
|
|
994
|
-
let status = 200;
|
|
995
|
-
|
|
996
|
-
/** @type {Error} */
|
|
997
|
-
let error;
|
|
998
|
-
|
|
999
|
-
ssr: if (page_config.ssr) {
|
|
1000
|
-
let context = {};
|
|
1001
|
-
branch = [];
|
|
1002
|
-
|
|
1003
|
-
for (let i = 0; i < nodes.length; i += 1) {
|
|
1004
|
-
const node = nodes[i];
|
|
1005
|
-
|
|
1006
|
-
/** @type {Loaded} */
|
|
1007
|
-
let loaded;
|
|
1008
|
-
|
|
1009
|
-
if (node) {
|
|
1010
|
-
try {
|
|
1011
|
-
loaded = await load_node({
|
|
1012
|
-
request,
|
|
1013
|
-
options,
|
|
1014
|
-
state,
|
|
1015
|
-
route,
|
|
1016
|
-
page,
|
|
1017
|
-
node,
|
|
1018
|
-
$session,
|
|
1019
|
-
context,
|
|
1020
|
-
is_leaf: i === nodes.length - 1,
|
|
1021
|
-
is_error: false
|
|
1022
|
-
});
|
|
1023
|
-
|
|
1024
|
-
if (!loaded) return;
|
|
1025
|
-
|
|
1026
|
-
if (loaded.loaded.redirect) {
|
|
1027
|
-
return {
|
|
1028
|
-
status: loaded.loaded.status,
|
|
1029
|
-
headers: {
|
|
1030
|
-
location: encodeURI(loaded.loaded.redirect)
|
|
1031
|
-
}
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
if (loaded.loaded.error) {
|
|
1036
|
-
({ status, error } = loaded.loaded);
|
|
1037
|
-
}
|
|
1038
|
-
} catch (e) {
|
|
1039
|
-
options.handle_error(e);
|
|
1040
|
-
|
|
1041
|
-
status = 500;
|
|
1042
|
-
error = e;
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
if (error) {
|
|
1046
|
-
while (i--) {
|
|
1047
|
-
if (route.b[i]) {
|
|
1048
|
-
const error_node = await options.load_component(route.b[i]);
|
|
1049
|
-
let error_loaded;
|
|
1050
|
-
|
|
1051
|
-
/** @type {Loaded} */
|
|
1052
|
-
let node_loaded;
|
|
1053
|
-
let j = i;
|
|
1054
|
-
while (!(node_loaded = branch[j])) {
|
|
1055
|
-
j -= 1;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
try {
|
|
1059
|
-
error_loaded = await load_node({
|
|
1060
|
-
request,
|
|
1061
|
-
options,
|
|
1062
|
-
state,
|
|
1063
|
-
route,
|
|
1064
|
-
page,
|
|
1065
|
-
node: error_node,
|
|
1066
|
-
$session,
|
|
1067
|
-
context: node_loaded.context,
|
|
1068
|
-
is_leaf: false,
|
|
1069
|
-
is_error: true,
|
|
1070
|
-
status,
|
|
1071
|
-
error
|
|
1072
|
-
});
|
|
1073
|
-
|
|
1074
|
-
if (error_loaded.loaded.error) {
|
|
1075
|
-
continue;
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
branch = branch.slice(0, j + 1).concat(error_loaded);
|
|
1079
|
-
break ssr;
|
|
1080
|
-
} catch (e) {
|
|
1081
|
-
options.handle_error(e);
|
|
1082
|
-
|
|
1083
|
-
continue;
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
// TODO backtrack until we find an $error.svelte component
|
|
1089
|
-
// that we can use as the leaf node
|
|
1090
|
-
// for now just return regular error page
|
|
1091
|
-
return await respond_with_error({
|
|
1092
|
-
request,
|
|
1093
|
-
options,
|
|
1094
|
-
state,
|
|
1095
|
-
$session,
|
|
1096
|
-
status,
|
|
1097
|
-
error
|
|
1098
|
-
});
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
branch.push(loaded);
|
|
1103
|
-
|
|
1104
|
-
if (loaded && loaded.loaded.context) {
|
|
1105
|
-
// TODO come up with better names for stuff
|
|
1106
|
-
context = {
|
|
1107
|
-
...context,
|
|
1108
|
-
...loaded.loaded.context
|
|
1109
|
-
};
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
try {
|
|
1115
|
-
return await render_response({
|
|
1116
|
-
options,
|
|
1117
|
-
$session,
|
|
1118
|
-
page_config,
|
|
1119
|
-
status,
|
|
1120
|
-
error,
|
|
1121
|
-
branch: branch && branch.filter(Boolean),
|
|
1122
|
-
page
|
|
1123
|
-
});
|
|
1124
|
-
} catch (error) {
|
|
1125
|
-
options.handle_error(error);
|
|
1126
|
-
|
|
1127
|
-
return await respond_with_error({
|
|
1128
|
-
request,
|
|
1129
|
-
options,
|
|
1130
|
-
state,
|
|
1131
|
-
$session,
|
|
1132
|
-
status: 500,
|
|
1133
|
-
error
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
/**
|
|
1139
|
-
* @param {import('types/endpoint').ServerRequest} request
|
|
1140
|
-
* @param {import('types/internal').SSRPage} route
|
|
1141
|
-
* @param {import('types/internal').SSRRenderOptions} options
|
|
1142
|
-
* @param {import('types/internal').SSRRenderState} state
|
|
1143
|
-
* @returns {Promise<import('types/endpoint').ServerResponse>}
|
|
1144
|
-
*/
|
|
1145
|
-
async function render_page(request, route, options, state) {
|
|
1146
|
-
if (state.initiator === route) {
|
|
1147
|
-
// infinite request cycle detected
|
|
1148
|
-
return {
|
|
1149
|
-
status: 404,
|
|
1150
|
-
headers: {},
|
|
1151
|
-
body: `Not found: ${request.path}`
|
|
1152
|
-
};
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
const $session = await options.hooks.getSession(request);
|
|
1156
|
-
|
|
1157
|
-
if (route) {
|
|
1158
|
-
const response = await respond$1({
|
|
1159
|
-
request,
|
|
1160
|
-
options,
|
|
1161
|
-
state,
|
|
1162
|
-
$session,
|
|
1163
|
-
route
|
|
1164
|
-
});
|
|
1165
|
-
|
|
1166
|
-
if (response) {
|
|
1167
|
-
return response;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
if (state.fetched) {
|
|
1171
|
-
// we came here because of a bad request in a `load` function.
|
|
1172
|
-
// rather than render the error page — which could lead to an
|
|
1173
|
-
// infinite loop, if the `load` belonged to the root layout,
|
|
1174
|
-
// we respond with a bare-bones 500
|
|
1175
|
-
return {
|
|
1176
|
-
status: 500,
|
|
1177
|
-
headers: {},
|
|
1178
|
-
body: `Bad request in load function: failed to fetch ${state.fetched}`
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1181
|
-
} else {
|
|
1182
|
-
return await respond_with_error({
|
|
1183
|
-
request,
|
|
1184
|
-
options,
|
|
1185
|
-
state,
|
|
1186
|
-
$session,
|
|
1187
|
-
status: 404,
|
|
1188
|
-
error: new Error(`Not found: ${request.path}`)
|
|
1189
|
-
});
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
/** @param {Record<string, string>} obj */
|
|
1194
|
-
function lowercase_keys(obj) {
|
|
1195
|
-
/** @type {Record<string, string>} */
|
|
1196
|
-
const clone = {};
|
|
1197
|
-
|
|
1198
|
-
for (const key in obj) {
|
|
1199
|
-
clone[key.toLowerCase()] = obj[key];
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
return clone;
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
/**
|
|
1206
|
-
* @param {import('types/endpoint').ServerRequest} request
|
|
1207
|
-
* @param {import('types/internal').SSREndpoint} route
|
|
1208
|
-
* @returns {Promise<import('types/endpoint').ServerResponse>}
|
|
1209
|
-
*/
|
|
1210
|
-
async function render_route(request, route) {
|
|
1211
|
-
const mod = await route.load();
|
|
1212
|
-
|
|
1213
|
-
/** @type {import('types/endpoint').RequestHandler} */
|
|
1214
|
-
const handler = mod[request.method.toLowerCase().replace('delete', 'del')]; // 'delete' is a reserved word
|
|
1215
|
-
|
|
1216
|
-
if (handler) {
|
|
1217
|
-
const match = route.pattern.exec(request.path);
|
|
1218
|
-
const params = route.params(match);
|
|
1219
|
-
|
|
1220
|
-
const response = await handler({ ...request, params });
|
|
1221
|
-
|
|
1222
|
-
if (response) {
|
|
1223
|
-
if (typeof response !== 'object') {
|
|
1224
|
-
return {
|
|
1225
|
-
status: 500,
|
|
1226
|
-
body: `Invalid response from route ${request.path};
|
|
1227
|
-
expected an object, got ${typeof response}`,
|
|
1228
|
-
headers: {}
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
let { status = 200, body, headers = {} } = response;
|
|
1233
|
-
|
|
1234
|
-
headers = lowercase_keys(headers);
|
|
1235
|
-
|
|
1236
|
-
if (
|
|
1237
|
-
typeof body === 'object' &&
|
|
1238
|
-
(!('content-type' in headers) || headers['content-type'] === 'application/json')
|
|
1239
|
-
) {
|
|
1240
|
-
headers = { ...headers, 'content-type': 'application/json' };
|
|
1241
|
-
body = JSON.stringify(body);
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
return { status, body, headers };
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
function read_only_form_data() {
|
|
1250
|
-
/** @type {Map<string, string[]>} */
|
|
1251
|
-
const map = new Map();
|
|
1252
|
-
|
|
1253
|
-
return {
|
|
1254
|
-
/**
|
|
1255
|
-
* @param {string} key
|
|
1256
|
-
* @param {string} value
|
|
1257
|
-
*/
|
|
1258
|
-
append(key, value) {
|
|
1259
|
-
if (map.has(key)) {
|
|
1260
|
-
map.get(key).push(value);
|
|
1261
|
-
} else {
|
|
1262
|
-
map.set(key, [value]);
|
|
1263
|
-
}
|
|
1264
|
-
},
|
|
1265
|
-
|
|
1266
|
-
data: new ReadOnlyFormData(map)
|
|
1267
|
-
};
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
class ReadOnlyFormData {
|
|
1271
|
-
/** @type {Map<string, string[]>} */
|
|
1272
|
-
#map;
|
|
1273
|
-
|
|
1274
|
-
/** @param {Map<string, string[]>} map */
|
|
1275
|
-
constructor(map) {
|
|
1276
|
-
this.#map = map;
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
/** @param {string} key */
|
|
1280
|
-
get(key) {
|
|
1281
|
-
const value = this.#map.get(key);
|
|
1282
|
-
return value && value[0];
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
/** @param {string} key */
|
|
1286
|
-
getAll(key) {
|
|
1287
|
-
return this.#map.get(key);
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
/** @param {string} key */
|
|
1291
|
-
has(key) {
|
|
1292
|
-
return this.#map.has(key);
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
*[Symbol.iterator]() {
|
|
1296
|
-
for (const [key, value] of this.#map) {
|
|
1297
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1298
|
-
yield [key, value[i]];
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
*entries() {
|
|
1304
|
-
for (const [key, value] of this.#map) {
|
|
1305
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1306
|
-
yield [key, value[i]];
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
*keys() {
|
|
1312
|
-
for (const [key, value] of this.#map) {
|
|
1313
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1314
|
-
yield key;
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
*values() {
|
|
1320
|
-
for (const [, value] of this.#map) {
|
|
1321
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1322
|
-
yield value;
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
/** @param {import('types/hooks').Incoming} req */
|
|
1329
|
-
function parse_body(req) {
|
|
1330
|
-
const raw = req.rawBody;
|
|
1331
|
-
if (!raw) return raw;
|
|
1332
|
-
|
|
1333
|
-
const [type, ...directives] = req.headers['content-type'].split(/;\s*/);
|
|
1334
|
-
|
|
1335
|
-
if (typeof raw === 'string') {
|
|
1336
|
-
switch (type) {
|
|
1337
|
-
case 'text/plain':
|
|
1338
|
-
return raw;
|
|
1339
|
-
|
|
1340
|
-
case 'application/json':
|
|
1341
|
-
return JSON.parse(raw);
|
|
1342
|
-
|
|
1343
|
-
case 'application/x-www-form-urlencoded':
|
|
1344
|
-
return get_urlencoded(raw);
|
|
1345
|
-
|
|
1346
|
-
case 'multipart/form-data': {
|
|
1347
|
-
const boundary = directives.find((directive) => directive.startsWith('boundary='));
|
|
1348
|
-
if (!boundary) throw new Error('Missing boundary');
|
|
1349
|
-
return get_multipart(raw, boundary.slice('boundary='.length));
|
|
1350
|
-
}
|
|
1351
|
-
default:
|
|
1352
|
-
throw new Error(`Invalid Content-Type ${type}`);
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
return raw;
|
|
1357
|
-
}
|
|
1358
|
-
|
|
1359
|
-
/** @param {string} text */
|
|
1360
|
-
function get_urlencoded(text) {
|
|
1361
|
-
const { data, append } = read_only_form_data();
|
|
1362
|
-
|
|
1363
|
-
text
|
|
1364
|
-
.replace(/\+/g, ' ')
|
|
1365
|
-
.split('&')
|
|
1366
|
-
.forEach((str) => {
|
|
1367
|
-
const [key, value] = str.split('=');
|
|
1368
|
-
append(decodeURIComponent(key), decodeURIComponent(value));
|
|
1369
|
-
});
|
|
1370
|
-
|
|
1371
|
-
return data;
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
/**
|
|
1375
|
-
* @param {string} text
|
|
1376
|
-
* @param {string} boundary
|
|
1377
|
-
*/
|
|
1378
|
-
function get_multipart(text, boundary) {
|
|
1379
|
-
const parts = text.split(`--${boundary}`);
|
|
1380
|
-
|
|
1381
|
-
const nope = () => {
|
|
1382
|
-
throw new Error('Malformed form data');
|
|
1383
|
-
};
|
|
1384
|
-
|
|
1385
|
-
if (parts[0] !== '' || parts[parts.length - 1].trim() !== '--') {
|
|
1386
|
-
nope();
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
const { data, append } = read_only_form_data();
|
|
1390
|
-
|
|
1391
|
-
parts.slice(1, -1).forEach((part) => {
|
|
1392
|
-
const match = /\s*([\s\S]+?)\r\n\r\n([\s\S]*)\s*/.exec(part);
|
|
1393
|
-
const raw_headers = match[1];
|
|
1394
|
-
const body = match[2].trim();
|
|
1395
|
-
|
|
1396
|
-
let key;
|
|
1397
|
-
raw_headers.split('\r\n').forEach((str) => {
|
|
1398
|
-
const [raw_header, ...raw_directives] = str.split('; ');
|
|
1399
|
-
let [name, value] = raw_header.split(': ');
|
|
1400
|
-
|
|
1401
|
-
name = name.toLowerCase();
|
|
1402
|
-
|
|
1403
|
-
/** @type {Record<string, string>} */
|
|
1404
|
-
const directives = {};
|
|
1405
|
-
raw_directives.forEach((raw_directive) => {
|
|
1406
|
-
const [name, value] = raw_directive.split('=');
|
|
1407
|
-
directives[name] = JSON.parse(value); // TODO is this right?
|
|
1408
|
-
});
|
|
1409
|
-
|
|
1410
|
-
if (name === 'content-disposition') {
|
|
1411
|
-
if (value !== 'form-data') nope();
|
|
1412
|
-
|
|
1413
|
-
if (directives.filename) {
|
|
1414
|
-
// TODO we probably don't want to do this automatically
|
|
1415
|
-
throw new Error('File upload is not yet implemented');
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
if (directives.name) {
|
|
1419
|
-
key = directives.name;
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
});
|
|
1423
|
-
|
|
1424
|
-
if (!key) nope();
|
|
1425
|
-
|
|
1426
|
-
append(key, body);
|
|
1427
|
-
});
|
|
1428
|
-
|
|
1429
|
-
return data;
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
/**
|
|
1433
|
-
* @param {import('types/hooks').Incoming} incoming
|
|
1434
|
-
* @param {import('types/internal').SSRRenderOptions} options
|
|
1435
|
-
* @param {import('types/internal').SSRRenderState} [state]
|
|
1436
|
-
*/
|
|
1437
|
-
async function respond(incoming, options, state = {}) {
|
|
1438
|
-
if (incoming.path.endsWith('/') && incoming.path !== '/') {
|
|
1439
|
-
const q = incoming.query.toString();
|
|
1440
|
-
|
|
1441
|
-
return {
|
|
1442
|
-
status: 301,
|
|
1443
|
-
headers: {
|
|
1444
|
-
location: encodeURI(incoming.path.slice(0, -1) + (q ? `?${q}` : ''))
|
|
1445
|
-
}
|
|
1446
|
-
};
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
try {
|
|
1450
|
-
return await options.hooks.handle({
|
|
1451
|
-
request: {
|
|
1452
|
-
...incoming,
|
|
1453
|
-
headers: lowercase_keys(incoming.headers),
|
|
1454
|
-
body: parse_body(incoming),
|
|
1455
|
-
params: null,
|
|
1456
|
-
locals: {}
|
|
1457
|
-
},
|
|
1458
|
-
render: async (request) => {
|
|
1459
|
-
if (state.prerender && state.prerender.fallback) {
|
|
1460
|
-
return await render_response({
|
|
1461
|
-
options,
|
|
1462
|
-
$session: await options.hooks.getSession(request),
|
|
1463
|
-
page_config: { ssr: false, router: true, hydrate: true },
|
|
1464
|
-
status: 200,
|
|
1465
|
-
error: null,
|
|
1466
|
-
branch: [],
|
|
1467
|
-
page: null
|
|
1468
|
-
});
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
for (const route of options.manifest.routes) {
|
|
1472
|
-
if (!route.pattern.test(request.path)) continue;
|
|
1473
|
-
|
|
1474
|
-
const response =
|
|
1475
|
-
route.type === 'endpoint'
|
|
1476
|
-
? await render_route(request, route)
|
|
1477
|
-
: await render_page(request, route, options, state);
|
|
1478
|
-
|
|
1479
|
-
if (response) {
|
|
1480
|
-
// inject ETags for 200 responses
|
|
1481
|
-
if (response.status === 200) {
|
|
1482
|
-
if (!/(no-store|immutable)/.test(response.headers['cache-control'])) {
|
|
1483
|
-
const etag = `"${hash(response.body)}"`;
|
|
1484
|
-
|
|
1485
|
-
if (request.headers['if-none-match'] === etag) {
|
|
1486
|
-
return {
|
|
1487
|
-
status: 304,
|
|
1488
|
-
headers: {},
|
|
1489
|
-
body: null
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
response.headers['etag'] = etag;
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
return response;
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
return await render_page(request, null, options, state);
|
|
1502
|
-
}
|
|
1503
|
-
});
|
|
1504
|
-
} catch (e) {
|
|
1505
|
-
options.handle_error(e);
|
|
1506
|
-
|
|
1507
|
-
return {
|
|
1508
|
-
status: 500,
|
|
1509
|
-
headers: {},
|
|
1510
|
-
body: options.dev ? e.stack : e.message
|
|
1511
|
-
};
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
/** @param {string} str */
|
|
1516
|
-
function hash(str) {
|
|
1517
|
-
let hash = 5381,
|
|
1518
|
-
i = str.length;
|
|
1519
|
-
while (i) hash = (hash * 33) ^ str.charCodeAt(--i);
|
|
1520
|
-
return (hash >>> 0).toString(36);
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
export { respond };
|