@sveltejs/kit 1.0.6 → 1.0.8
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/package.json +1 -1
- package/src/core/prerender/prerender.js +15 -1
- package/src/core/sync/create_manifest_data/index.js +3 -0
- package/src/exports/vite/dev/index.js +11 -0
- package/src/exports/vite/index.js +1 -1
- package/src/runtime/client/client.js +1 -1
- package/src/runtime/client/utils.js +1 -0
- package/src/runtime/server/fetch.js +1 -11
- package/src/runtime/server/page/csp.js +2 -1
- package/src/runtime/server/page/load_data.js +121 -100
- package/src/runtime/server/page/render.js +2 -7
- package/types/ambient.d.ts +1 -1
package/package.json
CHANGED
|
@@ -102,10 +102,20 @@ export async function prerender() {
|
|
|
102
102
|
/** @type {import('types').SSRManifest} */
|
|
103
103
|
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
|
|
104
104
|
|
|
105
|
+
/** @type {Map<string, string>} */
|
|
106
|
+
const saved = new Map();
|
|
107
|
+
|
|
105
108
|
override({
|
|
106
109
|
building: true,
|
|
107
110
|
paths: config.paths,
|
|
108
|
-
read: (file) =>
|
|
111
|
+
read: (file) => {
|
|
112
|
+
// stuff we just wrote
|
|
113
|
+
const filepath = saved.get(file);
|
|
114
|
+
if (filepath) return readFileSync(filepath);
|
|
115
|
+
|
|
116
|
+
// stuff in `static`
|
|
117
|
+
return readFileSync(join(config.files.assets, file));
|
|
118
|
+
}
|
|
109
119
|
});
|
|
110
120
|
|
|
111
121
|
const server = new Server(manifest);
|
|
@@ -222,6 +232,7 @@ export async function prerender() {
|
|
|
222
232
|
}
|
|
223
233
|
|
|
224
234
|
const body = result.body ?? new Uint8Array(await result.response.arrayBuffer());
|
|
235
|
+
|
|
225
236
|
save(
|
|
226
237
|
'dependencies',
|
|
227
238
|
result.response,
|
|
@@ -351,6 +362,9 @@ export async function prerender() {
|
|
|
351
362
|
} else if (response_type !== OK) {
|
|
352
363
|
handle_http_error({ status: response.status, path: decoded, referrer, referenceType });
|
|
353
364
|
}
|
|
365
|
+
|
|
366
|
+
manifest.assets.add(file);
|
|
367
|
+
saved.set(file, dest);
|
|
354
368
|
}
|
|
355
369
|
|
|
356
370
|
for (const route of manifest._.routes) {
|
|
@@ -76,6 +76,9 @@ function create_matchers(config, cwd) {
|
|
|
76
76
|
matchers[type] = matcher_file;
|
|
77
77
|
}
|
|
78
78
|
} else {
|
|
79
|
+
// Allow for matcher test collocation
|
|
80
|
+
if (type.endsWith('.test') || type.endsWith('.spec')) continue;
|
|
81
|
+
|
|
79
82
|
throw new Error(
|
|
80
83
|
`Matcher names can only have underscores and alphanumeric characters — "${file}" is invalid`
|
|
81
84
|
);
|
|
@@ -29,6 +29,17 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
29
29
|
installPolyfills();
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
const fetch = globalThis.fetch;
|
|
33
|
+
globalThis.fetch = (info, init) => {
|
|
34
|
+
if (typeof info === 'string' && !/^\w+:\/\//.test(info)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Cannot use relative URL (${info}) with global fetch — use \`event.fetch\` instead: https://kit.svelte.dev/docs/web-standards#fetch-apis`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return fetch(info, init);
|
|
41
|
+
};
|
|
42
|
+
|
|
32
43
|
sync.init(svelte_config, vite_config.mode);
|
|
33
44
|
|
|
34
45
|
/** @type {import('types').Respond} */
|
|
@@ -301,7 +301,7 @@ function kit({ svelte_config }) {
|
|
|
301
301
|
},
|
|
302
302
|
|
|
303
303
|
async load(id, options) {
|
|
304
|
-
if (options?.ssr === false) {
|
|
304
|
+
if (options?.ssr === false && process.env.TEST !== 'true') {
|
|
305
305
|
const normalized_cwd = vite.normalizePath(cwd);
|
|
306
306
|
const normalized_lib = vite.normalizePath(svelte_config.kit.files.lib);
|
|
307
307
|
if (
|
|
@@ -709,7 +709,7 @@ export function create_client({ target, base }) {
|
|
|
709
709
|
let server_data = null;
|
|
710
710
|
|
|
711
711
|
const url_changed = current.url ? id !== current.url.pathname + current.url.search : false;
|
|
712
|
-
const route_changed = current.route ? id !== current.route.id : false;
|
|
712
|
+
const route_changed = current.route ? route.id !== current.route.id : false;
|
|
713
713
|
|
|
714
714
|
const invalid_server_nodes = loaders.reduce((acc, loader, i) => {
|
|
715
715
|
const previous = current.branch[i];
|
|
@@ -63,17 +63,7 @@ export function create_fetch({ event, options, state, get_cookie_header }) {
|
|
|
63
63
|
if (cookie) request.headers.set('cookie', cookie);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (mode === 'no-cors') {
|
|
69
|
-
response = new Response('', {
|
|
70
|
-
status: response.status,
|
|
71
|
-
statusText: response.statusText,
|
|
72
|
-
headers: response.headers
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return response;
|
|
66
|
+
return fetch(request);
|
|
77
67
|
}
|
|
78
68
|
|
|
79
69
|
/** @type {Response} */
|
|
@@ -107,129 +107,150 @@ export async function load_data({
|
|
|
107
107
|
params: event.params,
|
|
108
108
|
data: server_data_node?.data ?? null,
|
|
109
109
|
route: event.route,
|
|
110
|
-
fetch:
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts),
|
|
111
|
+
setHeaders: event.setHeaders,
|
|
112
|
+
depends: () => {},
|
|
113
|
+
parent
|
|
114
|
+
});
|
|
113
115
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
const data = result ? await unwrap_promises(result) : null;
|
|
117
|
+
validate_load_response(data, /** @type {string} */ (event.route.id));
|
|
118
|
+
return data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @param {Pick<import('types').RequestEvent, 'fetch' | 'url' | 'request' | 'route'>} event
|
|
123
|
+
* @param {import("types").SSRState} state
|
|
124
|
+
* @param {import("./types").Fetched[]} fetched
|
|
125
|
+
* @param {boolean} csr
|
|
126
|
+
* @param {Pick<Required<import("types").ResolveOptions>, 'filterSerializedResponseHeaders'>} resolve_opts
|
|
127
|
+
*/
|
|
128
|
+
export function create_universal_fetch(event, state, fetched, csr, resolve_opts) {
|
|
129
|
+
/**
|
|
130
|
+
* @param {URL | RequestInfo} input
|
|
131
|
+
* @param {RequestInit} [init]
|
|
132
|
+
*/
|
|
133
|
+
return async (input, init) => {
|
|
134
|
+
const cloned_body = input instanceof Request && input.body ? input.clone().body : null;
|
|
135
|
+
let response = await event.fetch(input, init);
|
|
116
136
|
|
|
117
|
-
|
|
118
|
-
|
|
137
|
+
const url = new URL(input instanceof Request ? input.url : input, event.url);
|
|
138
|
+
const same_origin = url.origin === event.url.origin;
|
|
119
139
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
140
|
+
/** @type {import('types').PrerenderDependency} */
|
|
141
|
+
let dependency;
|
|
142
|
+
|
|
143
|
+
if (same_origin) {
|
|
144
|
+
if (state.prerendering) {
|
|
145
|
+
dependency = { response, body: null };
|
|
146
|
+
state.prerendering.dependencies.set(url.pathname, dependency);
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
// simulate CORS errors and "no access to body in no-cors mode" server-side for consistency with client-side behaviour
|
|
150
|
+
const mode = input instanceof Request ? input.mode : init?.mode ?? 'cors';
|
|
151
|
+
if (mode === 'no-cors') {
|
|
152
|
+
response = new Response('', {
|
|
153
|
+
status: response.status,
|
|
154
|
+
statusText: response.statusText,
|
|
155
|
+
headers: response.headers
|
|
156
|
+
});
|
|
125
157
|
} else {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
acao ? 'Incorrect' : 'No'
|
|
134
|
-
} 'Access-Control-Allow-Origin' header is present on the requested resource`
|
|
135
|
-
);
|
|
136
|
-
}
|
|
158
|
+
const acao = response.headers.get('access-control-allow-origin');
|
|
159
|
+
if (!acao || (acao !== event.url.origin && acao !== '*')) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`CORS error: ${
|
|
162
|
+
acao ? 'Incorrect' : 'No'
|
|
163
|
+
} 'Access-Control-Allow-Origin' header is present on the requested resource`
|
|
164
|
+
);
|
|
137
165
|
}
|
|
138
166
|
}
|
|
167
|
+
}
|
|
139
168
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (!body || typeof body === 'string') {
|
|
146
|
-
const status_number = Number(response.status);
|
|
147
|
-
if (isNaN(status_number)) {
|
|
148
|
-
throw new Error(
|
|
149
|
-
`response.status is not a number. value: "${
|
|
150
|
-
response.status
|
|
151
|
-
}" type: ${typeof response.status}`
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
fetched.push({
|
|
156
|
-
url: same_origin ? url.href.slice(event.url.origin.length) : url.href,
|
|
157
|
-
method: event.request.method,
|
|
158
|
-
request_body: /** @type {string | ArrayBufferView | undefined} */ (
|
|
159
|
-
input instanceof Request && cloned_body
|
|
160
|
-
? await stream_to_string(cloned_body)
|
|
161
|
-
: init?.body
|
|
162
|
-
),
|
|
163
|
-
response_body: body,
|
|
164
|
-
response: response
|
|
165
|
-
});
|
|
166
|
-
}
|
|
169
|
+
const proxy = new Proxy(response, {
|
|
170
|
+
get(response, key, _receiver) {
|
|
171
|
+
async function text() {
|
|
172
|
+
const body = await response.text();
|
|
167
173
|
|
|
168
|
-
|
|
169
|
-
|
|
174
|
+
if (!body || typeof body === 'string') {
|
|
175
|
+
const status_number = Number(response.status);
|
|
176
|
+
if (isNaN(status_number)) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`response.status is not a number. value: "${
|
|
179
|
+
response.status
|
|
180
|
+
}" type: ${typeof response.status}`
|
|
181
|
+
);
|
|
170
182
|
}
|
|
171
183
|
|
|
172
|
-
|
|
184
|
+
fetched.push({
|
|
185
|
+
url: same_origin ? url.href.slice(event.url.origin.length) : url.href,
|
|
186
|
+
method: event.request.method,
|
|
187
|
+
request_body: /** @type {string | ArrayBufferView | undefined} */ (
|
|
188
|
+
input instanceof Request && cloned_body
|
|
189
|
+
? await stream_to_string(cloned_body)
|
|
190
|
+
: init?.body
|
|
191
|
+
),
|
|
192
|
+
response_body: body,
|
|
193
|
+
response: response
|
|
194
|
+
});
|
|
173
195
|
}
|
|
174
196
|
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
197
|
+
if (dependency) {
|
|
198
|
+
dependency.body = body;
|
|
199
|
+
}
|
|
178
200
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
201
|
+
return body;
|
|
202
|
+
}
|
|
182
203
|
|
|
183
|
-
|
|
184
|
-
|
|
204
|
+
if (key === 'arrayBuffer') {
|
|
205
|
+
return async () => {
|
|
206
|
+
const buffer = await response.arrayBuffer();
|
|
185
207
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
208
|
+
if (dependency) {
|
|
209
|
+
dependency.body = new Uint8Array(buffer);
|
|
210
|
+
}
|
|
189
211
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
212
|
+
// TODO should buffer be inlined into the page (albeit base64'd)?
|
|
213
|
+
// any conditions in which it shouldn't be?
|
|
193
214
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
};
|
|
198
|
-
}
|
|
215
|
+
return buffer;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
199
218
|
|
|
200
|
-
|
|
219
|
+
if (key === 'text') {
|
|
220
|
+
return text;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (key === 'json') {
|
|
224
|
+
return async () => {
|
|
225
|
+
return JSON.parse(await text());
|
|
226
|
+
};
|
|
201
227
|
}
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
if (csr) {
|
|
205
|
-
// ensure that excluded headers can't be read
|
|
206
|
-
const get = response.headers.get;
|
|
207
|
-
response.headers.get = (key) => {
|
|
208
|
-
const lower = key.toLowerCase();
|
|
209
|
-
const value = get.call(response.headers, lower);
|
|
210
|
-
if (value && !lower.startsWith('x-sveltekit-')) {
|
|
211
|
-
const included = resolve_opts.filterSerializedResponseHeaders(lower, value);
|
|
212
|
-
if (!included) {
|
|
213
|
-
throw new Error(
|
|
214
|
-
`Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://kit.svelte.dev/docs/hooks#server-hooks-handle (at ${event.route.id})`
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
228
|
|
|
219
|
-
|
|
220
|
-
};
|
|
229
|
+
return Reflect.get(response, key, response);
|
|
221
230
|
}
|
|
231
|
+
});
|
|
222
232
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
233
|
+
if (csr) {
|
|
234
|
+
// ensure that excluded headers can't be read
|
|
235
|
+
const get = response.headers.get;
|
|
236
|
+
response.headers.get = (key) => {
|
|
237
|
+
const lower = key.toLowerCase();
|
|
238
|
+
const value = get.call(response.headers, lower);
|
|
239
|
+
if (value && !lower.startsWith('x-sveltekit-')) {
|
|
240
|
+
const included = resolve_opts.filterSerializedResponseHeaders(lower, value);
|
|
241
|
+
if (!included) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
`Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://kit.svelte.dev/docs/hooks#server-hooks-handle (at ${event.route.id})`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
229
247
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
248
|
+
return value;
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return proxy;
|
|
253
|
+
};
|
|
233
254
|
}
|
|
234
255
|
|
|
235
256
|
/**
|
|
@@ -211,22 +211,17 @@ export async function render_response({
|
|
|
211
211
|
const path = prefixed(dep);
|
|
212
212
|
|
|
213
213
|
if (resolve_opts.preload({ type: 'css', path })) {
|
|
214
|
-
const attributes = [];
|
|
215
|
-
|
|
216
|
-
if (csp.style_needs_nonce) {
|
|
217
|
-
attributes.push(`nonce="${csp.nonce}"`);
|
|
218
|
-
}
|
|
214
|
+
const attributes = ['rel="stylesheet"'];
|
|
219
215
|
|
|
220
216
|
if (inline_styles.has(dep)) {
|
|
221
217
|
// don't load stylesheets that are already inlined
|
|
222
218
|
// include them in disabled state so that Vite can detect them and doesn't try to add them
|
|
223
219
|
attributes.push('disabled', 'media="(max-width: 0)"');
|
|
224
220
|
} else {
|
|
225
|
-
const preload_atts = ['rel="preload"', 'as="style"']
|
|
221
|
+
const preload_atts = ['rel="preload"', 'as="style"'];
|
|
226
222
|
link_header_preloads.add(`<${encodeURI(path)}>; ${preload_atts.join(';')}; nopush`);
|
|
227
223
|
}
|
|
228
224
|
|
|
229
|
-
attributes.unshift('rel="stylesheet"');
|
|
230
225
|
head += `\n\t\t<link href="${path}" ${attributes.join(' ')}>`;
|
|
231
226
|
}
|
|
232
227
|
}
|
package/types/ambient.d.ts
CHANGED
|
@@ -320,7 +320,7 @@ declare module '$app/stores' {
|
|
|
320
320
|
/**
|
|
321
321
|
* A readable store whose initial value is `false`. If [`version.pollInterval`](https://kit.svelte.dev/docs/configuration#version) is a non-zero value, SvelteKit will poll for new versions of the app and update the store value to `true` when it detects one. `updated.check()` will force an immediate check, regardless of polling.
|
|
322
322
|
*/
|
|
323
|
-
export const updated: Readable<boolean> & { check(): boolean };
|
|
323
|
+
export const updated: Readable<boolean> & { check(): Promise<boolean> };
|
|
324
324
|
|
|
325
325
|
/**
|
|
326
326
|
* A function that returns all of the contextual stores. On the server, this must be called during component initialization.
|