@sveltejs/kit
Advanced tools
Comparing version 1.22.3 to 1.25.1
{ | ||
"name": "@sveltejs/kit", | ||
"version": "1.22.3", | ||
"version": "1.25.1", | ||
"description": "The fastest way to build Svelte apps", | ||
@@ -25,3 +25,4 @@ "repository": { | ||
"sirv": "^2.0.2", | ||
"undici": "~5.22.0" | ||
"tiny-glob": "^0.2.9", | ||
"undici": "~5.25.0" | ||
}, | ||
@@ -31,3 +32,2 @@ "devDependencies": { | ||
"@types/connect": "^3.4.35", | ||
"@types/marked": "^4.0.7", | ||
"@types/mime": "^3.0.1", | ||
@@ -37,4 +37,4 @@ "@types/node": "^16.18.6", | ||
"@types/set-cookie-parser": "^2.4.2", | ||
"dts-buddy": "^0.0.10", | ||
"marked": "^4.2.3", | ||
"dts-buddy": "^0.2.4", | ||
"marked": "^9.0.0", | ||
"rollup": "^3.7.0", | ||
@@ -45,3 +45,3 @@ "svelte": "^4.0.5", | ||
"vite": "^4.4.2", | ||
"vitest": "^0.32.2" | ||
"vitest": "^0.34.0" | ||
}, | ||
@@ -102,4 +102,5 @@ "peerDependencies": { | ||
"postinstall": "node postinstall.js", | ||
"generate:version": "node scripts/generate-version.js" | ||
"generate:version": "node scripts/generate-version.js", | ||
"generate:types": "node scripts/generate-dts.js" | ||
} | ||
} |
@@ -1,6 +0,5 @@ | ||
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
import { load_config } from './src/core/config/index.js'; | ||
import { list_files } from './src/core/utils.js'; | ||
import * as sync from './src/core/sync/sync.js'; | ||
import glob from 'tiny-glob/sync.js'; | ||
import fs from 'node:fs'; | ||
@@ -14,16 +13,22 @@ try { | ||
const directories = []; | ||
const workspaces = []; | ||
if (pkg.workspaces) { | ||
// we have to do this because of https://classic.yarnpkg.com/blog/2018/02/15/nohoist/ | ||
const packages = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages; | ||
// Find all npm and Yarn workspace glob patterns | ||
// https://classic.yarnpkg.com/blog/2018/02/15/nohoist/ | ||
// https://docs.npmjs.com/cli/v9/configuring-npm/package-json#workspaces | ||
const patterns = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages; | ||
for (const directory of packages) { | ||
directories.push(...list_files(directory).map((dir) => path.resolve(cwd, dir))); | ||
for (const pattern of patterns) { | ||
workspaces.push( | ||
...glob(pattern, { cwd, absolute: true }).filter((path) => | ||
fs.statSync(path).isDirectory() | ||
) | ||
); | ||
} | ||
} else { | ||
directories.push(cwd); | ||
workspaces.push(cwd); | ||
} | ||
for (const cwd of directories) { | ||
for (const cwd of workspaces) { | ||
process.chdir(cwd); | ||
@@ -30,0 +35,0 @@ |
import { existsSync, statSync, createReadStream, createWriteStream } from 'node:fs'; | ||
import { extname, join, resolve } from 'node:path'; | ||
import { extname, resolve } from 'node:path'; | ||
import { pipeline } from 'node:stream'; | ||
@@ -157,3 +157,3 @@ import { promisify } from 'node:util'; | ||
generateManifest: ({ relativePath, routes: subset }) => { | ||
generateManifest({ relativePath, routes: subset }) { | ||
return generate_manifest({ | ||
@@ -185,19 +185,6 @@ build_data, | ||
writeClient(dest) { | ||
const server_assets = copy( | ||
`${config.kit.outDir}/output/server/${config.kit.appDir}/immutable/assets`, | ||
join(dest, config.kit.appDir, 'immutable/assets') | ||
).map((filename) => join(config.kit.appDir, 'immutable/assets', filename)); | ||
const client_assets = copy(`${config.kit.outDir}/output/client`, dest); | ||
return Array.from(new Set([...server_assets, ...client_assets])); | ||
return copy(`${config.kit.outDir}/output/client`, dest); | ||
}, | ||
// @ts-expect-error | ||
writePrerendered(dest, opts) { | ||
// TODO remove for 1.0 | ||
if (opts?.fallback) { | ||
throw new Error( | ||
'The fallback option no longer exists — use builder.generateFallback(fallback) instead' | ||
); | ||
} | ||
writePrerendered(dest) { | ||
const source = `${config.kit.outDir}/output/prerendered`; | ||
@@ -204,0 +191,0 @@ return [...copy(`${source}/pages`, dest), ...copy(`${source}/dependencies`, dest)]; |
@@ -63,3 +63,3 @@ import { join } from 'node:path'; | ||
metadata.nodes[node.index] = { | ||
has_server_load: node.server?.load !== undefined | ||
has_server_load: node.server?.load !== undefined || node.server?.trailingSlash !== undefined | ||
}; | ||
@@ -73,3 +73,3 @@ } | ||
/** @type {import('types').HttpMethod[]} */ | ||
/** @type {(import('types').HttpMethod | '*')[]} */ | ||
const api_methods = []; | ||
@@ -101,2 +101,4 @@ | ||
api_methods.push(method); | ||
} else if (mod.fallback) { | ||
api_methods.push('*'); | ||
} | ||
@@ -103,0 +105,0 @@ }); |
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
import colors from 'kleur'; | ||
import mime from 'mime'; | ||
@@ -204,5 +205,28 @@ import { list_files, runtime_directory } from '../../utils.js'; | ||
if (file.is_dir) continue; | ||
if (!file.name.startsWith('+')) continue; | ||
if (!valid_extensions.find((ext) => file.name.endsWith(ext))) continue; | ||
const ext = valid_extensions.find((ext) => file.name.endsWith(ext)); | ||
if (!ext) continue; | ||
if (!file.name.startsWith('+')) { | ||
const name = file.name.slice(0, -ext.length); | ||
// check if it is a valid route filename but missing the + prefix | ||
const typo = | ||
/^(?:(page(?:@(.*))?)|(layout(?:@(.*))?)|(error))$/.test(name) || | ||
/^(?:(server)|(page(?:(@[a-zA-Z0-9_-]*))?(\.server)?)|(layout(?:(@[a-zA-Z0-9_-]*))?(\.server)?))$/.test( | ||
name | ||
); | ||
if (typo) { | ||
console.log( | ||
colors | ||
.bold() | ||
.yellow( | ||
`Missing route file prefix. Did you mean +${file.name}?` + | ||
` at ${path.join(dir, file.name)}` | ||
) | ||
); | ||
} | ||
continue; | ||
} | ||
if (file.name.endsWith('.d.ts')) { | ||
@@ -209,0 +233,0 @@ let name = file.name.slice(0, -5); |
@@ -0,4 +1,6 @@ | ||
import path from 'node:path'; | ||
import { relative_path, resolve_entry } from '../../utils/filesystem.js'; | ||
import { s } from '../../utils/misc.js'; | ||
import { dedent, write_if_changed } from './utils.js'; | ||
import colors from 'kleur'; | ||
@@ -111,2 +113,14 @@ /** | ||
const typo = resolve_entry('src/+hooks.client'); | ||
if (typo) { | ||
console.log( | ||
colors | ||
.bold() | ||
.yellow( | ||
`Unexpected + prefix. Did you mean ${typo.split('/').at(-1)?.slice(1)}?` + | ||
` at ${path.resolve(typo)}` | ||
) | ||
); | ||
} | ||
write_if_changed( | ||
@@ -113,0 +127,0 @@ `${output}/app.js`, |
@@ -1,2 +0,1 @@ | ||
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
@@ -9,2 +8,3 @@ import { hash } from '../../runtime/hash.js'; | ||
import { write_if_changed } from './utils.js'; | ||
import colors from 'kleur'; | ||
@@ -80,5 +80,16 @@ /** | ||
export function write_server(config, output) { | ||
// TODO the casting shouldn't be necessary — investigate | ||
const hooks_file = /** @type {string} */ (resolve_entry(config.kit.files.hooks.server)); | ||
const hooks_file = resolve_entry(config.kit.files.hooks.server); | ||
const typo = resolve_entry('src/+hooks.server'); | ||
if (typo) { | ||
console.log( | ||
colors | ||
.bold() | ||
.yellow( | ||
`Unexpected + prefix. Did you mean ${typo.split('/').at(-1)?.slice(1)}?` + | ||
` at ${path.resolve(typo)}` | ||
) | ||
); | ||
} | ||
/** @param {string} file */ | ||
@@ -93,3 +104,3 @@ function relative(file) { | ||
config, | ||
hooks: fs.existsSync(hooks_file) ? relative(hooks_file) : null, | ||
hooks: hooks_file ? relative(hooks_file) : null, | ||
has_service_worker: | ||
@@ -96,0 +107,0 @@ config.kit.serviceWorker.register && !!resolve_entry(config.kit.files.serviceWorker), |
@@ -41,3 +41,3 @@ import { HttpError, Redirect, ActionFailure } from '../runtime/control.js'; | ||
* @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages). Must be in the range 300-308. | ||
* @param {string} location The location to redirect to. | ||
* @param {string | URL} location The location to redirect to. | ||
*/ | ||
@@ -49,3 +49,3 @@ export function redirect(status, location) { | ||
return new Redirect(status, location); | ||
return new Redirect(status, location.toString()); | ||
} | ||
@@ -52,0 +52,0 @@ |
@@ -122,3 +122,3 @@ import 'svelte'; // pick up `declare module "*.svelte"` | ||
getServerDirectory(): string; | ||
/** Get the application path including any configured `base` path, e.g. `/my-base-path/_app`. */ | ||
/** Get the application path including any configured `base` path, e.g. `my-base-path/_app`. */ | ||
getAppPath(): string; | ||
@@ -435,3 +435,3 @@ | ||
/** | ||
* Inline CSS inside a `<style>` block at the head of the HTML. This option is a number that specifies the maximum length of a CSS file to be inlined. All CSS files needed for the page and smaller than this value are merged and inlined in a `<style>` block. | ||
* Inline CSS inside a `<style>` block at the head of the HTML. This option is a number that specifies the maximum length of a CSS file in UTF-16 code units, as specified by the [String.length](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length) property, to be inlined. All CSS files needed for the page and smaller than this value are merged and inlined in a `<style>` block. | ||
* | ||
@@ -702,9 +702,9 @@ * > This results in fewer initial requests and can improve your [First Contentful Paint](https://web.dev/first-contentful-paint) score. However, it generates larger HTML output and reduces the effectiveness of browser caches. Use it advisedly. | ||
* | ||
* - it can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request | ||
* - it can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context) | ||
* - internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call | ||
* - during server-side rendering, the response will be captured and inlined into the rendered HTML. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](https://kit.svelte.dev/docs/hooks#server-hooks-handle) | ||
* - during hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request | ||
* - It can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request. | ||
* - It can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context). | ||
* - Internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call. | ||
* - During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the `text` and `json` methods of the `Response` object. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](https://kit.svelte.dev/docs/hooks#server-hooks-handle) | ||
* - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request. | ||
* | ||
* > Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it. | ||
* You can learn more about making credentialed requests with cookies [here](https://kit.svelte.dev/docs/load#cookies) | ||
*/ | ||
@@ -736,3 +736,3 @@ fetch: typeof fetch; | ||
* | ||
* You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://kit.svelte.dev/docs/types#public-types-cookies) API in a server-only `load` function instead. | ||
* You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://kit.svelte.dev/docs/types#public-types-cookies) API in a server-only `load` function instead. | ||
* | ||
@@ -858,3 +858,3 @@ * `setHeaders` has no effect when a `load` function runs in the browser. | ||
*/ | ||
type: Omit<NavigationType, 'enter'>; | ||
type: Exclude<NavigationType, 'enter'>; | ||
/** | ||
@@ -868,2 +868,7 @@ * Whether or not the navigation will result in the page being unloaded (i.e. not a client-side navigation) | ||
delta?: number; | ||
/** | ||
* A promise that resolves once the navigation is complete, and rejects if the navigation | ||
* fails or is aborted. In the case of a `willUnload` navigation, the promise will never resolve | ||
*/ | ||
complete: Promise<void>; | ||
} | ||
@@ -882,5 +887,23 @@ | ||
/** | ||
* The argument passed to [`onNavigate`](https://kit.svelte.dev/docs/modules#$app-navigation-onnavigate) callbacks. | ||
*/ | ||
export interface OnNavigate extends Navigation { | ||
/** | ||
* The type of navigation: | ||
* - `form`: The user submitted a `<form>` | ||
* - `link`: Navigation was triggered by a link click | ||
* - `goto`: Navigation was triggered by a `goto(...)` call or a redirect | ||
* - `popstate`: Navigation was triggered by back/forward navigation | ||
*/ | ||
type: Exclude<NavigationType, 'enter' | 'leave'>; | ||
/** | ||
* Since `onNavigate` callbacks are called immediately before a client-side navigation, they will never be called with a navigation that unloads the page. | ||
*/ | ||
willUnload: false; | ||
} | ||
/** | ||
* The argument passed to [`afterNavigate`](https://kit.svelte.dev/docs/modules#$app-navigation-afternavigate) callbacks. | ||
*/ | ||
export interface AfterNavigate extends Navigation { | ||
export interface AfterNavigate extends Omit<Navigation, 'type'> { | ||
/** | ||
@@ -894,5 +917,5 @@ * The type of navigation: | ||
*/ | ||
type: Omit<NavigationType, 'leave'>; | ||
type: Exclude<NavigationType, 'leave'>; | ||
/** | ||
* Since `afterNavigate` is called after a navigation completes, it will never be called with a navigation that unloads the page. | ||
* Since `afterNavigate` callbacks are called after a navigation completes, they will never be called with a navigation that unloads the page. | ||
*/ | ||
@@ -960,7 +983,9 @@ willUnload: false; | ||
* | ||
* - it can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request | ||
* - it can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context) | ||
* - internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call | ||
* - It can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request. | ||
* - It can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context). | ||
* - Internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call. | ||
* - During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the `text` and `json` methods of the `Response` object. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](https://kit.svelte.dev/docs/hooks#server-hooks-handle) | ||
* - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request. | ||
* | ||
* > Cookies will only be passed through if the target host is the same as the SvelteKit application or a more specific subdomain of it. | ||
* You can learn more about making credentialed requests with cookies [here](https://kit.svelte.dev/docs/load#cookies) | ||
*/ | ||
@@ -1017,3 +1042,3 @@ fetch: typeof fetch; | ||
* | ||
* You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://kit.svelte.dev/docs/types#public-types-cookies) API instead. | ||
* You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://kit.svelte.dev/docs/types#public-types-cookies) API instead. | ||
*/ | ||
@@ -1072,6 +1097,6 @@ setHeaders(headers: Record<string, string>): void; | ||
api: { | ||
methods: HttpMethod[]; | ||
methods: Array<HttpMethod | '*'>; | ||
}; | ||
page: { | ||
methods: Extract<HttpMethod, 'GET' | 'POST'>[]; | ||
methods: Array<Extract<HttpMethod, 'GET' | 'POST'>>; | ||
}; | ||
@@ -1081,3 +1106,3 @@ pattern: RegExp; | ||
segments: RouteSegment[]; | ||
methods: HttpMethod[]; | ||
methods: Array<HttpMethod | '*'>; | ||
config: Config; | ||
@@ -1084,0 +1109,0 @@ } |
@@ -18,2 +18,3 @@ import fs from 'node:fs'; | ||
import { not_found } from '../utils.js'; | ||
import { SCHEME } from '../../../utils/url.js'; | ||
@@ -35,3 +36,3 @@ const cwd = process.cwd(); | ||
globalThis.fetch = (info, init) => { | ||
if (typeof info === 'string' && !/^\w+:\/\//.test(info)) { | ||
if (typeof info === 'string' && !SCHEME.test(info)) { | ||
throw new Error( | ||
@@ -58,7 +59,10 @@ `Cannot use relative URL (${info}) with global fetch — use \`event.fetch\` instead: https://kit.svelte.dev/docs/web-standards#fetch-apis` | ||
try { | ||
return await vite.ssrLoadModule(url); | ||
return await vite.ssrLoadModule(url, { fixStacktrace: true }); | ||
} catch (/** @type {any} */ err) { | ||
const msg = buildErrorMessage(err, [colors.red(`Internal server error: ${err.message}`)]); | ||
vite.config.logger.error(msg, { error: err }); | ||
if (!vite.config.logger.hasErrorLogged(err)) { | ||
vite.config.logger.error(msg, { error: err }); | ||
} | ||
vite.ws.send({ | ||
@@ -238,3 +242,3 @@ type: 'error', | ||
const url = path.resolve(cwd, file); | ||
const module = await vite.ssrLoadModule(url); | ||
const module = await vite.ssrLoadModule(url, { fixStacktrace: true }); | ||
@@ -254,5 +258,6 @@ if (module.match) { | ||
/** @param {string} stack */ | ||
function fix_stack_trace(stack) { | ||
return stack ? vite.ssrRewriteStacktrace(stack) : stack; | ||
/** @param {Error} error */ | ||
function fix_stack_trace(error) { | ||
vite.ssrFixStacktrace(error); | ||
return error.stack; | ||
} | ||
@@ -400,3 +405,3 @@ | ||
res.statusCode = 500; | ||
res.end(fix_stack_trace(/** @type {string} */ (error.stack))); | ||
res.end(fix_stack_trace(error)); | ||
} | ||
@@ -462,3 +467,3 @@ }); | ||
const { Server } = /** @type {import('types').ServerModule} */ ( | ||
await vite.ssrLoadModule(`${runtime_base}/server/index.js`) | ||
await vite.ssrLoadModule(`${runtime_base}/server/index.js`, { fixStacktrace: true }) | ||
); | ||
@@ -532,3 +537,3 @@ | ||
res.statusCode = 500; | ||
res.end(fix_stack_trace(/** @type {string} */ (error.stack))); | ||
res.end(fix_stack_trace(error)); | ||
} | ||
@@ -535,0 +540,0 @@ }); |
@@ -8,3 +8,3 @@ import fs from 'node:fs'; | ||
import { mkdirp, posixify, read, resolve_entry, rimraf } from '../../utils/filesystem.js'; | ||
import { copy, mkdirp, posixify, read, resolve_entry, rimraf } from '../../utils/filesystem.js'; | ||
import { create_static_module, create_dynamic_module } from '../../core/env.js'; | ||
@@ -549,3 +549,4 @@ import * as sync from '../../core/sync/sync.js'; | ||
// causing us to do a more expensive hydration check. | ||
const client_base = kit.paths.relative || kit.paths.assets ? './' : kit.paths.base || '/'; | ||
const client_base = | ||
kit.paths.relative !== false || kit.paths.assets ? './' : kit.paths.base || '/'; | ||
@@ -724,2 +725,7 @@ new_config = { | ||
copy( | ||
`${out}/server/${kit.appDir}/immutable/assets`, | ||
`${out}/client/${kit.appDir}/immutable/assets` | ||
); | ||
/** @type {import('vite').Manifest} */ | ||
@@ -726,0 +732,0 @@ const client_manifest = JSON.parse(read(`${out}/client/${vite_config.build.manifest}`)); |
@@ -105,2 +105,16 @@ import { client_method } from '../client/singletons.js'; | ||
/** | ||
* A lifecycle function that runs the supplied `callback` immediately before we navigate to a new URL. | ||
* | ||
* If you return a `Promise`, SvelteKit will wait for it to resolve before completing the navigation. This allows you to — for example — use `document.startViewTransition`. Avoid promises that are slow to resolve, since navigation will appear stalled to the user. | ||
* | ||
* If a function (or a `Promise` that resolves to a function) is returned from the callback, it will be called once the DOM has updated. | ||
* | ||
* `onNavigate` must be called during a component initialization. It remains active as long as the component is mounted. | ||
* @type {(callback: (navigation: import('@sveltejs/kit').OnNavigate) => import('../../types/internal.js').MaybePromise<(() => void) | void>) => void} | ||
* @param {(navigation: import('@sveltejs/kit').OnNavigate) => void} callback | ||
* @returns {void} | ||
*/ | ||
export const onNavigate = /* @__PURE__ */ client_method('on_navigate'); | ||
/** | ||
* A lifecycle function that runs the supplied `callback` when the current component mounts, and also whenever we navigate to a new URL. | ||
@@ -107,0 +121,0 @@ * |
@@ -34,3 +34,3 @@ import { DEV } from 'esm-env'; | ||
import { HttpError, Redirect } from '../control.js'; | ||
import { INVALIDATED_PARAM, validate_depends } from '../shared.js'; | ||
import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM, validate_depends } from '../shared.js'; | ||
import { INDEX_KEY, PRELOAD_PRIORITIES, SCROLL_KEY, SNAPSHOT_KEY } from './constants.js'; | ||
@@ -93,2 +93,5 @@ import { stores } from './singletons.js'; | ||
/** @type {Array<(navigation: import('@sveltejs/kit').OnNavigate) => import('types').MaybePromise<(() => void) | void>>} */ | ||
on_navigate: [], | ||
/** @type {Array<(navigation: import('@sveltejs/kit').AfterNavigate) => void>} */ | ||
@@ -304,3 +307,4 @@ after_navigate: [] | ||
willUnload: false, | ||
type: 'enter' | ||
type: 'enter', | ||
complete: Promise.resolve() | ||
}; | ||
@@ -455,8 +459,8 @@ callbacks.after_navigate.forEach((fn) => fn(navigation)); | ||
const load_input = { | ||
route: { | ||
get id() { | ||
route: new Proxy(route, { | ||
get: (target, key) => { | ||
uses.route = true; | ||
return route.id; | ||
return target[/** @type {'id'} */ (key)]; | ||
} | ||
}, | ||
}), | ||
params: new Proxy(params, { | ||
@@ -909,3 +913,3 @@ get: (target, key) => { | ||
* url: URL; | ||
* type: import('@sveltejs/kit').NavigationType; | ||
* type: import('@sveltejs/kit').Navigation["type"]; | ||
* intent?: import('./types').NavigationIntent; | ||
@@ -918,26 +922,13 @@ * delta?: number; | ||
/** @type {import('@sveltejs/kit').Navigation} */ | ||
const navigation = { | ||
from: { | ||
params: current.params, | ||
route: { id: current.route?.id ?? null }, | ||
url: current.url | ||
}, | ||
to: { | ||
params: intent?.params ?? null, | ||
route: { id: intent?.route?.id ?? null }, | ||
url | ||
}, | ||
willUnload: !intent, | ||
type | ||
}; | ||
const nav = create_navigation(current, intent, url, type); | ||
if (delta !== undefined) { | ||
navigation.delta = delta; | ||
nav.navigation.delta = delta; | ||
} | ||
const cancellable = { | ||
...navigation, | ||
...nav.navigation, | ||
cancel: () => { | ||
should_block = true; | ||
nav.reject(new Error('navigation was cancelled')); | ||
} | ||
@@ -951,3 +942,3 @@ }; | ||
return should_block ? null : navigation; | ||
return should_block ? null : nav; | ||
} | ||
@@ -965,3 +956,3 @@ | ||
* } | null; | ||
* type: import('@sveltejs/kit').NavigationType; | ||
* type: import('@sveltejs/kit').Navigation["type"]; | ||
* delta?: number; | ||
@@ -986,5 +977,5 @@ * nav_token?: {}; | ||
const intent = get_navigation_intent(url, false); | ||
const navigation = before_navigate({ url, type, delta, intent }); | ||
const nav = before_navigate({ url, type, delta, intent }); | ||
if (!navigation) { | ||
if (!nav) { | ||
blocked(); | ||
@@ -1002,3 +993,3 @@ return; | ||
if (started) { | ||
stores.navigating.set(navigation); | ||
stores.navigating.set(nav.navigation); | ||
} | ||
@@ -1030,3 +1021,6 @@ | ||
// abort if user navigated during update | ||
if (token !== nav_token) return false; | ||
if (token !== nav_token) { | ||
nav.reject(new Error('navigation was aborted')); | ||
return false; | ||
} | ||
@@ -1107,2 +1101,24 @@ if (navigation_result.type === 'redirect') { | ||
const after_navigate = ( | ||
await Promise.all( | ||
callbacks.on_navigate.map((fn) => | ||
fn(/** @type {import('@sveltejs/kit').OnNavigate} */ (nav.navigation)) | ||
) | ||
) | ||
).filter((value) => typeof value === 'function'); | ||
if (after_navigate.length > 0) { | ||
function cleanup() { | ||
callbacks.after_navigate = callbacks.after_navigate.filter( | ||
// @ts-ignore | ||
(fn) => !after_navigate.includes(fn) | ||
); | ||
} | ||
after_navigate.push(cleanup); | ||
// @ts-ignore | ||
callbacks.after_navigate.push(...after_navigate); | ||
} | ||
root.$set(navigation_result.props); | ||
@@ -1157,4 +1173,6 @@ } else { | ||
nav.fulfil(undefined); | ||
callbacks.after_navigate.forEach((fn) => | ||
fn(/** @type {import('@sveltejs/kit').AfterNavigate} */ (navigation)) | ||
fn(/** @type {import('@sveltejs/kit').AfterNavigate} */ (nav.navigation)) | ||
); | ||
@@ -1355,2 +1373,13 @@ stores.navigating.set(null); | ||
on_navigate: (fn) => { | ||
onMount(() => { | ||
callbacks.on_navigate.push(fn); | ||
return () => { | ||
const i = callbacks.on_navigate.indexOf(fn); | ||
callbacks.on_navigate.splice(i, 1); | ||
}; | ||
}); | ||
}, | ||
disable_scroll_handling: () => { | ||
@@ -1461,2 +1490,4 @@ if (DEV && started && !updating) { | ||
if (!navigating) { | ||
const nav = create_navigation(current, undefined, null, 'leave'); | ||
// If we're navigating, beforeNavigate was already called. If we end up in here during navigation, | ||
@@ -1466,11 +1497,7 @@ // it's due to an external or full-page-reload link, for which we don't want to call the hook again. | ||
const navigation = { | ||
from: { | ||
params: current.params, | ||
route: { id: current.route?.id ?? null }, | ||
url: current.url | ||
}, | ||
to: null, | ||
willUnload: true, | ||
type: 'leave', | ||
cancel: () => (should_block = true) | ||
...nav.navigation, | ||
cancel: () => { | ||
should_block = true; | ||
nav.reject(new Error('navigation was cancelled')); | ||
} | ||
}; | ||
@@ -1838,2 +1865,5 @@ | ||
data_url.pathname = add_data_suffix(url.pathname); | ||
if (url.pathname.endsWith('/')) { | ||
data_url.searchParams.append(TRAILING_SLASH_PARAM, '1'); | ||
} | ||
if (DEV && url.searchParams.has(INVALIDATED_PARAM)) { | ||
@@ -2007,2 +2037,49 @@ throw new Error(`Cannot used reserved query parameter "${INVALIDATED_PARAM}"`); | ||
/** | ||
* @param {import('./types').NavigationState} current | ||
* @param {import('./types').NavigationIntent | undefined} intent | ||
* @param {URL | null} url | ||
* @param {Exclude<import('@sveltejs/kit').NavigationType, 'enter'>} type | ||
*/ | ||
function create_navigation(current, intent, url, type) { | ||
/** @type {(value: any) => void} */ | ||
let fulfil; | ||
/** @type {(error: any) => void} */ | ||
let reject; | ||
const complete = new Promise((f, r) => { | ||
fulfil = f; | ||
reject = r; | ||
}); | ||
// Handle any errors off-chain so that it doesn't show up as an unhandled rejection | ||
complete.catch(() => {}); | ||
/** @type {import('@sveltejs/kit').Navigation} */ | ||
const navigation = { | ||
from: { | ||
params: current.params, | ||
route: { id: current.route?.id ?? null }, | ||
url: current.url | ||
}, | ||
to: url && { | ||
params: intent?.params ?? null, | ||
route: { id: intent?.route?.id ?? null }, | ||
url | ||
}, | ||
willUnload: !intent, | ||
type, | ||
complete | ||
}; | ||
return { | ||
navigation, | ||
// @ts-expect-error | ||
fulfil, | ||
// @ts-expect-error | ||
reject | ||
}; | ||
} | ||
if (DEV) { | ||
@@ -2009,0 +2086,0 @@ // Nasty hack to silence harmless warnings the user can do nothing about |
@@ -24,3 +24,3 @@ import { writable } from 'svelte/store'; | ||
if (!BROWSER) { | ||
if (key === 'before_navigate' || key === 'after_navigate') { | ||
if (key === 'before_navigate' || key === 'after_navigate' || key === 'on_navigate') { | ||
// @ts-expect-error doesn't recognize that both keys here return void so expects a async function | ||
@@ -27,0 +27,0 @@ return () => {}; |
@@ -5,2 +5,3 @@ import { applyAction } from '../app/forms'; | ||
beforeNavigate, | ||
onNavigate, | ||
goto, | ||
@@ -47,2 +48,3 @@ invalidate, | ||
before_navigate: typeof beforeNavigate; | ||
on_navigate: typeof onNavigate; | ||
disable_scroll_handling(): void; | ||
@@ -49,0 +51,0 @@ goto: typeof goto; |
@@ -15,5 +15,5 @@ import { ENDPOINT_METHODS, PAGE_METHODS } from '../../constants.js'; | ||
let handler = mod[method]; | ||
let handler = mod[method] || mod.fallback; | ||
if (!handler && method === 'HEAD') { | ||
if (method === 'HEAD' && mod.GET && !mod.HEAD) { | ||
handler = mod.GET; | ||
@@ -20,0 +20,0 @@ } |
@@ -54,3 +54,3 @@ import * as set_cookie_parser from 'set-cookie-parser'; | ||
if (url.origin !== event.url.origin) { | ||
// allow cookie passthrough for "same-origin" | ||
// Allow cookie passthrough for "credentials: same-origin" and "credentials: include" | ||
// if SvelteKit is serving my.domain.com: | ||
@@ -63,2 +63,4 @@ // - domain.com WILL NOT receive cookies | ||
// leading dot prevents mydomain.com matching domain.com | ||
// Do not forward other cookies for "credentials: include" because we don't know | ||
// which cookie belongs to which domain (browser does not pass this info) | ||
if (`.${url.hostname}`.endsWith(`.${event.url.hostname}`) && credentials !== 'omit') { | ||
@@ -65,0 +67,0 @@ const cookie = get_cookie_header(url, request.headers.get('cookie')); |
@@ -15,2 +15,3 @@ import * as devalue from 'devalue'; | ||
import { SVELTE_KIT_ASSETS } from '../../../constants.js'; | ||
import { SCHEME } from '../../../utils/url.js'; | ||
@@ -155,3 +156,3 @@ // TODO rename this function/module | ||
globalThis.fetch = (info, init) => { | ||
if (typeof info === 'string' && !/^\w+:\/\//.test(info)) { | ||
if (typeof info === 'string' && !SCHEME.test(info)) { | ||
throw new Error( | ||
@@ -158,0 +159,0 @@ `Cannot call \`fetch\` eagerly during server side rendering with relative URL (${info}) — put your \`fetch\` calls inside \`onMount\` or a \`load\` function instead` |
@@ -31,2 +31,7 @@ import { render_response } from './render.js'; | ||
}) { | ||
// reroute to the fallback page to prevent an infinite chain of requests. | ||
if (event.request.headers.get('x-sveltekit-error')) { | ||
return static_error_page(options, status, /** @type {Error} */ (error).message); | ||
} | ||
/** @type {import('./types').Fetched[]} */ | ||
@@ -33,0 +38,0 @@ const fetched = []; |
@@ -32,3 +32,3 @@ import { DEV } from 'esm-env'; | ||
import { action_json_redirect, is_action_json_request } from './page/actions.js'; | ||
import { INVALIDATED_PARAM } from '../shared.js'; | ||
import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM } from '../shared.js'; | ||
@@ -104,3 +104,6 @@ /* global __SVELTEKIT_ADAPTER_NAME__ */ | ||
decoded = strip_data_suffix(decoded) || '/'; | ||
url.pathname = strip_data_suffix(url.pathname) || '/'; | ||
url.pathname = | ||
strip_data_suffix(url.pathname) + | ||
(url.searchParams.get(TRAILING_SLASH_PARAM) === '1' ? '/' : '') || '/'; | ||
url.searchParams.delete(TRAILING_SLASH_PARAM); | ||
invalidated_data_nodes = url.searchParams | ||
@@ -459,2 +462,10 @@ .get(INVALIDATED_PARAM) | ||
if (state.error && event.isSubRequest) { | ||
return await fetch(request, { | ||
headers: { | ||
'x-sveltekit-error': 'true' | ||
} | ||
}); | ||
} | ||
if (state.error) { | ||
@@ -461,0 +472,0 @@ return text('Internal Server Error', { |
@@ -102,11 +102,3 @@ import { DEV } from 'esm-env'; | ||
if (__SVELTEKIT_DEV__ && typeof error == 'object') { | ||
error = new Proxy(error, { | ||
get: (target, property) => { | ||
if (property === 'stack') { | ||
return fix_stack_trace(target.stack); | ||
} | ||
return Reflect.get(target, property, target); | ||
} | ||
}); | ||
fix_stack_trace(error); | ||
} | ||
@@ -113,0 +105,0 @@ |
@@ -7,4 +7,4 @@ /** @type {Record<string, string>} */ | ||
/** @param {string} stack */ | ||
export let fix_stack_trace = (stack) => stack; | ||
/** @param {any} error */ | ||
export let fix_stack_trace = (error) => error?.stack; | ||
@@ -21,5 +21,5 @@ /** @type {(environment: Record<string, string>) => void} */ | ||
/** @param {(stack: string) => string} value */ | ||
/** @param {(error: Error) => string} value */ | ||
export function set_fix_stack_trace(value) { | ||
fix_stack_trace = value; | ||
} |
@@ -15,1 +15,3 @@ /** | ||
export const INVALIDATED_PARAM = 'x-sveltekit-invalidated'; | ||
export const TRAILING_SLASH_PARAM = 'x-sveltekit-trailing-slash'; |
@@ -35,3 +35,3 @@ import { SvelteComponent } from 'svelte'; | ||
set_version(version: string): void; | ||
set_fix_stack_trace(fix_stack_trace: (stack: string) => string): void; | ||
set_fix_stack_trace(fix_stack_trace: (error: unknown) => string): void; | ||
} | ||
@@ -263,3 +263,3 @@ | ||
api: { | ||
methods: HttpMethod[]; | ||
methods: Array<HttpMethod | '*'>; | ||
}; | ||
@@ -269,5 +269,5 @@ page: { | ||
}; | ||
methods: HttpMethod[]; | ||
methods: Array<HttpMethod | '*'>; | ||
prerender: PrerenderOption | undefined; | ||
entries: Array<string> | undefined; | ||
entries: string[] | undefined; | ||
} | ||
@@ -373,2 +373,3 @@ | ||
entries?: PrerenderEntryGenerator; | ||
fallback?: RequestHandler; | ||
}; | ||
@@ -375,0 +376,0 @@ |
@@ -82,2 +82,3 @@ /** | ||
'HEAD', | ||
'fallback', | ||
'prerender', | ||
@@ -84,0 +85,0 @@ 'trailingSlash', |
@@ -139,2 +139,3 @@ const param_pattern = /^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/; | ||
const values = match.slice(1); | ||
const values_needing_match = values.filter((value) => value !== undefined); | ||
@@ -174,2 +175,11 @@ let buffered = 0; | ||
} | ||
// There are no more params and no more values, but all non-empty values have been matched | ||
if ( | ||
!next_param && | ||
!next_value && | ||
Object.keys(result).length === values_needing_match.length | ||
) { | ||
buffered = 0; | ||
} | ||
continue; | ||
@@ -176,0 +186,0 @@ } |
import { BROWSER } from 'esm-env'; | ||
/** | ||
* Matches a URI scheme. See https://www.rfc-editor.org/rfc/rfc3986#section-3.1 | ||
* @type {RegExp} | ||
*/ | ||
export const SCHEME = /^[a-z][a-z\d+\-.]+:/i; | ||
const absolute = /^([a-z]+:)?\/?\//; | ||
const scheme = /^[a-z]+:/; | ||
@@ -11,3 +16,3 @@ /** | ||
export function resolve(base, path) { | ||
if (scheme.test(path)) return path; | ||
if (SCHEME.test(path)) return path; | ||
if (path[0] === '#') return base + path; | ||
@@ -143,2 +148,4 @@ | ||
export function disable_hash(url) { | ||
allow_nodejs_console_log(url); | ||
Object.defineProperty(url, 'hash', { | ||
@@ -158,2 +165,4 @@ get() { | ||
export function disable_search(url) { | ||
allow_nodejs_console_log(url); | ||
for (const property of ['search', 'searchParams']) { | ||
@@ -168,2 +177,15 @@ Object.defineProperty(url, property, { | ||
/** | ||
* Allow URL to be console logged, bypassing disabled properties. | ||
* @param {URL} url | ||
*/ | ||
function allow_nodejs_console_log(url) { | ||
if (!BROWSER) { | ||
// @ts-ignore | ||
url[Symbol.for('nodejs.util.inspect.custom')] = (depth, opts, inspect) => { | ||
return inspect(new URL(url), opts); | ||
}; | ||
} | ||
} | ||
const DATA_SUFFIX = '/__data.json'; | ||
@@ -170,0 +192,0 @@ |
// generated during release, do not modify | ||
/** @type {string} */ | ||
export const VERSION = '1.22.3'; | ||
export const VERSION = '1.25.1'; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
669983
14
19703
15
13
+ Addedtiny-glob@^0.2.9
+ Added@fastify/busboy@2.1.1(transitive)
+ Addedglobalyzer@0.1.0(transitive)
+ Addedglobrex@0.1.2(transitive)
+ Addedtiny-glob@0.2.9(transitive)
+ Addedundici@5.25.4(transitive)
- Removedbusboy@1.6.0(transitive)
- Removedstreamsearch@1.1.0(transitive)
- Removedundici@5.22.1(transitive)
Updatedundici@~5.25.0