@sveltejs/kit
Version:
SvelteKit is the fastest way to build Svelte apps
136 lines (116 loc) • 3.77 kB
JavaScript
import { text } from '@sveltejs/kit';
import { ENDPOINT_METHODS } from '../../constants.js';
import { manifest } from './internal.js';
import * as e from '../../messages/server-errors.js';
/**
* @param {Partial<Record<import('types').HttpMethod, any>>} mod
* @param {import('types').HttpMethod} method
*/
export function method_not_allowed(mod, method) {
return text(`${method} method not allowed`, {
status: 405,
headers: {
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405
// "The server must generate an Allow header field in a 405 status code response"
allow: allowed_methods(mod).join(', ')
}
});
}
/** @param {Partial<Record<import('types').HttpMethod, any>>} mod */
export function allowed_methods(mod) {
const allowed = ENDPOINT_METHODS.filter((method) => method in mod);
// if there's no HEAD handler, but we have a GET handler, we respond to
// HEAD requests using the GET handler and omit the response body.
if ('GET' in mod && !('HEAD' in mod)) {
allowed.push('HEAD');
}
return allowed;
}
/**
* @param {number} status
* @param {string} location
*/
export function redirect_response(status, location) {
const response = new Response(undefined, {
status,
headers: { location }
});
return response;
}
/**
* @param {Response} response
*/
export function with_version_header(response) {
if (__SVELTEKIT_APP_VERSION_CHECKS_ENABLED__) {
response.headers.set('x-sveltekit-version', __SVELTEKIT_APP_VERSION__);
}
return response;
}
/**
* Throws an error explaining why data returned from `load` couldn't be serialized by devalue,
* whose error becomes the cause
* @param {import('@sveltejs/kit').RequestEvent} event
* @param {Error & { path: string }} error
* @returns {never}
*/
export function throw_devalue_error(event, error) {
const id = /** @type {string} */ (event.route.id);
if (error.path) {
e.load_not_serializable({ id, message: error.message, path: error.path }, { cause: error });
}
if (error.path === '') {
e.load_not_plain_object({ id }, { cause: error });
}
// belt and braces — this should never happen
throw new Error(error.message, { cause: error });
}
/**
* @param {import('types').ServerDataNode} node
*/
export function serialize_uses(node) {
const uses = {};
if (node.uses && node.uses.dependencies.size > 0) {
uses.dependencies = Array.from(node.uses.dependencies);
}
if (node.uses && node.uses.search_params.size > 0) {
uses.search_params = Array.from(node.uses.search_params);
}
if (node.uses && node.uses.params.size > 0) {
uses.params = Array.from(node.uses.params);
}
if (node.uses?.parent) uses.parent = 1;
if (node.uses?.route) uses.route = 1;
if (node.uses?.url) uses.url = 1;
return uses;
}
/**
* Returns `true` if the given path was prerendered
* @param {string} pathname Should include the base and be decoded
*/
export function has_prerendered_path(pathname) {
return (
manifest.prerendered_routes.has(pathname) ||
(pathname.at(-1) === '/' && manifest.prerendered_routes.has(pathname.slice(0, -1)))
);
}
/**
* Returns the filename without the extension. e.g., `+page.server`, `+page`, etc.
* @param {string | undefined} node_id
* @returns {string}
*/
export function get_node_type(node_id) {
const parts = node_id?.split('/');
const filename = parts?.at(-1);
if (!filename) return 'unknown';
const dot_parts = filename.split('.');
return dot_parts.slice(0, -1).join('.');
}
/**
* Counts HTML comments that are not SSI directives (which start with `<!--#`).
* Used to detect when `transformPageChunk` removes comments that Svelte needs for hydration.
* @param {string} str
* @returns {number}
*/
export function count_non_ssi_comments(str) {
return (str.match(/<!--(?!#)/g) ?? []).length;
}