@sveltejs/kit 1.0.7 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -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) => readFileSync(join(config.files.assets, 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) {
@@ -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];
@@ -211,6 +211,7 @@ export function create_updated_store() {
211
211
  /** @type {NodeJS.Timeout} */
212
212
  let timeout;
213
213
 
214
+ /** @type {() => Promise<boolean>} */
214
215
  async function check() {
215
216
  if (DEV || !BROWSER) return false;
216
217
 
@@ -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
- let response = await fetch(request);
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} */
@@ -16,7 +16,8 @@ const quoted = new Set([
16
16
  'none',
17
17
  'strict-dynamic',
18
18
  'report-sample',
19
- 'wasm-unsafe-eval'
19
+ 'wasm-unsafe-eval',
20
+ 'script'
20
21
  ]);
21
22
 
22
23
  const crypto_pattern = /^(nonce|sha\d\d\d)-/;
@@ -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: async (input, init) => {
111
- const cloned_body = input instanceof Request && input.body ? input.clone().body : null;
112
- const response = await event.fetch(input, init);
110
+ fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts),
111
+ setHeaders: event.setHeaders,
112
+ depends: () => {},
113
+ parent
114
+ });
113
115
 
114
- const url = new URL(input instanceof Request ? input.url : input, event.url);
115
- const same_origin = url.origin === event.url.origin;
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
- /** @type {import('types').PrerenderDependency} */
118
- let dependency;
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
- if (same_origin) {
121
- if (state.prerendering) {
122
- dependency = { response, body: null };
123
- state.prerendering.dependencies.set(url.pathname, dependency);
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
- // simulate CORS errors server-side for consistency with client-side behaviour
127
- const mode = input instanceof Request ? input.mode : init?.mode ?? 'cors';
128
- if (mode !== 'no-cors') {
129
- const acao = response.headers.get('access-control-allow-origin');
130
- if (!acao || (acao !== event.url.origin && acao !== '*')) {
131
- throw new Error(
132
- `CORS error: ${
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
- const proxy = new Proxy(response, {
141
- get(response, key, _receiver) {
142
- async function text() {
143
- const body = await response.text();
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
- if (dependency) {
169
- dependency.body = body;
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
- return body;
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 (key === 'arrayBuffer') {
176
- return async () => {
177
- const buffer = await response.arrayBuffer();
197
+ if (dependency) {
198
+ dependency.body = body;
199
+ }
178
200
 
179
- if (dependency) {
180
- dependency.body = new Uint8Array(buffer);
181
- }
201
+ return body;
202
+ }
182
203
 
183
- // TODO should buffer be inlined into the page (albeit base64'd)?
184
- // any conditions in which it shouldn't be?
204
+ if (key === 'arrayBuffer') {
205
+ return async () => {
206
+ const buffer = await response.arrayBuffer();
185
207
 
186
- return buffer;
187
- };
188
- }
208
+ if (dependency) {
209
+ dependency.body = new Uint8Array(buffer);
210
+ }
189
211
 
190
- if (key === 'text') {
191
- return text;
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
- if (key === 'json') {
195
- return async () => {
196
- return JSON.parse(await text());
197
- };
198
- }
215
+ return buffer;
216
+ };
217
+ }
199
218
 
200
- return Reflect.get(response, key, response);
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
- return value;
220
- };
229
+ return Reflect.get(response, key, response);
221
230
  }
231
+ });
222
232
 
223
- return proxy;
224
- },
225
- setHeaders: event.setHeaders,
226
- depends: () => {},
227
- parent
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
- const data = result ? await unwrap_promises(result) : null;
231
- validate_load_response(data, /** @type {string} */ (event.route.id));
232
- return data;
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"'].concat(attributes);
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
  }
@@ -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.