@sveltejs/kit
Advanced tools
Comparing version 2.10.1 to 2.11.0
{ | ||
"name": "@sveltejs/kit", | ||
"version": "2.10.1", | ||
"version": "2.11.0", | ||
"description": "SvelteKit is the fastest way to build Svelte apps", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -155,6 +155,10 @@ import path from 'node:path'; | ||
${client_hooks_file ? 'init: client_hooks.init,' : ''} | ||
reroute: ${universal_hooks_file ? 'universal_hooks.reroute || ' : ''}(() => {}) | ||
reroute: ${universal_hooks_file ? 'universal_hooks.reroute || ' : ''}(() => {}), | ||
transport: ${universal_hooks_file ? 'universal_hooks.transport || ' : ''}{} | ||
}; | ||
export const decoders = Object.fromEntries(Object.entries(hooks.transport).map(([k, v]) => [k, v.decode])); | ||
export const decode = (type, value) => decoders[type](value); | ||
export { default as root } from '../root.${isSvelte5Plus() ? 'js' : 'svelte'}'; | ||
@@ -161,0 +165,0 @@ ` |
@@ -74,3 +74,4 @@ import path from 'node:path'; | ||
let reroute; | ||
${universal_hooks ? `({ reroute } = await import(${s(universal_hooks)}));` : ''} | ||
let transport; | ||
${universal_hooks ? `({ reroute, transport } = await import(${s(universal_hooks)}));` : ''} | ||
@@ -81,4 +82,5 @@ return { | ||
handleError, | ||
init, | ||
reroute, | ||
init, | ||
transport | ||
}; | ||
@@ -85,0 +87,0 @@ } |
@@ -729,2 +729,3 @@ import 'svelte'; // pick up `declare module "*.svelte"` | ||
* The [`init`](https://svelte.dev/docs/kit/hooks#Shared-hooks-init) will be invoked before the server responds to its first request | ||
* @since 2.10.0 | ||
*/ | ||
@@ -735,2 +736,3 @@ export type ServerInit = () => MaybePromise<void>; | ||
* The [`init`](https://svelte.dev/docs/kit/hooks#Shared-hooks-init) will be invoked once the app starts in the browser | ||
* @since 2.10.0 | ||
*/ | ||
@@ -746,2 +748,39 @@ export type ClientInit = () => MaybePromise<void>; | ||
/** | ||
* The [`transport`](https://svelte.dev/docs/kit/hooks#Universal-hooks-transport) hook allows you to transport custom types across the server/client boundary. | ||
* | ||
* Each transporter has a pair of `encode` and `decode` functions. On the server, `encode` determines whether a value is an instance of the custom type and, if so, returns a non-falsy encoding of the value which can be an object or an array (or `false` otherwise). | ||
* | ||
* In the browser, `decode` turns the encoding back into an instance of the custom type. | ||
* | ||
* ```ts | ||
* import type { Transport } from '@sveltejs/kit'; | ||
* | ||
* declare class MyCustomType { | ||
* data: any | ||
* } | ||
* | ||
* // hooks.js | ||
* export const transport: Transport = { | ||
* MyCustomType: { | ||
* encode: (value) => value instanceof MyCustomType && [value.data], | ||
* decode: ([data]) => new MyCustomType(data) | ||
* } | ||
* }; | ||
* ``` | ||
* @since 2.11.0 | ||
*/ | ||
export type Transport = Record<string, Transporter>; | ||
/** | ||
* A member of the [`transport`](https://svelte.dev/docs/kit/hooks#Universal-hooks-transport) hook. | ||
*/ | ||
export interface Transporter< | ||
T = any, | ||
U = Exclude<any, false | 0 | '' | null | undefined | typeof NaN> | ||
> { | ||
encode: (value: T) => false | U; | ||
decode: (data: U) => T; | ||
} | ||
/** | ||
* The generic form of `PageLoad` and `LayoutLoad`. You should import those from `./$types` (see [generated types](https://svelte.dev/docs/kit/types#Generated-types)) | ||
@@ -748,0 +787,0 @@ * rather than using `Load` directly. |
import * as devalue from 'devalue'; | ||
import { DEV } from 'esm-env'; | ||
import { invalidateAll } from './navigation.js'; | ||
import { applyAction } from '../client/client.js'; | ||
import { app, applyAction } from '../client/client.js'; | ||
@@ -32,5 +32,7 @@ export { applyAction }; | ||
const parsed = JSON.parse(result); | ||
if (parsed.data) { | ||
parsed.data = devalue.parse(parsed.data); | ||
parsed.data = devalue.parse(parsed.data, app.decoders); | ||
} | ||
return parsed; | ||
@@ -37,0 +39,0 @@ } |
@@ -29,2 +29,6 @@ import { SvelteComponent } from 'svelte'; | ||
decode: (type: string, value: any) => any; | ||
decoders: Record<string, (data: any) => any>; | ||
root: typeof SvelteComponent; | ||
@@ -58,3 +62,3 @@ } | ||
constructors: Array<typeof SvelteComponent>; | ||
components?: Array<SvelteComponent>; | ||
components?: SvelteComponent[]; | ||
page: Page; | ||
@@ -61,0 +65,0 @@ form?: Record<string, any> | null; |
@@ -200,2 +200,5 @@ import { HttpError, SvelteKitError, Redirect } from '../../control.js'; | ||
const reducers = { | ||
...Object.fromEntries( | ||
Object.entries(options.hooks.transport).map(([key, value]) => [key, value.encode]) | ||
), | ||
/** @param {any} thing */ | ||
@@ -202,0 +205,0 @@ Promise: (thing) => { |
@@ -79,3 +79,4 @@ import { respond } from './respond.js'; | ||
handleFetch: module.handleFetch || (({ request, fetch }) => fetch(request)), | ||
reroute: module.reroute || (() => {}) | ||
reroute: module.reroute || (() => {}), | ||
transport: module.transport || {} | ||
}; | ||
@@ -94,3 +95,4 @@ | ||
handleFetch: ({ request, fetch }) => fetch(request), | ||
reroute: () => {} | ||
reroute: () => {}, | ||
transport: {} | ||
}; | ||
@@ -97,0 +99,0 @@ } else { |
@@ -64,3 +64,7 @@ import * as devalue from 'devalue'; | ||
// through knowing where the related interface is used. | ||
data: stringify_action_response(data.data, /** @type {string} */ (event.route.id)) | ||
data: stringify_action_response( | ||
data.data, | ||
/** @type {string} */ (event.route.id), | ||
options.hooks.transport | ||
) | ||
}); | ||
@@ -72,3 +76,7 @@ } else { | ||
// @ts-expect-error see comment above | ||
data: stringify_action_response(data, /** @type {string} */ (event.route.id)) | ||
data: stringify_action_response( | ||
data, | ||
/** @type {string} */ (event.route.id), | ||
options.hooks.transport | ||
) | ||
}); | ||
@@ -259,5 +267,15 @@ } | ||
* @param {string} route_id | ||
* @param {import('types').ServerHooks['transport']} transport | ||
*/ | ||
export function uneval_action_response(data, route_id) { | ||
return try_deserialize(data, devalue.uneval, route_id); | ||
export function uneval_action_response(data, route_id, transport) { | ||
const replacer = (/** @type {any} */ thing) => { | ||
for (const key in transport) { | ||
const encoded = transport[key].encode(thing); | ||
if (encoded) { | ||
return `app.decode('${key}', ${devalue.uneval(encoded, replacer)})`; | ||
} | ||
} | ||
}; | ||
return try_serialize(data, (value) => devalue.uneval(value, replacer), route_id); | ||
} | ||
@@ -269,5 +287,10 @@ | ||
* @param {string} route_id | ||
* @param {import('types').ServerHooks['transport']} transport | ||
*/ | ||
function stringify_action_response(data, route_id) { | ||
return try_deserialize(data, devalue.stringify, route_id); | ||
function stringify_action_response(data, route_id, transport) { | ||
const encoders = Object.fromEntries( | ||
Object.entries(transport).map(([key, value]) => [key, value.encode]) | ||
); | ||
return try_serialize(data, (value) => devalue.stringify(value, encoders), route_id); | ||
} | ||
@@ -280,3 +303,3 @@ | ||
*/ | ||
function try_deserialize(data, fn, route_id) { | ||
function try_serialize(data, fn, route_id) { | ||
try { | ||
@@ -283,0 +306,0 @@ return fn(data); |
@@ -324,8 +324,16 @@ import * as devalue from 'devalue'; | ||
// When resolving, the id might not yet be available due to the data | ||
// be evaluated upon init of kit, so we use a timeout to retry | ||
properties.push(`resolve: ({ id, data, error }) => { | ||
const { fulfil, reject } = deferred.get(id); | ||
deferred.delete(id); | ||
if (error) reject(error); | ||
else fulfil(data); | ||
const try_to_resolve = () => { | ||
if (!deferred.has(id)) { | ||
setTimeout(try_to_resolve, 0); | ||
return; | ||
} | ||
const { fulfil, reject } = deferred.get(id); | ||
deferred.delete(id); | ||
if (error) reject(error); | ||
else fulfil(data); | ||
} | ||
try_to_resolve(); | ||
}`); | ||
@@ -346,8 +354,7 @@ } | ||
blocks.push(`const data = ${data};`); | ||
if (form_value) { | ||
serialized.form = uneval_action_response( | ||
form_value, | ||
/** @type {string} */ (event.route.id) | ||
/** @type {string} */ (event.route.id), | ||
options.hooks.transport | ||
); | ||
@@ -362,3 +369,3 @@ } | ||
`node_ids: [${branch.map(({ node }) => node.index).join(', ')}]`, | ||
'data', | ||
`data: ${data}`, | ||
`form: ${serialized.form}`, | ||
@@ -579,2 +586,9 @@ `error: ${serialized.error}` | ||
return `${global}.defer(${id})`; | ||
} else { | ||
for (const key in options.hooks.transport) { | ||
const encoded = options.hooks.transport[key].encode(thing); | ||
if (encoded) { | ||
return `app.decode('${key}', ${devalue.uneval(encoded, replacer)})`; | ||
} | ||
} | ||
} | ||
@@ -581,0 +595,0 @@ } |
@@ -22,3 +22,4 @@ import { SvelteComponent } from 'svelte'; | ||
ServerInit, | ||
ClientInit | ||
ClientInit, | ||
Transporter | ||
} from '@sveltejs/kit'; | ||
@@ -115,2 +116,3 @@ import { | ||
reroute: Reroute; | ||
transport: Record<string, Transporter>; | ||
init?: ServerInit; | ||
@@ -122,2 +124,3 @@ } | ||
reroute: Reroute; | ||
transport: Record<string, Transporter>; | ||
init?: ClientInit; | ||
@@ -124,0 +127,0 @@ } |
@@ -172,4 +172,5 @@ import fs from 'node:fs'; | ||
const stats = fs.statSync(entry); | ||
if (stats.isDirectory()) { | ||
return resolve_entry(path.join(entry, 'index')); | ||
const index = path.join(entry, 'index'); | ||
if (stats.isDirectory() && fs.existsSync(index)) { | ||
return resolve_entry(index); | ||
} | ||
@@ -176,0 +177,0 @@ |
// generated during release, do not modify | ||
/** @type {string} */ | ||
export const VERSION = '2.10.1'; | ||
export const VERSION = '2.11.0'; |
Sorry, the diff of this file is too big to display
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
749202
21738