@sveltejs/kit
Version:
SvelteKit is the fastest way to build Svelte apps
524 lines (467 loc) • 13.7 kB
TypeScript
import { SvelteComponent } from 'svelte';
import {
Config,
ServerLoad,
Handle,
HandleServerError,
KitConfig,
Load,
RequestHandler,
ResolveOptions,
Server,
ServerInitOptions,
HandleFetch,
Actions,
HandleClientError,
Reroute,
RequestEvent,
SSRManifest,
Emulator,
Adapter,
ServerInit,
ClientInit,
Transporter
} from '@sveltejs/kit';
import {
HttpMethod,
MaybePromise,
PrerenderOption,
RequestOptions,
TrailingSlash
} from './private.js';
export interface ServerModule {
Server: typeof InternalServer;
}
export interface ServerInternalModule {
set_assets(path: string): void;
set_building(): void;
set_manifest(manifest: SSRManifest): void;
set_prerendering(): void;
set_private_env(environment: Record<string, string>): void;
set_public_env(environment: Record<string, string>): void;
set_read_implementation(implementation: (path: string) => ReadableStream): void;
set_safe_public_env(environment: Record<string, string>): void;
set_version(version: string): void;
set_fix_stack_trace(fix_stack_trace: (error: unknown) => string): void;
}
export interface Asset {
file: string;
size: number;
type: string | null;
}
export interface AssetDependencies {
assets: string[];
file: string;
imports: string[];
stylesheets: string[];
fonts: string[];
stylesheet_map: Map<string, { css: Set<string>; assets: Set<string> }>;
}
export interface BuildData {
app_dir: string;
app_path: string;
manifest_data: ManifestData;
out_dir: string;
service_worker: string | null;
client: {
/** Path to the client entry point. */
start: string;
/** Path to the generated `app.js` file that contains the client manifest. Only set in case of `bundleStrategy === 'split'`. */
app?: string;
/** JS files that the client entry point relies on. */
imports: string[];
/**
* JS files that represent the entry points of the layouts/pages.
* An entry is undefined if the layout/page has no component or universal file (i.e. only has a `.server.js` file).
* Only set in case of `router.resolution === 'server'`.
*/
nodes?: Array<string | undefined>;
/**
* CSS files referenced in the entry points of the layouts/pages.
* An entry is undefined if the layout/page has no component or universal file (i.e. only has a `.server.js` file) or if has no CSS.
* Only set in case of `router.resolution === 'server'`.
*/
css?: Array<string[] | undefined>;
/**
* Contains the client route manifest in a form suitable for the server which is used for server side route resolution.
* Notably, it contains all routes, regardless of whether they are prerendered or not (those are missing in the optimized server route manifest).
* Only set in case of `router.resolution === 'server'`.
*/
routes?: SSRClientRoute[];
stylesheets: string[];
fonts: string[];
uses_env_dynamic_public: boolean;
/** Only set in case of `bundleStrategy === 'inline'`. */
inline?: {
script: string;
style: string | undefined;
};
} | null;
server_manifest: import('vite').Manifest;
}
export interface CSRPageNode {
component: typeof SvelteComponent;
universal: {
load?: Load;
trailingSlash?: TrailingSlash;
};
}
export type CSRPageNodeLoader = () => Promise<CSRPageNode>;
/**
* Definition of a client side route.
* The boolean in the tuples indicates whether the route has a server load.
*/
export type CSRRoute = {
id: string;
exec(path: string): undefined | Record<string, string>;
errors: Array<CSRPageNodeLoader | undefined>;
layouts: Array<[has_server_load: boolean, node_loader: CSRPageNodeLoader] | undefined>;
leaf: [has_server_load: boolean, node_loader: CSRPageNodeLoader];
};
/**
* Definition of a client side route as transported via `<pathname>/__route.js` when using server-side route resolution.
*/
export type CSRRouteServer = {
id: string;
errors: Array<number | undefined>;
layouts: Array<[has_server_load: boolean, node_id: number] | undefined>;
leaf: [has_server_load: boolean, node_id: number];
nodes: Record<string, CSRPageNodeLoader>;
};
export interface Deferred {
fulfil: (value: any) => void;
reject: (error: Error) => void;
}
export type GetParams = (match: RegExpExecArray) => Record<string, string>;
export interface ServerHooks {
handleFetch: HandleFetch;
handle: Handle;
handleError: HandleServerError;
reroute: Reroute;
transport: Record<string, Transporter>;
init?: ServerInit;
}
export interface ClientHooks {
handleError: HandleClientError;
reroute: Reroute;
transport: Record<string, Transporter>;
init?: ClientInit;
}
export interface Env {
private: Record<string, string>;
public: Record<string, string>;
}
export class InternalServer extends Server {
init(options: ServerInitOptions): Promise<void>;
respond(
request: Request,
options: RequestOptions & {
prerendering?: PrerenderOptions;
read: (file: string) => Buffer;
/** A hook called before `handle` during dev, so that `AsyncLocalStorage` can be populated. */
before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
emulator?: Emulator;
}
): Promise<Response>;
}
export interface ManifestData {
/** Static files from `kit.config.files.assets`. */
assets: Asset[];
hooks: {
client: string | null;
server: string | null;
universal: string | null;
};
nodes: PageNode[];
routes: RouteData[];
matchers: Record<string, string>;
}
export interface PageNode {
depth: number;
/** The `+page/layout.svelte`. */
component?: string; // TODO supply default component if it's missing (bit of an edge case)
/** The `+page/layout.js/.ts`. */
universal?: string;
/** The `+page/layout.server.js/ts`. */
server?: string;
parent_id?: string;
parent?: PageNode;
/** Filled with the pages that reference this layout (if this is a layout). */
child_pages?: PageNode[];
}
export interface PrerenderDependency {
response: Response;
body: null | string | Uint8Array;
}
export interface PrerenderOptions {
cache?: string; // including this here is a bit of a hack, but it makes it easy to add <meta http-equiv>
fallback?: boolean;
dependencies: Map<string, PrerenderDependency>;
/** True for the duration of a call to the `reroute` hook */
inside_reroute?: boolean;
}
export type RecursiveRequired<T> = {
// Recursive implementation of TypeScript's Required utility type.
// Will recursively continue until it reaches a primitive or Function
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
[K in keyof T]-?: Extract<T[K], Function> extends never // If it does not have a Function type
? RecursiveRequired<T[K]> // recursively continue through.
: T[K]; // Use the exact type for everything else
};
export type RequiredResolveOptions = Required<ResolveOptions>;
export interface RouteParam {
name: string;
matcher: string;
optional: boolean;
rest: boolean;
chained: boolean;
}
/**
* Represents a route segment in the app. It can either be an intermediate node
* with only layout/error pages, or a leaf, at which point either `page` and `leaf`
* or `endpoint` is set.
*/
export interface RouteData {
id: string;
parent: RouteData | null;
segment: string;
pattern: RegExp;
params: RouteParam[];
layout: PageNode | null;
error: PageNode | null;
leaf: PageNode | null;
page: {
layouts: Array<number | undefined>;
errors: Array<number | undefined>;
leaf: number;
} | null;
endpoint: {
file: string;
} | null;
}
export type ServerRedirectNode = {
type: 'redirect';
location: string;
};
export type ServerNodesResponse = {
type: 'data';
/**
* If `null`, then there was no load function <- TODO is this outdated now with the recent changes?
*/
nodes: Array<ServerDataNode | ServerDataSkippedNode | ServerErrorNode | null>;
};
export type ServerDataResponse = ServerRedirectNode | ServerNodesResponse;
/**
* Signals a successful response of the server `load` function.
* The `uses` property tells the client when it's possible to reuse this data
* in a subsequent request.
*/
export interface ServerDataNode {
type: 'data';
/**
* The serialized version of this contains a serialized representation of any deferred promises,
* which will be resolved later through chunk nodes.
*/
data: Record<string, any> | null;
uses: Uses;
slash?: TrailingSlash;
}
/**
* Resolved data/error of a deferred promise.
*/
export interface ServerDataChunkNode {
type: 'chunk';
id: number;
data?: Record<string, any>;
error?: any;
}
/**
* Signals that the server `load` function was not run, and the
* client should use what it has in memory.
*/
export interface ServerDataSkippedNode {
type: 'skip';
}
/**
* Signals that the server `load` function failed.
*/
export interface ServerErrorNode {
type: 'error';
error: App.Error;
/**
* Only set for HttpErrors.
*/
status?: number;
}
export interface ServerMetadataRoute {
config: any;
api: {
methods: Array<HttpMethod | '*'>;
};
page: {
methods: Array<'GET' | 'POST'>;
};
methods: Array<HttpMethod | '*'>;
prerender: PrerenderOption | undefined;
entries: string[] | undefined;
}
export interface ServerMetadata {
nodes: Array<{
/** Also `true` when using `trailingSlash`, because we need to do a server request in that case to get its value. */
has_server_load: boolean;
}>;
routes: Map<string, ServerMetadataRoute>;
}
export interface SSRComponent {
default: {
render(
props: Record<string, any>,
opts: { context: Map<any, any> }
): {
html: string;
head: string;
css: {
code: string;
map: any; // TODO
};
};
};
}
export type SSRComponentLoader = () => Promise<SSRComponent>;
export interface UniversalNode {
load?: Load;
prerender?: PrerenderOption;
ssr?: boolean;
csr?: boolean;
trailingSlash?: TrailingSlash;
config?: any;
entries?: PrerenderEntryGenerator;
}
export interface ServerNode {
load?: ServerLoad;
prerender?: PrerenderOption;
ssr?: boolean;
csr?: boolean;
trailingSlash?: TrailingSlash;
actions?: Actions;
config?: any;
entries?: PrerenderEntryGenerator;
}
export interface SSRNode {
/** index into the `nodes` array in the generated `client/app.js`. */
index: number;
/** external JS files that are loaded on the client. `imports[0]` is the entry point (e.g. `client/nodes/0.js`) */
imports: string[];
/** external CSS files that are loaded on the client */
stylesheets: string[];
/** external font files that are loaded on the client */
fonts: string[];
universal_id?: string;
server_id?: string;
/** inlined styles. */
inline_styles?(): MaybePromise<Record<string, string>>;
/** Svelte component */
component?: SSRComponentLoader;
/** +page.js or +layout.js */
universal?: UniversalNode;
/** +page.server.js, +layout.server.js, or +server.js */
server?: ServerNode;
}
export type SSRNodeLoader = () => Promise<SSRNode>;
export interface SSROptions {
app_template_contains_nonce: boolean;
csp: ValidatedConfig['kit']['csp'];
csrf_check_origin: boolean;
embedded: boolean;
env_public_prefix: string;
env_private_prefix: string;
hash_routing: boolean;
hooks: ServerHooks;
preload_strategy: ValidatedConfig['kit']['output']['preloadStrategy'];
root: SSRComponent['default'];
service_worker: boolean;
templates: {
app(values: {
head: string;
body: string;
assets: string;
nonce: string;
env: Record<string, string>;
}): string;
error(values: { message: string; status: number }): string;
};
version_hash: string;
}
export interface PageNodeIndexes {
errors: Array<number | undefined>;
layouts: Array<number | undefined>;
leaf: number;
}
export type PrerenderEntryGenerator = () => MaybePromise<Array<Record<string, string>>>;
export type SSREndpoint = Partial<Record<HttpMethod, RequestHandler>> & {
prerender?: PrerenderOption;
trailingSlash?: TrailingSlash;
config?: any;
entries?: PrerenderEntryGenerator;
fallback?: RequestHandler;
};
export interface SSRRoute {
id: string;
pattern: RegExp;
params: RouteParam[];
page: PageNodeIndexes | null;
endpoint: (() => Promise<SSREndpoint>) | null;
endpoint_id?: string;
}
export interface SSRClientRoute {
id: string;
pattern: RegExp;
params: RouteParam[];
errors: Array<number | undefined>;
layouts: Array<[has_server_load: boolean, node_id: number] | undefined>;
leaf: [has_server_load: boolean, node_id: number];
}
export interface SSRState {
fallback?: string;
getClientAddress(): string;
/**
* True if we're currently attempting to render an error page.
*/
error: boolean;
/**
* Allows us to prevent `event.fetch` from making infinitely looping internal requests.
*/
depth: number;
platform?: any;
prerendering?: PrerenderOptions;
/**
* When fetching data from a +server.js endpoint in `load`, the page's
* prerender option is inherited by the endpoint, unless overridden.
*/
prerender_default?: PrerenderOption;
read?: (file: string) => Buffer;
/**
* Used to setup `__SVELTEKIT_TRACK__` which checks if a used feature is supported.
* E.g. if `read` from `$app/server` is used, it checks whether the route's config is compatible.
*/
before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
emulator?: Emulator;
}
export type StrictBody = string | ArrayBufferView;
export interface Uses {
dependencies: Set<string>;
params: Set<string>;
parent: boolean;
route: boolean;
url: boolean;
search_params: Set<string>;
}
export type ValidatedConfig = Config & {
kit: ValidatedKitConfig;
extensions: string[];
};
export type ValidatedKitConfig = Omit<RecursiveRequired<KitConfig>, 'adapter'> & {
adapter?: Adapter;
};
export * from '../exports/index.js';
export * from './private.js';