Socket
Socket
Sign inDemoInstall

@remix-run/server-runtime

Package Overview
Dependencies
8
Maintainers
2
Versions
935
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.0-nightly-12e88ce-20230120 to 0.0.0-nightly-142f47be5-20240507

dist/deprecations.d.ts

18

dist/build.d.ts

@@ -1,4 +0,5 @@

import type { DataFunctionArgs } from "./routeModules";
import type { ActionFunctionArgs, LoaderFunctionArgs } from "./routeModules";
import type { AssetsManifest, EntryContext, FutureConfig } from "./entry";
import type { ServerRouteManifest } from "./routes";
import type { AppLoadContext } from "./data";
/**

@@ -8,2 +9,3 @@ * The output of the compiler for the server build.

export interface ServerBuild {
mode: string;
entry: {

@@ -14,15 +16,17 @@ module: ServerEntryModule;

assets: AssetsManifest;
basename?: string;
publicPath: string;
assetsBuildDirectory: string;
future: FutureConfig;
dev?: {
liveReloadPort: number;
};
isSpaMode: boolean;
}
export interface HandleDocumentRequestFunction {
(request: Request, responseStatusCode: number, responseHeaders: Headers, context: EntryContext): Promise<Response> | Response;
(request: Request, responseStatusCode: number, responseHeaders: Headers, context: EntryContext, loadContext: AppLoadContext): Promise<Response> | Response;
}
export interface HandleDataRequestFunction {
(response: Response, args: DataFunctionArgs): Promise<Response> | Response;
(response: Response, args: LoaderFunctionArgs | ActionFunctionArgs): Promise<Response> | Response;
}
export interface HandleErrorFunction {
(error: unknown, args: LoaderFunctionArgs | ActionFunctionArgs): void;
}
/**

@@ -35,2 +39,4 @@ * A module that serves as the entry point for a Remix app during server

handleDataRequest?: HandleDataRequestFunction;
handleError?: HandleErrorFunction;
streamTimeout?: number;
}

@@ -15,3 +15,3 @@ import type { CookieParseOptions, CookieSerializeOptions } from "cookie";

}
export declare type CookieOptions = CookieParseOptions & CookieSerializeOptions & CookieSignatureOptions;
export type CookieOptions = CookieParseOptions & CookieSerializeOptions & CookieSignatureOptions;
/**

@@ -54,3 +54,3 @@ * A HTTP cookie.

}
export declare type CreateCookieFunction = (name: string, cookieOptions?: CookieOptions) => Cookie;
export type CreateCookieFunction = (name: string, cookieOptions?: CookieOptions) => Cookie;
/**

@@ -65,3 +65,3 @@ * Creates a logical container for managing a browser cookie from the server.

}) => CreateCookieFunction;
export declare type IsCookieFunction = (object: any) => object is Cookie;
export type IsCookieFunction = (object: any) => object is Cookie;
/**

@@ -68,0 +68,0 @@ * Returns true if an object is a Remix cookie container.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -19,2 +19,13 @@ * Copyright (c) Remix Software Inc.

/**
* A HTTP cookie.
*
* A Cookie is a logical container for metadata about a HTTP cookie; its name
* and options. But it doesn't contain a value. Instead, it has `parse()` and
* `serialize()` methods that allow a single instance to be reused for
* parsing/encoding multiple different values.
*
* @see https://remix.run/utils/cookies#cookie-api
*/
/**
* Creates a logical container for managing a browser cookie from the server.

@@ -29,6 +40,5 @@ *

let {
secrets,
secrets = [],
...options
} = {
secrets: [],
path: "/",

@@ -35,0 +45,0 @@ sameSite: "lax",

@@ -1,2 +0,2 @@

export declare type SignFunction = (value: string, secret: string) => Promise<string>;
export declare type UnsignFunction = (cookie: string, secret: string) => Promise<string | false>;
export type SignFunction = (value: string, secret: string) => Promise<string>;
export type UnsignFunction = (cookie: string, secret: string) => Promise<string | false>;

@@ -1,5 +0,7 @@

import type { ActionFunction, DataFunctionArgs, LoaderFunction } from "./routeModules";
import type { ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs, ResponseStub } from "./routeModules";
/**
* An object of unknown type for route loaders and actions provided by the
* server's `getLoadContext()` function.
* server's `getLoadContext()` function. This is defined as an empty interface
* specifically so apps can leverage declaration merging to augment this type
* globally: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
*/

@@ -12,16 +14,20 @@ export interface AppLoadContext {

*/
export declare type AppData = any;
export declare function callRouteActionRR({ loadContext, action, params, request, routeId, }: {
export type AppData = unknown;
export declare function callRouteAction({ loadContext, action, params, request, routeId, singleFetch, response, }: {
request: Request;
action: ActionFunction;
params: DataFunctionArgs["params"];
params: ActionFunctionArgs["params"];
loadContext: AppLoadContext;
routeId: string;
}): Promise<Response>;
export declare function callRouteLoaderRR({ loadContext, loader, params, request, routeId, }: {
singleFetch: boolean;
response?: ResponseStub;
}): Promise<{} | Response | null>;
export declare function callRouteLoader({ loadContext, loader, params, request, routeId, singleFetch, response, }: {
request: Request;
loader: LoaderFunction;
params: DataFunctionArgs["params"];
params: LoaderFunctionArgs["params"];
loadContext: AppLoadContext;
routeId: string;
}): Promise<import("@remix-run/router").UNSAFE_DeferredData | Response>;
singleFetch: boolean;
response?: ResponseStub;
}): Promise<{} | Response | null>;
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -17,3 +17,14 @@ * Copyright (c) Remix Software Inc.

async function callRouteActionRR({
/**
* An object of unknown type for route loaders and actions provided by the
* server's `getLoadContext()` function. This is defined as an empty interface
* specifically so apps can leverage declaration merging to augment this type
* globally: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
*/
/**
* Data for a route that was returned from a `loader()`.
*/
async function callRouteAction({
loadContext,

@@ -23,3 +34,5 @@ action,

request,
routeId
routeId,
singleFetch,
response
}) {

@@ -29,3 +42,4 @@ let result = await action({

context: loadContext,
params
params,
response
});

@@ -35,5 +49,10 @@ if (result === undefined) {

}
// Allow naked object returns when single fetch is enabled
if (singleFetch) {
return result;
}
return responses.isResponse(result) ? result : responses.json(result);
}
async function callRouteLoaderRR({
async function callRouteLoader({
loadContext,

@@ -43,3 +62,5 @@ loader,

request,
routeId
routeId,
singleFetch,
response
}) {

@@ -49,3 +70,4 @@ let result = await loader({

context: loadContext,
params
params,
response
});

@@ -61,2 +83,7 @@ if (result === undefined) {

}
// Allow naked object returns when single fetch is enabled
if (singleFetch) {
return result;
}
return responses.isResponse(result) ? result : responses.json(result);

@@ -83,3 +110,12 @@ }

}
return new Request(url.href, request);
let init = {
method: request.method,
body: request.body,
headers: request.headers,
signal: request.signal
};
if (init.body) {
init.duplex = "half";
}
return new Request(url.href, init);
}

@@ -89,6 +125,15 @@ function stripDataParam(request) {

url.searchParams.delete("_data");
return new Request(url.href, request);
let init = {
method: request.method,
body: request.body,
headers: request.headers,
signal: request.signal
};
if (init.body) {
init.duplex = "half";
}
return new Request(url.href, init);
}
exports.callRouteActionRR = callRouteActionRR;
exports.callRouteLoaderRR = callRouteLoaderRR;
exports.callRouteAction = callRouteAction;
exports.callRouteLoader = callRouteLoader;
import type { StaticHandlerContext } from "@remix-run/router";
import type { SerializedError } from "./errors";
import type { RouteManifest, ServerRouteManifest, EntryRoute } from "./routes";

@@ -7,15 +8,25 @@ import type { RouteModules, EntryRouteModule } from "./routeModules";

routeModules: RouteModules<EntryRouteModule>;
criticalCss?: string;
serverHandoffString?: string;
serverHandoffStream?: ReadableStream<Uint8Array>;
renderMeta?: {
didRenderScripts?: boolean;
streamCache?: Record<number, Promise<void> & {
result?: {
done: boolean;
value: string;
};
error?: unknown;
}>;
};
staticHandlerContext: StaticHandlerContext;
future: FutureConfig;
isSpaMode: boolean;
serializeError(error: Error): SerializedError;
}
export interface FutureConfig {
unstable_cssModules: true;
unstable_cssSideEffectImports: boolean;
unstable_dev: false | {
remixRequestHandlerPath?: string;
};
unstable_vanillaExtract: boolean;
v2_errorBoundary: boolean;
v2_meta: boolean;
v3_fetcherPersist: boolean;
v3_relativeSplatPath: boolean;
v3_throwAbortReason: boolean;
unstable_singleFetch: boolean;
}

@@ -30,3 +41,4 @@ export interface AssetsManifest {

version: string;
hmrRuntime?: string;
}
export declare function createEntryRouteModules(manifest: ServerRouteManifest): RouteModules<EntryRouteModule>;
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

import type { StaticHandlerContext } from "@remix-run/router";
import { ServerMode } from "./mode";
/**

@@ -43,12 +44,9 @@ * This thing probably warrants some explanation.

*/
export interface ThrownResponse<T = any> {
status: number;
statusText: string;
data: T;
}
export declare type SerializedError = {
export declare function sanitizeError<T = unknown>(error: T, serverMode: ServerMode): T | Error;
export declare function sanitizeErrors(errors: NonNullable<StaticHandlerContext["errors"]>, serverMode: ServerMode): {};
export type SerializedError = {
message: string;
stack?: string;
};
export declare function serializeError(error: Error): Promise<SerializedError>;
export declare function serializeErrors(errors: StaticHandlerContext["errors"]): StaticHandlerContext["errors"];
export declare function serializeError(error: Error, serverMode: ServerMode): SerializedError;
export declare function serializeErrors(errors: StaticHandlerContext["errors"], serverMode: ServerMode): StaticHandlerContext["errors"];
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -16,2 +16,3 @@ * Copyright (c) Remix Software Inc.

var router = require('@remix-run/router');
var mode = require('./mode.js');

@@ -60,11 +61,29 @@ /**

// TODO Re-export as ErrorResponse?
function sanitizeError(error, serverMode) {
if (error instanceof Error && serverMode !== mode.ServerMode.Development) {
let sanitized = new Error("Unexpected Server Error");
sanitized.stack = undefined;
return sanitized;
}
return error;
}
function sanitizeErrors(errors, serverMode) {
return Object.entries(errors).reduce((acc, [routeId, error]) => {
return Object.assign(acc, {
[routeId]: sanitizeError(error, serverMode)
});
}, {});
}
async function serializeError(error) {
// must be type alias due to inference issues on interfaces
// https://github.com/microsoft/TypeScript/issues/15300
function serializeError(error, serverMode) {
let sanitized = sanitizeError(error, serverMode);
return {
message: error.message,
stack: error.stack
message: sanitized.message,
stack: sanitized.stack
};
}
function serializeErrors(errors) {
function serializeErrors(errors, serverMode) {
if (!errors) return null;

@@ -82,6 +101,14 @@ let entries = Object.entries(errors);

} else if (val instanceof Error) {
let sanitized = sanitizeError(val, serverMode);
serialized[key] = {
message: val.message,
stack: val.stack,
__type: "Error"
message: sanitized.message,
stack: sanitized.stack,
__type: "Error",
// If this is a subclass (i.e., ReferenceError), send up the type so we
// can re-create the same type during hydration. This will only apply
// in dev mode since all production errors are sanitized to normal
// Error instances
...(sanitized.name !== "Error" ? {
__subType: sanitized.name
} : {})
};

@@ -95,3 +122,5 @@ } else {

exports.sanitizeError = sanitizeError;
exports.sanitizeErrors = sanitizeErrors;
exports.serializeError = serializeError;
exports.serializeErrors = serializeErrors;
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -15,2 +15,13 @@ * Copyright (c) Remix Software Inc.

/**
* A HTTP cookie.
*
* A Cookie is a logical container for metadata about a HTTP cookie; its name
* and options. But it doesn't contain a value. Instead, it has `parse()` and
* `serialize()` methods that allow a single instance to be reused for
* parsing/encoding multiple different values.
*
* @see https://remix.run/utils/cookies#cookie-api
*/
/**
* Creates a logical container for managing a browser cookie from the server.

@@ -25,6 +36,5 @@ *

let {
secrets,
secrets = [],
...options
} = {
secrets: [],
path: "/",

@@ -31,0 +41,0 @@ sameSite: "lax",

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -13,3 +13,14 @@ * Copyright (c) Remix Software Inc.

async function callRouteActionRR({
/**
* An object of unknown type for route loaders and actions provided by the
* server's `getLoadContext()` function. This is defined as an empty interface
* specifically so apps can leverage declaration merging to augment this type
* globally: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
*/
/**
* Data for a route that was returned from a `loader()`.
*/
async function callRouteAction({
loadContext,

@@ -19,3 +30,5 @@ action,

request,
routeId
routeId,
singleFetch,
response
}) {

@@ -25,3 +38,4 @@ let result = await action({

context: loadContext,
params
params,
response
});

@@ -31,5 +45,10 @@ if (result === undefined) {

}
// Allow naked object returns when single fetch is enabled
if (singleFetch) {
return result;
}
return isResponse(result) ? result : json(result);
}
async function callRouteLoaderRR({
async function callRouteLoader({
loadContext,

@@ -39,3 +58,5 @@ loader,

request,
routeId
routeId,
singleFetch,
response
}) {

@@ -45,3 +66,4 @@ let result = await loader({

context: loadContext,
params
params,
response
});

@@ -57,2 +79,7 @@ if (result === undefined) {

}
// Allow naked object returns when single fetch is enabled
if (singleFetch) {
return result;
}
return isResponse(result) ? result : json(result);

@@ -79,3 +106,12 @@ }

}
return new Request(url.href, request);
let init = {
method: request.method,
body: request.body,
headers: request.headers,
signal: request.signal
};
if (init.body) {
init.duplex = "half";
}
return new Request(url.href, init);
}

@@ -85,5 +121,14 @@ function stripDataParam(request) {

url.searchParams.delete("_data");
return new Request(url.href, request);
let init = {
method: request.method,
body: request.body,
headers: request.headers,
signal: request.signal
};
if (init.body) {
init.duplex = "half";
}
return new Request(url.href, init);
}
export { callRouteActionRR, callRouteLoaderRR };
export { callRouteAction, callRouteLoader };
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -12,2 +12,3 @@ * Copyright (c) Remix Software Inc.

import { isRouteErrorResponse } from '@remix-run/router';
import { ServerMode } from './mode.js';

@@ -56,11 +57,29 @@ /**

// TODO Re-export as ErrorResponse?
function sanitizeError(error, serverMode) {
if (error instanceof Error && serverMode !== ServerMode.Development) {
let sanitized = new Error("Unexpected Server Error");
sanitized.stack = undefined;
return sanitized;
}
return error;
}
function sanitizeErrors(errors, serverMode) {
return Object.entries(errors).reduce((acc, [routeId, error]) => {
return Object.assign(acc, {
[routeId]: sanitizeError(error, serverMode)
});
}, {});
}
async function serializeError(error) {
// must be type alias due to inference issues on interfaces
// https://github.com/microsoft/TypeScript/issues/15300
function serializeError(error, serverMode) {
let sanitized = sanitizeError(error, serverMode);
return {
message: error.message,
stack: error.stack
message: sanitized.message,
stack: sanitized.stack
};
}
function serializeErrors(errors) {
function serializeErrors(errors, serverMode) {
if (!errors) return null;

@@ -78,6 +97,14 @@ let entries = Object.entries(errors);

} else if (val instanceof Error) {
let sanitized = sanitizeError(val, serverMode);
serialized[key] = {
message: val.message,
stack: val.stack,
__type: "Error"
message: sanitized.message,
stack: sanitized.stack,
__type: "Error",
// If this is a subclass (i.e., ReferenceError), send up the type so we
// can re-create the same type during hydration. This will only apply
// in dev mode since all production errors are sanitized to normal
// Error instances
...(sanitized.name !== "Error" ? {
__subType: sanitized.name
} : {})
};

@@ -91,2 +118,2 @@ } else {

export { serializeError, serializeErrors };
export { sanitizeError, sanitizeErrors, serializeError, serializeErrors };
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -13,2 +13,3 @@ * Copyright (c) Remix Software Inc.

// @ts-ignore
function composeUploadHandlers(...handlers) {

@@ -15,0 +16,0 @@ return async part => {

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -13,6 +13,27 @@ * Copyright (c) Remix Software Inc.

function getDocumentHeadersRR(build, context) {
let matches = context.errors ? context.matches.slice(0, context.matches.findIndex(m => context.errors[m.route.id]) + 1) : context.matches;
return matches.reduce((parentHeaders, match) => {
function getDocumentHeaders(build, context) {
let boundaryIdx = context.errors ? context.matches.findIndex(m => context.errors[m.route.id]) : -1;
let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
let errorHeaders;
if (boundaryIdx >= 0) {
// Look for any errorHeaders from the boundary route down, which can be
// identified by the presence of headers but no data
let {
actionHeaders,
actionData,
loaderHeaders,
loaderData
} = context;
context.matches.slice(boundaryIdx).some(match => {
let id = match.route.id;
if (actionHeaders[id] && (!actionData || actionData[id] === undefined)) {
errorHeaders = actionHeaders[id];
} else if (loaderHeaders[id] && loaderData[id] === undefined) {
errorHeaders = loaderHeaders[id];
}
return errorHeaders != null;
});
}
return matches.reduce((parentHeaders, match, idx) => {
let {
id

@@ -23,10 +44,33 @@ } = match.route;

let actionHeaders = context.actionHeaders[id] || new Headers();
// Only expose errorHeaders to the leaf headers() function to
// avoid duplication via parentHeaders
let includeErrorHeaders = errorHeaders != undefined && idx === matches.length - 1;
// Only prepend cookies from errorHeaders at the leaf renderable route
// when it's not the same as loaderHeaders/actionHeaders to avoid
// duplicate cookies
let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
// Use the parent headers for any route without a `headers` export
if (routeModule.headers == null) {
let headers = new Headers(parentHeaders);
if (includeErrorCookies) {
prependCookies(errorHeaders, headers);
}
prependCookies(actionHeaders, headers);
prependCookies(loaderHeaders, headers);
return headers;
}
let headers = new Headers(routeModule.headers ? typeof routeModule.headers === "function" ? routeModule.headers({
loaderHeaders,
parentHeaders,
actionHeaders
actionHeaders,
errorHeaders: includeErrorHeaders ? errorHeaders : undefined
}) : routeModule.headers : undefined);
// Automatically preserve Set-Cookie headers that were set either by the
// loader or by a parent route.
// Automatically preserve Set-Cookie headers from bubbled responses,
// loaders, errors, and parent routes
if (includeErrorCookies) {
prependCookies(errorHeaders, headers);
}
prependCookies(actionHeaders, headers);

@@ -48,2 +92,2 @@ prependCookies(loaderHeaders, headers);

export { getDocumentHeadersRR };
export { getDocumentHeaders };
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -13,3 +13,4 @@ * Copyright (c) Remix Software Inc.

export { composeUploadHandlers as unstable_composeUploadHandlers, parseMultipartFormData as unstable_parseMultipartFormData } from './formData.js';
export { defer, json, redirect } from './responses.js';
export { defer, json, redirect, redirectDocument } from './responses.js';
export { SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol } from './single-fetch.js';
export { createRequestHandler } from './server.js';

@@ -21,1 +22,2 @@ export { createSession, createSessionStorageFactory, isSession } from './sessions.js';

export { MaxPartSizeExceededError } from './upload/errors.js';
export { broadcastDevReady, logDevReady, setDevServerHooks as unstable_setDevServerHooks } from './dev.js';
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -14,8 +14,8 @@ * Copyright (c) Remix Software Inc.

*/
let ServerMode;
(function (ServerMode) {
let ServerMode = /*#__PURE__*/function (ServerMode) {
ServerMode["Development"] = "development";
ServerMode["Production"] = "production";
ServerMode["Test"] = "test";
})(ServerMode || (ServerMode = {}));
return ServerMode;
}({});
function isServerMode(value) {

@@ -22,0 +22,0 @@ return value === ServerMode.Development || value === ServerMode.Production || value === ServerMode.Test;

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -11,5 +11,8 @@ * Copyright (c) Remix Software Inc.

*/
import { defer as defer$1 } from '@remix-run/router';
import { json as json$1, defer as defer$1, redirect as redirect$1, redirectDocument as redirectDocument$1 } from '@remix-run/router';
import { serializeError } from './errors.js';
// must be a type since this is a subtype of response
// interfaces must conform to the types they extend
/**

@@ -22,33 +25,12 @@ * This is a shortcut for creating `application/json` responses. Converts `data`

const json = (data, init = {}) => {
let responseInit = typeof init === "number" ? {
status: init
} : init;
let headers = new Headers(responseInit.headers);
if (!headers.has("Content-Type")) {
headers.set("Content-Type", "application/json; charset=utf-8");
}
return new Response(JSON.stringify(data), {
...responseInit,
headers
});
return json$1(data, init);
};
/**
* This is a shortcut for creating `application/json` responses. Converts `data`
* to JSON and sets the `Content-Type` header.
* This is a shortcut for creating Remix deferred responses
*
* @see https://remix.run/api/remix#json
* @see https://remix.run/utils/defer
*/
const defer = (data, init = {}) => {
let responseInit = typeof init === "number" ? {
status: init
} : init;
let headers = new Headers(responseInit.headers);
if (!headers.has("Content-Type")) {
headers.set("Content-Type", "application/json; charset=utf-8");
}
return defer$1(data, {
...responseInit,
headers
});
return defer$1(data, init);
};

@@ -62,17 +44,15 @@ /**

const redirect = (url, init = 302) => {
let responseInit = init;
if (typeof responseInit === "number") {
responseInit = {
status: responseInit
};
} else if (typeof responseInit.status === "undefined") {
responseInit.status = 302;
}
let headers = new Headers(responseInit.headers);
headers.set("Location", url);
return new Response(null, {
...responseInit,
headers
});
return redirect$1(url, init);
};
/**
* A redirect response that will force a document reload to the new location.
* Sets the status code and the `Location` header.
* Defaults to "302 Found".
*
* @see https://remix.run/utils/redirect
*/
const redirectDocument = (url, init = 302) => {
return redirectDocument$1(url, init);
};
function isDeferredData(value) {

@@ -100,3 +80,3 @@ let deferred = value;

const DEFERRED_VALUE_PLACEHOLDER_PREFIX = "__deferred_promise:";
function createDeferredReadableStream(deferredData, signal) {
function createDeferredReadableStream(deferredData, signal, serverMode) {
let encoder = new TextEncoder();

@@ -121,7 +101,7 @@ let stream = new ReadableStream({

for (let preresolvedKey of preresolvedKeys) {
enqueueTrackedPromise(controller, encoder, preresolvedKey, deferredData.data[preresolvedKey]);
enqueueTrackedPromise(controller, encoder, preresolvedKey, deferredData.data[preresolvedKey], serverMode);
}
let unsubscribe = deferredData.subscribe((aborted, settledKey) => {
if (settledKey) {
enqueueTrackedPromise(controller, encoder, settledKey, deferredData.data[settledKey]);
enqueueTrackedPromise(controller, encoder, settledKey, deferredData.data[settledKey], serverMode);
}

@@ -136,6 +116,6 @@ });

}
function enqueueTrackedPromise(controller, encoder, settledKey, promise) {
function enqueueTrackedPromise(controller, encoder, settledKey, promise, serverMode) {
if ("_error" in promise) {
controller.enqueue(encoder.encode("error:" + JSON.stringify({
[settledKey]: serializeError(promise._error)
[settledKey]: promise._error instanceof Error ? serializeError(promise._error, serverMode) : promise._error
}) + "\n\n"));

@@ -149,2 +129,2 @@ } else {

export { createDeferredReadableStream, defer, isDeferredData, isRedirectResponse, isRedirectStatusCode, isResponse, json, redirect };
export { createDeferredReadableStream, defer, isDeferredData, isRedirectResponse, isRedirectStatusCode, isResponse, json, redirect, redirectDocument };
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -13,4 +13,4 @@ * Copyright (c) Remix Software Inc.

function matchServerRoutes(routes, pathname) {
let matches = matchRoutes(routes, pathname);
function matchServerRoutes(routes, pathname, basename) {
let matches = matchRoutes(routes, pathname, basename);
if (!matches) return null;

@@ -17,0 +17,0 @@ return matches.map(match => ({

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -11,8 +11,26 @@ * Copyright (c) Remix Software Inc.

*/
import { callRouteLoaderRR, callRouteActionRR } from './data.js';
import { callRouteLoader, callRouteAction } from './data.js';
function createRoutes(manifest, parentId) {
return Object.entries(manifest).filter(([, route]) => route.parentId === parentId).map(([id, route]) => ({
// NOTE: make sure to change the Route in remix-react if you change this
// NOTE: make sure to change the EntryRoute in remix-react if you change this
function groupRoutesByParentId(manifest) {
let routes = {};
Object.values(manifest).forEach(route => {
let parentId = route.parentId || "";
if (!routes[parentId]) {
routes[parentId] = [];
}
routes[parentId].push(route);
});
return routes;
}
// Create a map of routes by parentId to use recursively instead of
// repeatedly filtering the manifest.
function createRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
return (routesByParentId[parentId] || []).map(route => ({
...route,
children: createRoutes(manifest, id)
children: createRoutes(manifest, route.id, routesByParentId)
}));

@@ -23,11 +41,13 @@ }

// createStaticHandler
function createStaticHandlerDataRoutes(manifest, future, parentId) {
return Object.values(manifest).filter(route => route.parentId === parentId).map(route => {
let hasErrorBoundary = future.v2_errorBoundary === true ? route.id === "root" || route.module.ErrorBoundary != null : route.id === "root" || route.module.CatchBoundary != null || route.module.ErrorBoundary != null;
function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
return (routesByParentId[parentId] || []).map(route => {
let commonRoute = {
// Always include root due to default boundaries
hasErrorBoundary,
hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
id: route.id,
path: route.path,
loader: route.module.loader ? args => callRouteLoaderRR({
loader: route.module.loader ?
// Need to use RR's version here to permit the optional context even
// though we know it'll always be provided in remix
(args, dataStrategyCtx) => callRouteLoader({
request: args.request,

@@ -37,5 +57,7 @@ params: args.params,

loader: route.module.loader,
routeId: route.id
routeId: route.id,
singleFetch: future.unstable_singleFetch === true,
response: dataStrategyCtx === null || dataStrategyCtx === void 0 ? void 0 : dataStrategyCtx.response
}) : undefined,
action: route.module.action ? args => callRouteActionRR({
action: route.module.action ? (args, dataStrategyCtx) => callRouteAction({
request: args.request,

@@ -45,3 +67,5 @@ params: args.params,

action: route.module.action,
routeId: route.id
routeId: route.id,
singleFetch: future.unstable_singleFetch === true,
response: dataStrategyCtx === null || dataStrategyCtx === void 0 ? void 0 : dataStrategyCtx.response
}) : undefined,

@@ -55,3 +79,3 @@ handle: route.module.handle

caseSensitive: route.caseSensitive,
children: createStaticHandlerDataRoutes(manifest, future, route.id),
children: createStaticHandlerDataRoutes(manifest, future, route.id, routesByParentId),
...commonRoute

@@ -58,0 +82,0 @@ };

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -11,55 +11,131 @@ * Copyright (c) Remix Software Inc.

*/
import { createStaticHandler, UNSAFE_DEFERRED_SYMBOL, isRouteErrorResponse, getStaticContextFromError } from '@remix-run/router';
import { UNSAFE_DEFERRED_SYMBOL, isRouteErrorResponse, json, UNSAFE_ErrorResponseImpl, getStaticContextFromError, stripBasename, createStaticHandler } from '@remix-run/router';
import { createEntryRouteModules } from './entry.js';
import { serializeErrors, serializeError } from './errors.js';
import { getDocumentHeadersRR } from './headers.js';
import { serializeError, sanitizeErrors, serializeErrors } from './errors.js';
import { getDocumentHeaders } from './headers.js';
import invariant from './invariant.js';
import { isServerMode, ServerMode } from './mode.js';
import { ServerMode, isServerMode } from './mode.js';
import { matchServerRoutes } from './routeMatching.js';
import { createRoutes, createStaticHandlerDataRoutes } from './routes.js';
import { isRedirectResponse, createDeferredReadableStream, isResponse, json } from './responses.js';
import { isRedirectResponse, createDeferredReadableStream, isResponse, isRedirectStatusCode, json as json$1 } from './responses.js';
import { createServerHandoffString } from './serverHandoff.js';
import { getDevServerHooks } from './dev.js';
import { getSingleFetchRedirect, encodeViaTurboStream, singleFetchAction, singleFetchLoaders, getResponseStubs, getSingleFetchDataStrategy, mergeResponseStubs, isResponseStub, getSingleFetchResourceRouteDataStrategy, SingleFetchRedirectSymbol } from './single-fetch.js';
import { resourceRouteJsonWarning } from './deprecations.js';
import { ResponseStubOperationsSymbol } from './routeModules.js';
const createRequestHandler = (build, mode) => {
function derive(build, mode) {
var _build$future, _build$future2;
let routes = createRoutes(build.routes);
let dataRoutes = createStaticHandlerDataRoutes(build.routes, build.future);
let serverMode = isServerMode(mode) ? mode : ServerMode.Production;
let staticHandler = createStaticHandler(dataRoutes);
let staticHandler = createStaticHandler(dataRoutes, {
basename: build.basename,
future: {
v7_relativeSplatPath: ((_build$future = build.future) === null || _build$future === void 0 ? void 0 : _build$future.v3_relativeSplatPath) === true,
v7_throwAbortReason: ((_build$future2 = build.future) === null || _build$future2 === void 0 ? void 0 : _build$future2.v3_throwAbortReason) === true
}
});
let errorHandler = build.entry.module.handleError || ((error, {
request
}) => {
if (serverMode !== ServerMode.Test && !request.signal.aborted) {
console.error(
// @ts-expect-error This is "private" from users but intended for internal use
isRouteErrorResponse(error) && error.error ? error.error : error);
}
});
return {
routes,
dataRoutes,
serverMode,
staticHandler,
errorHandler
};
}
const createRequestHandler = (build, mode) => {
let _build;
let routes;
let serverMode;
let staticHandler;
let errorHandler;
return async function requestHandler(request, loadContext = {}) {
_build = typeof build === "function" ? await build() : build;
mode ??= _build.mode;
if (typeof build === "function") {
let derived = derive(_build, mode);
routes = derived.routes;
serverMode = derived.serverMode;
staticHandler = derived.staticHandler;
errorHandler = derived.errorHandler;
} else if (!routes || !serverMode || !staticHandler || !errorHandler) {
let derived = derive(_build, mode);
routes = derived.routes;
serverMode = derived.serverMode;
staticHandler = derived.staticHandler;
errorHandler = derived.errorHandler;
}
let url = new URL(request.url);
// special __REMIX_ASSETS_MANIFEST endpoint for checking if app server serving up-to-date routes and assets
let {
unstable_dev
} = build.future;
if (mode === "development" && unstable_dev !== false && url.pathname === (unstable_dev.remixRequestHandlerPath ?? "") + "/__REMIX_ASSETS_MANIFEST") {
if (request.method !== "GET") {
return new Response("Method not allowed", {
status: 405
});
let matches = matchServerRoutes(routes, url.pathname, _build.basename);
let params = matches && matches.length > 0 ? matches[0].params : {};
let handleError = error => {
if (mode === ServerMode.Development) {
var _getDevServerHooks, _getDevServerHooks$pr;
(_getDevServerHooks = getDevServerHooks()) === null || _getDevServerHooks === void 0 ? void 0 : (_getDevServerHooks$pr = _getDevServerHooks.processRequestError) === null || _getDevServerHooks$pr === void 0 ? void 0 : _getDevServerHooks$pr.call(_getDevServerHooks, error);
}
return new Response(JSON.stringify(build.assets), {
status: 200,
headers: {
"Content-Type": "application/json"
}
errorHandler(error, {
context: loadContext,
params,
request
});
}
let matches = matchServerRoutes(routes, url.pathname);
};
let response;
if (url.searchParams.has("_data")) {
if (_build.future.unstable_singleFetch) {
handleError(new Error("Warning: Single fetch-enabled apps should not be making ?_data requests, " + "this is likely to break in the future"));
}
let routeId = url.searchParams.get("_data");
response = await handleDataRequestRR(serverMode, staticHandler, routeId, request, loadContext);
if (build.entry.module.handleDataRequest) {
let match = matches.find(match => match.route.id == routeId);
response = await build.entry.module.handleDataRequest(response, {
response = await handleDataRequest(serverMode, _build, staticHandler, routeId, request, loadContext, handleError);
if (_build.entry.module.handleDataRequest) {
response = await _build.entry.module.handleDataRequest(response, {
context: loadContext,
params: match.params,
params,
request
});
if (isRedirectResponse(response)) {
response = createRemixRedirectResponse(response, _build.basename);
}
}
} else if (matches && matches[matches.length - 1].route.module.default == null) {
response = await handleResourceRequestRR(serverMode, staticHandler, matches.slice(-1)[0].route.id, request, loadContext);
} else if (_build.future.unstable_singleFetch && url.pathname.endsWith(".data")) {
let handlerUrl = new URL(request.url);
handlerUrl.pathname = handlerUrl.pathname.replace(/\.data$/, "").replace(/^\/_root$/, "/");
let singleFetchMatches = matchServerRoutes(routes, handlerUrl.pathname, _build.basename);
response = await handleSingleFetchRequest(serverMode, _build, staticHandler, request, handlerUrl, loadContext, handleError);
if (_build.entry.module.handleDataRequest) {
response = await _build.entry.module.handleDataRequest(response, {
context: loadContext,
params: singleFetchMatches ? singleFetchMatches[0].params : {},
request
});
if (isRedirectResponse(response)) {
let result = getSingleFetchRedirect(response.status, response.headers);
if (request.method === "GET") {
result = {
[SingleFetchRedirectSymbol]: result
};
}
let headers = new Headers(response.headers);
headers.set("Content-Type", "text/x-turbo");
return new Response(encodeViaTurboStream(result, request.signal, _build.entry.module.streamTimeout, serverMode), {
status: 200,
headers
});
}
}
} else if (matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
response = await handleResourceRequest(serverMode, _build, staticHandler, matches.slice(-1)[0].route.id, request, loadContext, handleError);
} else {
response = await handleDocumentRequestRR(serverMode, build, staticHandler, request, loadContext);
var _getDevServerHooks2, _getDevServerHooks2$g;
let criticalCss = mode === ServerMode.Development ? await ((_getDevServerHooks2 = getDevServerHooks()) === null || _getDevServerHooks2 === void 0 ? void 0 : (_getDevServerHooks2$g = _getDevServerHooks2.getCriticalCss) === null || _getDevServerHooks2$g === void 0 ? void 0 : _getDevServerHooks2$g.call(_getDevServerHooks2, _build, url.pathname)) : undefined;
response = await handleDocumentRequest(serverMode, _build, staticHandler, request, loadContext, handleError, criticalCss);
}

@@ -76,3 +152,3 @@ if (request.method === "HEAD") {

};
async function handleDataRequestRR(serverMode, staticHandler, routeId, request, loadContext) {
async function handleDataRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {
try {

@@ -84,26 +160,20 @@ let response = await staticHandler.queryRoute(request, {

if (isRedirectResponse(response)) {
// We don't have any way to prevent a fetch request from following
// redirects. So we use the `X-Remix-Redirect` header to indicate the
// next URL, and then "follow" the redirect manually on the client.
let headers = new Headers(response.headers);
headers.set("X-Remix-Redirect", headers.get("Location"));
headers.set("X-Remix-Status", response.status);
headers.delete("Location");
if (response.headers.get("Set-Cookie") !== null) {
headers.set("X-Remix-Revalidate", "yes");
}
return new Response(null, {
status: 204,
headers
});
return createRemixRedirectResponse(response, build.basename);
}
if (UNSAFE_DEFERRED_SYMBOL in response) {
let deferredData = response[UNSAFE_DEFERRED_SYMBOL];
let body = createDeferredReadableStream(deferredData, request.signal);
let body = createDeferredReadableStream(deferredData, request.signal, serverMode);
let init = deferredData.init || {};
let headers = new Headers(init.headers);
headers.set("Content-Type", "text/remix-deferred");
// Mark successful responses with a header so we can identify in-flight
// network errors that are missing this header
headers.set("X-Remix-Response", "yes");
init.headers = headers;
return new Response(body, init);
}
// Mark all successful responses with a header so we can identify in-flight
// network errors that are missing this header
response.headers.set("X-Remix-Response", "yes");
return response;

@@ -115,61 +185,46 @@ } catch (error) {

}
let status = 500;
let errorInstance = error;
if (isRouteErrorResponse(error)) {
status = error.status;
errorInstance = error.error || errorInstance;
handleError(error);
return errorResponseToJson(error, serverMode);
}
if (serverMode !== ServerMode.Test && !request.signal.aborted) {
console.error(errorInstance);
}
if (serverMode === ServerMode.Development && errorInstance instanceof Error) {
return errorBoundaryError(errorInstance, status);
}
return errorBoundaryError(new Error("Unexpected Server Error"), status);
let errorInstance = error instanceof Error || error instanceof DOMException ? error : new Error("Unexpected Server Error");
handleError(errorInstance);
return json(serializeError(errorInstance, serverMode), {
status: 500,
headers: {
"X-Remix-Error": "yes"
}
});
}
}
function findParentBoundary(routes, routeId, error) {
// Fall back to the root route if we don't match any routes, since Remix
// has default error/catch boundary handling. This handles the case where
// react-router doesn't have a matching "root" route to assign the error to
// so it returns context.errors = { __shim-error-route__: ErrorResponse }
let route = routes[routeId] || routes["root"];
// Router-thrown ErrorResponses will have the error instance. User-thrown
// Responses will not have an error. The one exception here is internal 404s
// which we handle the same as user-thrown 404s
let isCatch = isRouteErrorResponse(error) && (!error.error || error.status === 404);
if (isCatch && route.module.CatchBoundary || !isCatch && route.module.ErrorBoundary || !route.parentId) {
return route.id;
}
return findParentBoundary(routes, route.parentId, error);
}
async function handleSingleFetchRequest(serverMode, build, staticHandler, request, handlerUrl, loadContext, handleError) {
let {
result,
headers,
status
} = request.method !== "GET" ? await singleFetchAction(serverMode, staticHandler, request, handlerUrl, loadContext, handleError) : await singleFetchLoaders(serverMode, staticHandler, request, handlerUrl, loadContext, handleError);
// Re-generate a remix-friendly context.errors structure. The Router only
// handles generic errors and does not distinguish error versus catch. We
// may have a thrown response tagged to a route that only exports an
// ErrorBoundary or vice versa. So we adjust here and ensure that
// data-loading errors are properly associated with routes that have the right
// type of boundaries.
function differentiateCatchVersusErrorBoundaries(build, context) {
if (!context.errors) {
return;
}
let errors = {};
for (let routeId of Object.keys(context.errors)) {
let error = context.errors[routeId];
let handlingRouteId = findParentBoundary(build.routes, routeId, error);
errors[handlingRouteId] = error;
}
context.errors = errors;
// Mark all successful responses with a header so we can identify in-flight
// network errors that are missing this header
let resultHeaders = new Headers(headers);
resultHeaders.set("X-Remix-Response", "yes");
resultHeaders.set("Content-Type", "text/x-turbo");
// Note: Deferred data is already just Promises, so we don't have to mess
// `activeDeferreds` or anything :)
return new Response(encodeViaTurboStream(result, request.signal, build.entry.module.streamTimeout, serverMode), {
status: status || 200,
headers: resultHeaders
});
}
async function handleDocumentRequestRR(serverMode, build, staticHandler, request, loadContext) {
async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, criticalCss) {
let context;
let responseStubs = getResponseStubs();
try {
context = await staticHandler.query(request, {
requestContext: loadContext
requestContext: loadContext,
unstable_dataStrategy: build.future.unstable_singleFetch ? getSingleFetchDataStrategy(responseStubs) : undefined
});
} catch (error) {
if (!request.signal.aborted && serverMode !== ServerMode.Test) {
console.error(error);
}
handleError(error);
return new Response(null, {

@@ -182,8 +237,38 @@ status: 500

}
let statusCode;
let headers;
if (build.future.unstable_singleFetch) {
let merged = mergeResponseStubs(context, responseStubs);
statusCode = merged.statusCode;
headers = merged.headers;
if (isRedirectStatusCode(statusCode) && headers.has("Location")) {
return new Response(null, {
status: statusCode,
headers
});
}
} else {
statusCode = context.statusCode;
headers = getDocumentHeaders(build, context);
}
// Restructure context.errors to the right Catch/Error Boundary
if (build.future.v2_errorBoundary !== true) {
differentiateCatchVersusErrorBoundaries(build, context);
// Sanitize errors outside of development environments
if (context.errors) {
Object.values(context.errors).forEach(err => {
// @ts-expect-error `err.error` is "private" from users but intended for internal use
if ((!isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) {
handleError(err);
}
});
context.errors = sanitizeErrors(context.errors, serverMode);
}
let headers = getDocumentHeadersRR(build, context);
// Server UI state to send to the client.
// - When single fetch is enabled, this is streamed down via `serverHandoffStream`
// - Otherwise it's stringified into `serverHandoffString`
let state = {
loaderData: context.loaderData,
actionData: context.actionData,
errors: serializeErrors(context.errors, serverMode)
};
let entryContext = {

@@ -193,26 +278,56 @@ manifest: build.assets,

staticHandlerContext: context,
criticalCss,
serverHandoffString: createServerHandoffString({
state: {
loaderData: context.loaderData,
actionData: context.actionData,
errors: serializeErrors(context.errors)
},
url: context.location.pathname,
basename: build.basename,
criticalCss,
future: build.future,
dev: build.dev
isSpaMode: build.isSpaMode,
...(!build.future.unstable_singleFetch ? {
state
} : null)
}),
future: build.future
...(build.future.unstable_singleFetch ? {
serverHandoffStream: encodeViaTurboStream(state, request.signal, build.entry.module.streamTimeout, serverMode),
renderMeta: {}
} : null),
future: build.future,
isSpaMode: build.isSpaMode,
serializeError: err => serializeError(err, serverMode)
};
let handleDocumentRequestFunction = build.entry.module.default;
try {
return await handleDocumentRequestFunction(request, context.statusCode, headers, entryContext);
return await handleDocumentRequestFunction(request, statusCode, headers, entryContext, loadContext);
} catch (error) {
handleError(error);
let errorForSecondRender = error;
// If they threw a response, unwrap it into an ErrorResponse like we would
// have for a loader/action
if (isResponse(error)) {
try {
let data = await unwrapResponse(error);
errorForSecondRender = new UNSAFE_ErrorResponseImpl(error.status, error.statusText, data);
} catch (e) {
// If we can't unwrap the response - just leave it as-is
}
}
// Get a new StaticHandlerContext that contains the error at the right boundary
context = getStaticContextFromError(staticHandler.dataRoutes, context, error);
context = getStaticContextFromError(staticHandler.dataRoutes, context, errorForSecondRender);
// Restructure context.errors to the right Catch/Error Boundary
if (build.future.v2_errorBoundary !== true) {
differentiateCatchVersusErrorBoundaries(build, context);
// Sanitize errors outside of development environments
if (context.errors) {
context.errors = sanitizeErrors(context.errors, serverMode);
}
// Update entryContext for the second render pass
// Get a new entryContext for the second render pass
// Server UI state to send to the client.
// - When single fetch is enabled, this is streamed down via `serverHandoffStream`
// - Otherwise it's stringified into `serverHandoffString`
let state = {
loaderData: context.loaderData,
actionData: context.actionData,
errors: serializeErrors(context.errors, serverMode)
};
entryContext = {

@@ -222,13 +337,19 @@ ...entryContext,

serverHandoffString: createServerHandoffString({
state: {
loaderData: context.loaderData,
actionData: context.actionData,
errors: serializeErrors(context.errors)
},
future: build.future
})
url: context.location.pathname,
basename: build.basename,
future: build.future,
isSpaMode: build.isSpaMode,
...(!build.future.unstable_singleFetch ? {
state
} : null)
}),
...(build.future.unstable_singleFetch ? {
serverHandoffStream: encodeViaTurboStream(state, request.signal, build.entry.module.streamTimeout, serverMode),
renderMeta: {}
} : null)
};
try {
return await handleDocumentRequestFunction(request, context.statusCode, headers, entryContext);
return await handleDocumentRequestFunction(request, context.statusCode, headers, entryContext, loadContext);
} catch (error) {
handleError(error);
return returnLastResortErrorResponse(error, serverMode);

@@ -238,4 +359,5 @@ }

}
async function handleResourceRequestRR(serverMode, staticHandler, routeId, request, loadContext) {
async function handleResourceRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {
try {
let responseStubs = build.future.unstable_singleFetch ? getResponseStubs() : {};
// Note we keep the routeId here to align with the Remix handling of

@@ -246,5 +368,34 @@ // resource routes which doesn't take ?index into account and just takes

routeId,
requestContext: loadContext
requestContext: loadContext,
...(build.future.unstable_singleFetch ? {
unstable_dataStrategy: getSingleFetchResourceRouteDataStrategy({
responseStubs
})
} : null)
});
// callRouteLoader/callRouteAction always return responses
if (typeof response === "object") {
invariant(!(UNSAFE_DEFERRED_SYMBOL in response), `You cannot return a \`defer()\` response from a Resource Route. Did you ` + `forget to export a default UI component from the "${routeId}" route?`);
}
if (build.future.unstable_singleFetch) {
let stub = responseStubs[routeId];
if (isResponse(response)) {
// If a response was returned, we use it's status and we merge our
// response stub headers onto it
let ops = stub[ResponseStubOperationsSymbol];
for (let [op, ...args] of ops) {
// @ts-expect-error
response.headers[op](...args);
}
} else {
console.warn(resourceRouteJsonWarning(request.method === "GET" ? "loader" : "action", routeId));
// Otherwise we create a json Response using the stub
response = json$1(response, {
status: stub.status,
headers: stub.headers
});
}
}
// callRouteLoader/callRouteAction always return responses (w/o single fetch).
// With single fetch, users should always be Responses from resource routes
invariant(isResponse(response), "Expected a Response to be returned from queryRoute");

@@ -259,8 +410,18 @@ return response;

}
if (isRouteErrorResponse(error)) {
if (error) {
handleError(error);
}
return errorResponseToJson(error, serverMode);
}
handleError(error);
return returnLastResortErrorResponse(error, serverMode);
}
}
async function errorBoundaryError(error, status) {
return json(await serializeError(error), {
status,
function errorResponseToJson(errorResponse, serverMode) {
return json(serializeError(
// @ts-expect-error This is "private" from users but intended for internal use
errorResponse.error || new Error("Unexpected Server Error"), serverMode), {
status: errorResponse.status,
statusText: errorResponse.statusText,
headers: {

@@ -272,5 +433,2 @@ "X-Remix-Error": "yes"

function returnLastResortErrorResponse(error, serverMode) {
if (serverMode !== ServerMode.Test) {
console.error(error);
}
let message = "Unexpected Server Error";

@@ -289,3 +447,26 @@ if (serverMode !== ServerMode.Production) {

}
function unwrapResponse(response) {
let contentType = response.headers.get("Content-Type");
// Check between word boundaries instead of startsWith() due to the last
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
return contentType && /\bapplication\/json\b/.test(contentType) ? response.body == null ? null : response.json() : response.text();
}
function createRemixRedirectResponse(response, basename) {
// We don't have any way to prevent a fetch request from following
// redirects. So we use the `X-Remix-Redirect` header to indicate the
// next URL, and then "follow" the redirect manually on the client.
let headers = new Headers(response.headers);
let redirectUrl = headers.get("Location");
headers.set("X-Remix-Redirect", basename ? stripBasename(redirectUrl, basename) || redirectUrl : redirectUrl);
headers.set("X-Remix-Status", String(response.status));
headers.delete("Location");
if (response.headers.get("Set-Cookie") !== null) {
headers.set("X-Remix-Revalidate", "yes");
}
return new Response(null, {
status: 204,
headers
});
}
export { createRequestHandler, differentiateCatchVersusErrorBoundaries };
export { createRequestHandler };
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -18,2 +18,8 @@ * Copyright (c) Remix Software Inc.

/**
* Session persists data across HTTP requests.
*
* @see https://remix.run/utils/sessions#session-api
*/
function flash(name) {

@@ -81,2 +87,12 @@ return `__flash_${name}__`;

/**
* SessionIdStorageStrategy is designed to allow anyone to easily build their
* own SessionStorage using `createSessionStorage(strategy)`.
*
* This strategy describes a common scenario where the session id is stored in
* a cookie but the actual session data is stored elsewhere, usually in a
* database or on disk. A set of create, read, update, and delete operations
* are provided for managing the session data.
*/
/**
* Creates a SessionStorage object using a SessionIdStorageStrategy.

@@ -109,6 +125,7 @@ *

} = session;
let expires = (options === null || options === void 0 ? void 0 : options.maxAge) != null ? new Date(Date.now() + options.maxAge * 1000) : (options === null || options === void 0 ? void 0 : options.expires) != null ? options.expires : cookie.expires;
if (id) {
await updateData(id, data, cookie.expires);
await updateData(id, data, expires);
} else {
id = await createData(data, cookie.expires);
id = await createData(data, expires);
}

@@ -121,2 +138,3 @@ return cookie.serialize(id, options);

...options,
maxAge: undefined,
expires: new Date(0)

@@ -123,0 +141,0 @@ });

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -44,2 +44,3 @@ * Copyright (c) Remix Software Inc.

...options,
maxAge: undefined,
expires: new Date(0)

@@ -46,0 +47,0 @@ });

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -23,3 +23,2 @@ * Copyright (c) Remix Software Inc.

} = {}) => {
let uniqueId = 0;
let map = new Map();

@@ -29,3 +28,3 @@ return createSessionStorage({

async createData(data, expires) {
let id = (++uniqueId).toString();
let id = Math.random().toString(36).substring(2, 10);
map.set(id, {

@@ -32,0 +31,0 @@ data,

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -1,2 +0,2 @@

export declare type UploadHandlerPart = {
export type UploadHandlerPart = {
name: string;

@@ -7,3 +7,3 @@ filename?: string;

};
export declare type UploadHandler = (part: UploadHandlerPart) => Promise<File | string | null | undefined>;
export type UploadHandler = (part: UploadHandlerPart) => Promise<File | string | null | undefined>;
export declare function composeUploadHandlers(...handlers: UploadHandler[]): UploadHandler;

@@ -10,0 +10,0 @@ /**

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -17,2 +17,3 @@ * Copyright (c) Remix Software Inc.

// @ts-ignore
function composeUploadHandlers(...handlers) {

@@ -19,0 +20,0 @@ return async part => {

import type { StaticHandlerContext } from "@remix-run/router";
import type { ServerBuild } from "./build";
export declare function getDocumentHeadersRR(build: ServerBuild, context: StaticHandlerContext): Headers;
export declare function getDocumentHeaders(build: ServerBuild, context: StaticHandlerContext): Headers;
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -17,6 +17,27 @@ * Copyright (c) Remix Software Inc.

function getDocumentHeadersRR(build, context) {
let matches = context.errors ? context.matches.slice(0, context.matches.findIndex(m => context.errors[m.route.id]) + 1) : context.matches;
return matches.reduce((parentHeaders, match) => {
function getDocumentHeaders(build, context) {
let boundaryIdx = context.errors ? context.matches.findIndex(m => context.errors[m.route.id]) : -1;
let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
let errorHeaders;
if (boundaryIdx >= 0) {
// Look for any errorHeaders from the boundary route down, which can be
// identified by the presence of headers but no data
let {
actionHeaders,
actionData,
loaderHeaders,
loaderData
} = context;
context.matches.slice(boundaryIdx).some(match => {
let id = match.route.id;
if (actionHeaders[id] && (!actionData || actionData[id] === undefined)) {
errorHeaders = actionHeaders[id];
} else if (loaderHeaders[id] && loaderData[id] === undefined) {
errorHeaders = loaderHeaders[id];
}
return errorHeaders != null;
});
}
return matches.reduce((parentHeaders, match, idx) => {
let {
id

@@ -27,10 +48,33 @@ } = match.route;

let actionHeaders = context.actionHeaders[id] || new Headers();
// Only expose errorHeaders to the leaf headers() function to
// avoid duplication via parentHeaders
let includeErrorHeaders = errorHeaders != undefined && idx === matches.length - 1;
// Only prepend cookies from errorHeaders at the leaf renderable route
// when it's not the same as loaderHeaders/actionHeaders to avoid
// duplicate cookies
let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
// Use the parent headers for any route without a `headers` export
if (routeModule.headers == null) {
let headers = new Headers(parentHeaders);
if (includeErrorCookies) {
prependCookies(errorHeaders, headers);
}
prependCookies(actionHeaders, headers);
prependCookies(loaderHeaders, headers);
return headers;
}
let headers = new Headers(routeModule.headers ? typeof routeModule.headers === "function" ? routeModule.headers({
loaderHeaders,
parentHeaders,
actionHeaders
actionHeaders,
errorHeaders: includeErrorHeaders ? errorHeaders : undefined
}) : routeModule.headers : undefined);
// Automatically preserve Set-Cookie headers that were set either by the
// loader or by a parent route.
// Automatically preserve Set-Cookie headers from bubbled responses,
// loaders, errors, and parent routes
if (includeErrorCookies) {
prependCookies(errorHeaders, headers);
}
prependCookies(actionHeaders, headers);

@@ -52,2 +96,2 @@ prependCookies(loaderHeaders, headers);

exports.getDocumentHeadersRR = getDocumentHeadersRR;
exports.getDocumentHeaders = getDocumentHeaders;
export { createCookieFactory, isCookie } from "./cookies";
export { composeUploadHandlers as unstable_composeUploadHandlers, parseMultipartFormData as unstable_parseMultipartFormData, } from "./formData";
export { defer, json, redirect } from "./responses";
export { defer, json, redirect, redirectDocument } from "./responses";
export type { SingleFetchResult as UNSAFE_SingleFetchResult, SingleFetchResults as UNSAFE_SingleFetchResults, } from "./single-fetch";
export { SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol } from "./single-fetch";
export { createRequestHandler } from "./server";

@@ -10,3 +12,4 @@ export { createSession, createSessionStorageFactory, isSession, } from "./sessions";

export { MaxPartSizeExceededError } from "./upload/errors";
export { broadcastDevReady, logDevReady, setDevServerHooks as unstable_setDevServerHooks, } from "./dev";
export type { CreateCookieFunction, CreateCookieSessionStorageFunction, CreateMemorySessionStorageFunction, CreateRequestHandlerFunction, CreateSessionFunction, CreateSessionStorageFunction, IsCookieFunction, IsSessionFunction, JsonFunction, RedirectFunction, } from "./interface";
export type { ActionArgs, ActionFunction, AppData, AppLoadContext, Cookie, CookieOptions, CookieParseOptions, CookieSerializeOptions, CookieSignatureOptions, DataFunctionArgs, EntryContext, ErrorBoundaryComponent, HandleDataRequestFunction, HandleDocumentRequestFunction, HeadersFunction, HtmlLinkDescriptor, HtmlMetaDescriptor, V2_HtmlMetaDescriptor, LinkDescriptor, LinksFunction, LoaderArgs, LoaderFunction, MemoryUploadHandlerFilterArgs, MemoryUploadHandlerOptions, MetaDescriptor, MetaFunction, V2_MetaFunction, PageLinkDescriptor, RequestHandler, RouteComponent, RouteHandle, SerializeFrom, ServerBuild, ServerEntryModule, Session, SessionData, SessionIdStorageStrategy, SessionStorage, SignFunction, TypedDeferredData, TypedResponse, UnsignFunction, UploadHandler, UploadHandlerPart, } from "./reexport";
export type { ActionFunction, ActionFunctionArgs, AppLoadContext, Cookie, CookieOptions, CookieParseOptions, CookieSerializeOptions, CookieSignatureOptions, DataFunctionArgs, EntryContext, ErrorResponse, FlashSessionData, HandleDataRequestFunction, HandleDocumentRequestFunction, HeadersArgs, HeadersFunction, HtmlLinkDescriptor, LinkDescriptor, LinksFunction, LoaderFunction, LoaderFunctionArgs, MemoryUploadHandlerFilterArgs, MemoryUploadHandlerOptions, HandleErrorFunction, PageLinkDescriptor, RequestHandler, SerializeFrom, ServerBuild, ServerEntryModule, ServerRuntimeMetaArgs, ServerRuntimeMetaDescriptor, ServerRuntimeMetaFunction, Session, SessionData, SessionIdStorageStrategy, SessionStorage, SignFunction, TypedDeferredData, TypedResponse, UnsignFunction, UploadHandler, UploadHandlerPart, } from "./reexport";
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -18,2 +18,3 @@ * Copyright (c) Remix Software Inc.

var responses = require('./responses.js');
var singleFetch = require('./single-fetch.js');
var server = require('./server.js');

@@ -25,2 +26,3 @@ var sessions = require('./sessions.js');

var errors = require('./upload/errors.js');
var dev = require('./dev.js');

@@ -36,2 +38,4 @@

exports.redirect = responses.redirect;
exports.redirectDocument = responses.redirectDocument;
exports.UNSAFE_SingleFetchRedirectSymbol = singleFetch.SingleFetchRedirectSymbol;
exports.createRequestHandler = server.createRequestHandler;

@@ -45,1 +49,4 @@ exports.createSession = sessions.createSession;

exports.MaxPartSizeExceededError = errors.MaxPartSizeExceededError;
exports.broadcastDevReady = dev.broadcastDevReady;
exports.logDevReady = dev.logDevReady;
exports.unstable_setDevServerHooks = dev.setDevServerHooks;
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -1,3 +0,3 @@

declare type Primitive = null | undefined | string | number | boolean | symbol | bigint;
declare type LiteralUnion<LiteralType, BaseType extends Primitive> = LiteralType | (BaseType & Record<never, never>);
type Primitive = null | undefined | string | number | boolean | symbol | bigint;
type LiteralUnion<LiteralType, BaseType extends Primitive> = LiteralType | (BaseType & Record<never, never>);
interface HtmlLinkProps {

@@ -94,16 +94,7 @@ /**

*/
export declare type HtmlLinkDescriptor = ((HtmlLinkProps & Pick<Required<HtmlLinkProps>, "href">) | (HtmlLinkPreloadImage & Pick<Required<HtmlLinkPreloadImage>, "imageSizes">) | (HtmlLinkPreloadImage & Pick<Required<HtmlLinkPreloadImage>, "href"> & {
export type HtmlLinkDescriptor = (HtmlLinkProps & Pick<Required<HtmlLinkProps>, "href">) | (HtmlLinkPreloadImage & Pick<Required<HtmlLinkPreloadImage>, "imageSizes">) | (HtmlLinkPreloadImage & Pick<Required<HtmlLinkPreloadImage>, "href"> & {
imageSizes?: never;
})) & {
});
export interface PageLinkDescriptor extends Omit<HtmlLinkDescriptor, "href" | "rel" | "type" | "sizes" | "imageSrcSet" | "imageSizes" | "as" | "color" | "title"> {
/**
* @deprecated Use `imageSrcSet` instead.
*/
imagesrcset?: string;
/**
* @deprecated Use `imageSizes` instead.
*/
imagesizes?: string;
};
export interface PageLinkDescriptor extends Omit<HtmlLinkDescriptor, "href" | "rel" | "type" | "sizes" | "imageSrcSet" | "imageSizes" | "imagesrcset" | "imagesizes" | "as" | "color" | "title"> {
/**
* The absolute path of the page to prefetch.

@@ -113,3 +104,3 @@ */

}
export declare type LinkDescriptor = HtmlLinkDescriptor | PageLinkDescriptor;
export type LinkDescriptor = HtmlLinkDescriptor | PageLinkDescriptor;
export {};
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -18,12 +18,13 @@ * Copyright (c) Remix Software Inc.

*/
exports.ServerMode = void 0;
(function (ServerMode) {
let ServerMode = /*#__PURE__*/function (ServerMode) {
ServerMode["Development"] = "development";
ServerMode["Production"] = "production";
ServerMode["Test"] = "test";
})(exports.ServerMode || (exports.ServerMode = {}));
return ServerMode;
}({});
function isServerMode(value) {
return value === exports.ServerMode.Development || value === exports.ServerMode.Production || value === exports.ServerMode.Test;
return value === ServerMode.Development || value === ServerMode.Production || value === ServerMode.Test;
}
exports.ServerMode = ServerMode;
exports.isServerMode = isServerMode;

@@ -1,2 +0,3 @@

export type { HandleDataRequestFunction, HandleDocumentRequestFunction, ServerBuild, ServerEntryModule, } from "./build";
export type { ErrorResponse } from "@remix-run/router";
export type { HandleDataRequestFunction, HandleDocumentRequestFunction, HandleErrorFunction, ServerBuild, ServerEntryModule, } from "./build";
export type { UploadHandlerPart, UploadHandler } from "./formData";

@@ -6,9 +7,9 @@ export type { MemoryUploadHandlerOptions, MemoryUploadHandlerFilterArgs, } from "./upload/memoryUploadHandler";

export type { SignFunction, UnsignFunction } from "./crypto";
export type { AppLoadContext, AppData } from "./data";
export type { AppLoadContext } from "./data";
export type { EntryContext } from "./entry";
export type { HtmlLinkDescriptor, LinkDescriptor, PageLinkDescriptor, } from "./links";
export type { TypedDeferredData, TypedResponse } from "./responses";
export type { ActionArgs, ActionFunction, DataFunctionArgs, ErrorBoundaryComponent, HeadersFunction, HtmlMetaDescriptor, V2_HtmlMetaDescriptor, LinksFunction, LoaderArgs, LoaderFunction, MetaDescriptor, MetaFunction, V2_MetaFunction, RouteComponent, RouteHandle, } from "./routeModules";
export type { ActionFunction, ActionFunctionArgs, DataFunctionArgs, HeadersArgs, HeadersFunction, LinksFunction, LoaderFunction, LoaderFunctionArgs, ServerRuntimeMetaArgs, ServerRuntimeMetaDescriptor, ServerRuntimeMetaFunction, } from "./routeModules";
export type { SerializeFrom } from "./serialize";
export type { RequestHandler } from "./server";
export type { Session, SessionData, SessionIdStorageStrategy, SessionStorage, } from "./sessions";
export type { Session, SessionData, SessionIdStorageStrategy, SessionStorage, FlashSessionData, } from "./sessions";
import { type UNSAFE_DeferredData as DeferredData } from "@remix-run/router";
export declare type TypedDeferredData<Data extends Record<string, unknown>> = Pick<DeferredData, "init"> & {
import type { ServerMode } from "./mode";
declare const typedDeferredDataBrand: unique symbol;
export type TypedDeferredData<Data extends Record<string, unknown>> = Pick<DeferredData, "init"> & {
data: Data;
readonly [typedDeferredDataBrand]: "TypedDeferredData";
};
export declare type DeferFunction = <Data extends Record<string, unknown>>(data: Data, init?: number | ResponseInit) => TypedDeferredData<Data>;
export declare type JsonFunction = <Data extends unknown>(data: Data, init?: number | ResponseInit) => TypedResponse<Data>;
export declare type TypedResponse<T extends unknown = unknown> = Omit<Response, "json"> & {
export type DeferFunction = <Data extends Record<string, unknown>>(data: Data, init?: number | ResponseInit) => TypedDeferredData<Data>;
export type JsonFunction = <Data>(data: Data, init?: number | ResponseInit) => TypedResponse<Data>;
export type TypedResponse<T = unknown> = Omit<Response, "json"> & {
json(): Promise<T>;

@@ -18,9 +21,8 @@ };

/**
* This is a shortcut for creating `application/json` responses. Converts `data`
* to JSON and sets the `Content-Type` header.
* This is a shortcut for creating Remix deferred responses
*
* @see https://remix.run/api/remix#json
* @see https://remix.run/utils/defer
*/
export declare const defer: DeferFunction;
export declare type RedirectFunction = (url: string, init?: number | ResponseInit) => TypedResponse<never>;
export type RedirectFunction = (url: string, init?: number | ResponseInit) => TypedResponse<never>;
/**

@@ -33,2 +35,10 @@ * A redirect response. Sets the status code and the `Location` header.

export declare const redirect: RedirectFunction;
/**
* A redirect response that will force a document reload to the new location.
* Sets the status code and the `Location` header.
* Defaults to "302 Found".
*
* @see https://remix.run/utils/redirect
*/
export declare const redirectDocument: RedirectFunction;
export declare function isDeferredData(value: any): value is DeferredData;

@@ -38,2 +48,3 @@ export declare function isResponse(value: any): value is Response;

export declare function isRedirectResponse(response: Response): boolean;
export declare function createDeferredReadableStream(deferredData: DeferredData, signal: AbortSignal): any;
export declare function createDeferredReadableStream(deferredData: DeferredData, signal: AbortSignal, serverMode: ServerMode): any;
export {};
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -18,2 +18,5 @@ * Copyright (c) Remix Software Inc.

// must be a type since this is a subtype of response
// interfaces must conform to the types they extend
/**

@@ -26,33 +29,12 @@ * This is a shortcut for creating `application/json` responses. Converts `data`

const json = (data, init = {}) => {
let responseInit = typeof init === "number" ? {
status: init
} : init;
let headers = new Headers(responseInit.headers);
if (!headers.has("Content-Type")) {
headers.set("Content-Type", "application/json; charset=utf-8");
}
return new Response(JSON.stringify(data), {
...responseInit,
headers
});
return router.json(data, init);
};
/**
* This is a shortcut for creating `application/json` responses. Converts `data`
* to JSON and sets the `Content-Type` header.
* This is a shortcut for creating Remix deferred responses
*
* @see https://remix.run/api/remix#json
* @see https://remix.run/utils/defer
*/
const defer = (data, init = {}) => {
let responseInit = typeof init === "number" ? {
status: init
} : init;
let headers = new Headers(responseInit.headers);
if (!headers.has("Content-Type")) {
headers.set("Content-Type", "application/json; charset=utf-8");
}
return router.defer(data, {
...responseInit,
headers
});
return router.defer(data, init);
};

@@ -66,17 +48,15 @@ /**

const redirect = (url, init = 302) => {
let responseInit = init;
if (typeof responseInit === "number") {
responseInit = {
status: responseInit
};
} else if (typeof responseInit.status === "undefined") {
responseInit.status = 302;
}
let headers = new Headers(responseInit.headers);
headers.set("Location", url);
return new Response(null, {
...responseInit,
headers
});
return router.redirect(url, init);
};
/**
* A redirect response that will force a document reload to the new location.
* Sets the status code and the `Location` header.
* Defaults to "302 Found".
*
* @see https://remix.run/utils/redirect
*/
const redirectDocument = (url, init = 302) => {
return router.redirectDocument(url, init);
};
function isDeferredData(value) {

@@ -104,3 +84,3 @@ let deferred = value;

const DEFERRED_VALUE_PLACEHOLDER_PREFIX = "__deferred_promise:";
function createDeferredReadableStream(deferredData, signal) {
function createDeferredReadableStream(deferredData, signal, serverMode) {
let encoder = new TextEncoder();

@@ -125,7 +105,7 @@ let stream = new ReadableStream({

for (let preresolvedKey of preresolvedKeys) {
enqueueTrackedPromise(controller, encoder, preresolvedKey, deferredData.data[preresolvedKey]);
enqueueTrackedPromise(controller, encoder, preresolvedKey, deferredData.data[preresolvedKey], serverMode);
}
let unsubscribe = deferredData.subscribe((aborted, settledKey) => {
if (settledKey) {
enqueueTrackedPromise(controller, encoder, settledKey, deferredData.data[settledKey]);
enqueueTrackedPromise(controller, encoder, settledKey, deferredData.data[settledKey], serverMode);
}

@@ -140,6 +120,6 @@ });

}
function enqueueTrackedPromise(controller, encoder, settledKey, promise) {
function enqueueTrackedPromise(controller, encoder, settledKey, promise, serverMode) {
if ("_error" in promise) {
controller.enqueue(encoder.encode("error:" + JSON.stringify({
[settledKey]: errors.serializeError(promise._error)
[settledKey]: promise._error instanceof Error ? errors.serializeError(promise._error, serverMode) : promise._error
}) + "\n\n"));

@@ -161,1 +141,2 @@ } else {

exports.redirect = redirect;
exports.redirectDocument = redirectDocument;

@@ -8,2 +8,2 @@ import type { Params } from "@remix-run/router";

}
export declare function matchServerRoutes(routes: ServerRoute[], pathname: string): RouteMatch<ServerRoute>[] | null;
export declare function matchServerRoutes(routes: ServerRoute[], pathname: string, basename?: string): RouteMatch<ServerRoute>[] | null;
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -17,4 +17,4 @@ * Copyright (c) Remix Software Inc.

function matchServerRoutes(routes, pathname) {
let matches = router.matchRoutes(routes, pathname);
function matchServerRoutes(routes, pathname, basename) {
let matches = router.matchRoutes(routes, pathname, basename);
if (!matches) return null;

@@ -21,0 +21,0 @@ return matches.map(match => ({

@@ -1,38 +0,86 @@

import type { ComponentType } from "react";
import type { Location, Params } from "@remix-run/router";
import type { AppLoadContext, AppData } from "./data";
import type { ActionFunction as RRActionFunction, ActionFunctionArgs as RRActionFunctionArgs, AgnosticRouteMatch, LoaderFunction as RRLoaderFunction, LoaderFunctionArgs as RRLoaderFunctionArgs, Location, Params } from "@remix-run/router";
import type { AppData, AppLoadContext } from "./data";
import type { LinkDescriptor } from "./links";
import type { RouteData } from "./routeData";
import type { Route } from "./routes";
import type { SerializeFrom } from "./serialize";
export interface RouteModules<RouteModule> {
[routeId: string]: RouteModule;
[routeId: string]: RouteModule | undefined;
}
/**
* The arguments passed to ActionFunction and LoaderFunction.
* @deprecated Use `LoaderFunctionArgs`/`ActionFunctionArgs` instead
*/
export interface DataFunctionArgs {
request: Request;
export type DataFunctionArgs = RRActionFunctionArgs<AppLoadContext> & RRLoaderFunctionArgs<AppLoadContext> & {
context: AppLoadContext;
params: Params;
}
export declare type LoaderArgs = DataFunctionArgs;
export declare type ActionArgs = DataFunctionArgs;
};
export declare const ResponseStubOperationsSymbol: unique symbol;
export type ResponseStubOperation = [
"set" | "append" | "delete",
string,
string?
];
/**
* A function that handles data mutations for a route.
* A stubbed response to let you set the status/headers of your response from
* loader/action functions
*/
export interface ActionFunction {
(args: DataFunctionArgs): Promise<Response> | Response | Promise<AppData> | AppData;
}
export type ResponseStub = {
status: number | undefined;
headers: Headers;
};
export type ResponseStubImpl = ResponseStub & {
[ResponseStubOperationsSymbol]: ResponseStubOperation[];
};
/**
* A React component that is rendered when the server throws a Response.
* A function that handles data mutations for a route on the server
*/
export declare type CatchBoundaryComponent = ComponentType<{}>;
export type ActionFunction = (args: ActionFunctionArgs) => ReturnType<RRActionFunction>;
/**
* A React component that is rendered when there is an error on a route.
* Arguments passed to a route `action` function
*/
export declare type ErrorBoundaryComponent = ComponentType<{
error: Error;
}>;
export type ActionFunctionArgs = RRActionFunctionArgs<AppLoadContext> & {
context: AppLoadContext;
response?: ResponseStub;
};
/**
* A function that handles data mutations for a route on the client
* @private Public API is exported from @remix-run/react
*/
type ClientActionFunction = (args: ClientActionFunctionArgs) => ReturnType<RRActionFunction>;
/**
* Arguments passed to a route `clientAction` function
* @private Public API is exported from @remix-run/react
*/
export type ClientActionFunctionArgs = RRActionFunctionArgs<undefined> & {
serverAction: <T = AppData>() => Promise<SerializeFrom<T>>;
};
/**
* A function that loads data for a route on the server
*/
export type LoaderFunction = (args: LoaderFunctionArgs) => ReturnType<RRLoaderFunction>;
/**
* Arguments passed to a route `loader` function
*/
export type LoaderFunctionArgs = RRLoaderFunctionArgs<AppLoadContext> & {
context: AppLoadContext;
response?: ResponseStub;
};
/**
* A function that loads data for a route on the client
* @private Public API is exported from @remix-run/react
*/
type ClientLoaderFunction = ((args: ClientLoaderFunctionArgs) => ReturnType<RRLoaderFunction>) & {
hydrate?: boolean;
};
/**
* Arguments passed to a route `clientLoader` function
* @private Public API is exported from @remix-run/react
*/
export type ClientLoaderFunctionArgs = RRLoaderFunctionArgs<undefined> & {
serverLoader: <T = AppData>() => Promise<SerializeFrom<T>>;
};
export type HeadersArgs = {
loaderHeaders: Headers;
parentHeaders: Headers;
actionHeaders: Headers;
errorHeaders: Headers | undefined;
};
/**
* A function that returns HTTP headers to be used for a route. These headers

@@ -42,7 +90,3 @@ * will be merged with (and take precedence over) headers from parent routes.

export interface HeadersFunction {
(args: {
loaderHeaders: Headers;
parentHeaders: Headers;
actionHeaders: Headers;
}): Headers | HeadersInit;
(args: HeadersArgs): Headers | HeadersInit;
}

@@ -57,14 +101,10 @@ /**

/**
* A function that loads data for a route.
*/
export interface LoaderFunction {
(args: DataFunctionArgs): Promise<Response> | Response | Promise<AppData> | AppData;
}
/**
* A function that returns an object of name + content pairs to use for
* `<meta>` tags for a route. These tags will be merged with (and take
* precedence over) tags from parent routes.
* A function that returns an array of data objects to use for rendering
* metadata HTML tags in a route. These tags are not rendered on descendant
* routes in the route hierarchy. In other words, they will only be rendered on
* the route in which they are exported.
*
* @param Loader - Loader for this meta function's route
* @param ParentsLoaders - Mapping from a parent's route filepath to that route's loader
* @param Loader - The type of the current route's loader function
* @param MatchLoaders - Mapping from a parent route's filepath to its loader
* function type
*

@@ -107,10 +147,10 @@ * Note that parent route filepaths are relative to the `app/` directory.

* "routes/sales/customers": CustomersLoader,
* }> = ({ data, parentsData }) => {
* }> = ({ data, matches }) => {
* const { name } = data
* // ^? string
* const { customerCount } = parentsData["routes/sales/customers"]
* const { customerCount } = matches.find((match) => match.id === "routes/sales/customers").data
* // ^? number
* const { salesCount } = parentsData["routes/sales"]
* const { salesCount } = matches.find((match) => match.id === "routes/sales").data
* // ^? number
* const { hello } = parentsData["root"]
* const { hello } = matches.find((match) => match.id === "root").data
* // ^? "world"

@@ -120,52 +160,25 @@ * }

*/
export interface V1_MetaFunction<Loader extends LoaderFunction | unknown = unknown, ParentsLoaders extends Record<string, LoaderFunction> = {}> {
(args: {
data: Loader extends LoaderFunction ? SerializeFrom<Loader> : AppData;
parentsData: {
[k in keyof ParentsLoaders]: SerializeFrom<ParentsLoaders[k]>;
} & RouteData;
params: Params;
location: Location;
}): HtmlMetaDescriptor;
export interface ServerRuntimeMetaFunction<Loader extends LoaderFunction | unknown = unknown, ParentsLoaders extends Record<string, LoaderFunction | unknown> = Record<string, unknown>> {
(args: ServerRuntimeMetaArgs<Loader, ParentsLoaders>): ServerRuntimeMetaDescriptor[];
}
export declare type MetaFunction<Loader extends LoaderFunction | unknown = unknown, ParentsLoaders extends Record<string, LoaderFunction> = {}> = V1_MetaFunction<Loader, ParentsLoaders>;
interface RouteMatchWithMeta<Route> {
interface ServerRuntimeMetaMatch<RouteId extends string = string, Loader extends LoaderFunction | unknown = unknown> {
id: RouteId;
pathname: AgnosticRouteMatch["pathname"];
data: Loader extends LoaderFunction ? SerializeFrom<Loader> : unknown;
handle?: RouteHandle;
params: AgnosticRouteMatch["params"];
meta: ServerRuntimeMetaDescriptor[];
error?: unknown;
}
type ServerRuntimeMetaMatches<MatchLoaders extends Record<string, LoaderFunction | unknown> = Record<string, unknown>> = Array<{
[K in keyof MatchLoaders]: ServerRuntimeMetaMatch<Exclude<K, number | symbol>, MatchLoaders[K]>;
}[keyof MatchLoaders]>;
export interface ServerRuntimeMetaArgs<Loader extends LoaderFunction | unknown = unknown, MatchLoaders extends Record<string, LoaderFunction | unknown> = Record<string, unknown>> {
data: (Loader extends LoaderFunction ? SerializeFrom<Loader> : AppData) | undefined;
params: Params;
pathname: string;
route: Route;
meta: V2_HtmlMetaDescriptor[];
location: Location;
matches: ServerRuntimeMetaMatches<MatchLoaders>;
error?: unknown;
}
interface ClientRoute extends Route {
loader?: LoaderFunction;
action: ActionFunction;
children?: ClientRoute[];
module: string;
hasLoader: boolean;
}
export interface V2_MetaFunction<Loader extends LoaderFunction | unknown = unknown, ParentsLoaders extends Record<string, LoaderFunction> = {}> {
(args: {
data: Loader extends LoaderFunction ? SerializeFrom<Loader> : AppData;
parentsData: {
[k in keyof ParentsLoaders]: SerializeFrom<ParentsLoaders[k]>;
} & RouteData;
params: Params;
location: Location;
matches: RouteMatchWithMeta<ClientRoute>[];
}): V2_HtmlMetaDescriptor[];
}
/**
* A name/content pair used to render `<meta>` tags in a meta function for a
* route. The value can be either a string, which will render a single `<meta>`
* tag, or an array of strings that will render multiple tags with the same
* `name` attribute.
*/
export interface V1_HtmlMetaDescriptor {
charset?: "utf-8";
charSet?: "utf-8";
title?: string;
[name: string]: null | string | undefined | Record<string, string> | Array<Record<string, string> | string>;
}
export declare type HtmlMetaDescriptor = V1_HtmlMetaDescriptor;
export declare type MetaDescriptor = HtmlMetaDescriptor;
export declare type V2_HtmlMetaDescriptor = {
export type ServerRuntimeMetaDescriptor = {
charSet: "utf-8";

@@ -184,19 +197,31 @@ } | {

} | {
"script:ld+json": LdJsonObject;
} | {
tagName: "meta" | "link";
[name: string]: string;
} | {
[name: string]: unknown;
};
type LdJsonObject = {
[Key in string]: LdJsonValue;
} & {
[Key in string]?: LdJsonValue | undefined;
};
type LdJsonArray = LdJsonValue[] | readonly LdJsonValue[];
type LdJsonPrimitive = string | number | boolean | null;
type LdJsonValue = LdJsonPrimitive | LdJsonObject | LdJsonArray;
/**
* A React component that is rendered for a route.
*/
export declare type RouteComponent = ComponentType<{}>;
/**
* An arbitrary object that is associated with a route.
*/
export declare type RouteHandle = any;
export type RouteHandle = unknown;
export interface EntryRouteModule {
CatchBoundary?: CatchBoundaryComponent;
ErrorBoundary?: ErrorBoundaryComponent;
default: RouteComponent;
clientAction?: ClientActionFunction;
clientLoader?: ClientLoaderFunction;
ErrorBoundary?: any;
HydrateFallback?: any;
Layout?: any;
default: any;
handle?: RouteHandle;
links?: LinksFunction;
meta?: MetaFunction | HtmlMetaDescriptor;
meta?: ServerRuntimeMetaFunction;
}

@@ -203,0 +228,0 @@ export interface ServerRouteModule extends EntryRouteModule {

@@ -7,3 +7,3 @@ import type { AgnosticDataRouteObject } from "@remix-run/router";

}
export declare type ServerRouteManifest = RouteManifest<Omit<ServerRoute, "children">>;
export type ServerRouteManifest = RouteManifest<Omit<ServerRoute, "children">>;
export interface Route {

@@ -19,5 +19,7 @@ index?: boolean;

hasLoader: boolean;
hasCatchBoundary: boolean;
hasClientAction: boolean;
hasClientLoader: boolean;
hasErrorBoundary: boolean;
imports?: string[];
css?: string[];
module: string;

@@ -30,3 +32,3 @@ parentId?: string;

}
export declare function createRoutes(manifest: ServerRouteManifest, parentId?: string): ServerRoute[];
export declare function createStaticHandlerDataRoutes(manifest: ServerRouteManifest, future: FutureConfig, parentId?: string): AgnosticDataRouteObject[];
export declare function createRoutes(manifest: ServerRouteManifest, parentId?: string, routesByParentId?: Record<string, Omit<ServerRoute, "children">[]>): ServerRoute[];
export declare function createStaticHandlerDataRoutes(manifest: ServerRouteManifest, future: FutureConfig, parentId?: string, routesByParentId?: Record<string, Omit<ServerRoute, "children">[]>): AgnosticDataRouteObject[];
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -17,6 +17,24 @@ * Copyright (c) Remix Software Inc.

function createRoutes(manifest, parentId) {
return Object.entries(manifest).filter(([, route]) => route.parentId === parentId).map(([id, route]) => ({
// NOTE: make sure to change the Route in remix-react if you change this
// NOTE: make sure to change the EntryRoute in remix-react if you change this
function groupRoutesByParentId(manifest) {
let routes = {};
Object.values(manifest).forEach(route => {
let parentId = route.parentId || "";
if (!routes[parentId]) {
routes[parentId] = [];
}
routes[parentId].push(route);
});
return routes;
}
// Create a map of routes by parentId to use recursively instead of
// repeatedly filtering the manifest.
function createRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
return (routesByParentId[parentId] || []).map(route => ({
...route,
children: createRoutes(manifest, id)
children: createRoutes(manifest, route.id, routesByParentId)
}));

@@ -27,11 +45,13 @@ }

// createStaticHandler
function createStaticHandlerDataRoutes(manifest, future, parentId) {
return Object.values(manifest).filter(route => route.parentId === parentId).map(route => {
let hasErrorBoundary = future.v2_errorBoundary === true ? route.id === "root" || route.module.ErrorBoundary != null : route.id === "root" || route.module.CatchBoundary != null || route.module.ErrorBoundary != null;
function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
return (routesByParentId[parentId] || []).map(route => {
let commonRoute = {
// Always include root due to default boundaries
hasErrorBoundary,
hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
id: route.id,
path: route.path,
loader: route.module.loader ? args => data.callRouteLoaderRR({
loader: route.module.loader ?
// Need to use RR's version here to permit the optional context even
// though we know it'll always be provided in remix
(args, dataStrategyCtx) => data.callRouteLoader({
request: args.request,

@@ -41,5 +61,7 @@ params: args.params,

loader: route.module.loader,
routeId: route.id
routeId: route.id,
singleFetch: future.unstable_singleFetch === true,
response: dataStrategyCtx === null || dataStrategyCtx === void 0 ? void 0 : dataStrategyCtx.response
}) : undefined,
action: route.module.action ? args => data.callRouteActionRR({
action: route.module.action ? (args, dataStrategyCtx) => data.callRouteAction({
request: args.request,

@@ -49,3 +71,5 @@ params: args.params,

action: route.module.action,
routeId: route.id
routeId: route.id,
singleFetch: future.unstable_singleFetch === true,
response: dataStrategyCtx === null || dataStrategyCtx === void 0 ? void 0 : dataStrategyCtx.response
}) : undefined,

@@ -59,3 +83,3 @@ handle: route.module.handle

caseSensitive: route.caseSensitive,
children: createStaticHandlerDataRoutes(manifest, future, route.id),
children: createStaticHandlerDataRoutes(manifest, future, route.id, routesByParentId),
...commonRoute

@@ -62,0 +86,0 @@ };

@@ -1,28 +0,8 @@

import type { AppData } from "./data";
import type { Jsonify } from "./jsonify";
import type { TypedDeferredData, TypedResponse } from "./responses";
declare type JsonPrimitive = string | number | boolean | String | Number | Boolean | null;
declare type NonJsonPrimitive = undefined | Function | symbol;
declare type IsAny<T> = 0 extends 1 & T ? true : false;
declare type Serialize<T> = IsAny<T> extends true ? any : T extends TypedDeferredData<infer U> ? SerializeDeferred<U> : T extends JsonPrimitive ? T : T extends NonJsonPrimitive ? never : T extends {
toJSON(): infer U;
} ? U : T extends [] ? [] : T extends [unknown, ...unknown[]] ? SerializeTuple<T> : T extends ReadonlyArray<infer U> ? (U extends NonJsonPrimitive ? null : Serialize<U>)[] : T extends object ? SerializeObject<UndefinedToOptional<T>> : never;
/** JSON serialize [tuples](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) */
declare type SerializeTuple<T extends [unknown, ...unknown[]]> = {
[k in keyof T]: T[k] extends NonJsonPrimitive ? null : Serialize<T[k]>;
};
/** JSON serialize objects (not including arrays) and classes */
declare type SerializeObject<T extends object> = {
[k in keyof T as T[k] extends NonJsonPrimitive ? never : k]: Serialize<T[k]>;
};
declare type SerializeDeferred<T extends Record<string, unknown>> = {
[k in keyof T as T[k] extends Promise<unknown> ? k : T[k] extends NonJsonPrimitive ? never : k]: T[k] extends Promise<infer U> ? Promise<Serialize<U>> extends never ? "wtf" : Promise<Serialize<U>> : Serialize<T[k]> extends never ? k : Serialize<T[k]>;
};
declare type UndefinedToOptional<T extends object> = {
[k in keyof T as undefined extends T[k] ? never : k]: T[k];
} & {
[k in keyof T as undefined extends T[k] ? k : never]?: Exclude<T[k], undefined>;
};
declare type ArbitraryFunction = (...args: any[]) => unknown;
import type { ClientActionFunctionArgs, ClientLoaderFunctionArgs } from "./routeModules";
/**
* Infer JSON serialized data type returned by a loader or action.
* Infer JSON serialized data type returned by a loader or action, while
* avoiding deserialization if the input type if it's a clientLoader or
* clientAction that returns a non-Response
*

@@ -32,3 +12,15 @@ * For example:

*/
export declare type SerializeFrom<T extends AppData | ArbitraryFunction> = Serialize<T extends (...args: any[]) => infer Output ? Awaited<Output> extends TypedResponse<infer U> ? U : Awaited<Output> : Awaited<T>>;
export type SerializeFrom<T> = T extends (...args: any[]) => infer Output ? Parameters<T> extends [ClientLoaderFunctionArgs | ClientActionFunctionArgs] ? SerializeClient<Awaited<Output>> : Serialize<Awaited<Output>> : Jsonify<Awaited<T>>;
type SerializeClient<Output> = Output extends TypedDeferredData<infer U> ? {
[K in keyof U as K extends symbol ? never : Promise<any> extends U[K] ? K : never]: DeferValueClient<U[K]>;
} & {
[K in keyof U as Promise<any> extends U[K] ? never : K]: U[K];
} : Output extends TypedResponse<infer U> ? Jsonify<U> : Awaited<Output>;
type DeferValueClient<T> = T extends undefined ? undefined : T extends Promise<unknown> ? Promise<Awaited<T>> : T;
type Serialize<Output> = Output extends TypedDeferredData<infer U> ? {
[K in keyof U as K extends symbol ? never : Promise<any> extends U[K] ? K : never]: DeferValue<U[K]>;
} & Jsonify<{
[K in keyof U as Promise<any> extends U[K] ? never : K]: U[K];
}> : Output extends TypedResponse<infer U> ? Jsonify<U> : Jsonify<Output>;
type DeferValue<T> = T extends undefined ? undefined : T extends Promise<unknown> ? Promise<Jsonify<Awaited<T>>> : Jsonify<T>;
export {};

@@ -1,7 +0,5 @@

import type { StaticHandlerContext } from "@remix-run/router";
import type { AppLoadContext } from "./data";
import type { ServerBuild } from "./build";
export declare type RequestHandler = (request: Request, loadContext?: AppLoadContext) => Promise<Response>;
export declare type CreateRequestHandlerFunction = (build: ServerBuild, mode?: string) => RequestHandler;
export type RequestHandler = (request: Request, loadContext?: AppLoadContext) => Promise<Response>;
export type CreateRequestHandlerFunction = (build: ServerBuild | (() => ServerBuild | Promise<ServerBuild>), mode?: string) => RequestHandler;
export declare const createRequestHandler: CreateRequestHandlerFunction;
export declare function differentiateCatchVersusErrorBoundaries(build: ServerBuild, context: StaticHandlerContext): void;
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -25,45 +25,121 @@ * Copyright (c) Remix Software Inc.

var serverHandoff = require('./serverHandoff.js');
var dev = require('./dev.js');
var singleFetch = require('./single-fetch.js');
var deprecations = require('./deprecations.js');
var routeModules = require('./routeModules.js');
const createRequestHandler = (build, mode$1) => {
function derive(build, mode$1) {
var _build$future, _build$future2;
let routes$1 = routes.createRoutes(build.routes);
let dataRoutes = routes.createStaticHandlerDataRoutes(build.routes, build.future);
let serverMode = mode.isServerMode(mode$1) ? mode$1 : mode.ServerMode.Production;
let staticHandler = router.createStaticHandler(dataRoutes);
let staticHandler = router.createStaticHandler(dataRoutes, {
basename: build.basename,
future: {
v7_relativeSplatPath: ((_build$future = build.future) === null || _build$future === void 0 ? void 0 : _build$future.v3_relativeSplatPath) === true,
v7_throwAbortReason: ((_build$future2 = build.future) === null || _build$future2 === void 0 ? void 0 : _build$future2.v3_throwAbortReason) === true
}
});
let errorHandler = build.entry.module.handleError || ((error, {
request
}) => {
if (serverMode !== mode.ServerMode.Test && !request.signal.aborted) {
console.error(
// @ts-expect-error This is "private" from users but intended for internal use
router.isRouteErrorResponse(error) && error.error ? error.error : error);
}
});
return {
routes: routes$1,
dataRoutes,
serverMode,
staticHandler,
errorHandler
};
}
const createRequestHandler = (build, mode$1) => {
let _build;
let routes;
let serverMode;
let staticHandler;
let errorHandler;
return async function requestHandler(request, loadContext = {}) {
_build = typeof build === "function" ? await build() : build;
mode$1 ??= _build.mode;
if (typeof build === "function") {
let derived = derive(_build, mode$1);
routes = derived.routes;
serverMode = derived.serverMode;
staticHandler = derived.staticHandler;
errorHandler = derived.errorHandler;
} else if (!routes || !serverMode || !staticHandler || !errorHandler) {
let derived = derive(_build, mode$1);
routes = derived.routes;
serverMode = derived.serverMode;
staticHandler = derived.staticHandler;
errorHandler = derived.errorHandler;
}
let url = new URL(request.url);
// special __REMIX_ASSETS_MANIFEST endpoint for checking if app server serving up-to-date routes and assets
let {
unstable_dev
} = build.future;
if (mode$1 === "development" && unstable_dev !== false && url.pathname === (unstable_dev.remixRequestHandlerPath ?? "") + "/__REMIX_ASSETS_MANIFEST") {
if (request.method !== "GET") {
return new Response("Method not allowed", {
status: 405
});
let matches = routeMatching.matchServerRoutes(routes, url.pathname, _build.basename);
let params = matches && matches.length > 0 ? matches[0].params : {};
let handleError = error => {
if (mode$1 === mode.ServerMode.Development) {
var _getDevServerHooks, _getDevServerHooks$pr;
(_getDevServerHooks = dev.getDevServerHooks()) === null || _getDevServerHooks === void 0 ? void 0 : (_getDevServerHooks$pr = _getDevServerHooks.processRequestError) === null || _getDevServerHooks$pr === void 0 ? void 0 : _getDevServerHooks$pr.call(_getDevServerHooks, error);
}
return new Response(JSON.stringify(build.assets), {
status: 200,
headers: {
"Content-Type": "application/json"
}
errorHandler(error, {
context: loadContext,
params,
request
});
}
let matches = routeMatching.matchServerRoutes(routes$1, url.pathname);
};
let response;
if (url.searchParams.has("_data")) {
if (_build.future.unstable_singleFetch) {
handleError(new Error("Warning: Single fetch-enabled apps should not be making ?_data requests, " + "this is likely to break in the future"));
}
let routeId = url.searchParams.get("_data");
response = await handleDataRequestRR(serverMode, staticHandler, routeId, request, loadContext);
if (build.entry.module.handleDataRequest) {
let match = matches.find(match => match.route.id == routeId);
response = await build.entry.module.handleDataRequest(response, {
response = await handleDataRequest(serverMode, _build, staticHandler, routeId, request, loadContext, handleError);
if (_build.entry.module.handleDataRequest) {
response = await _build.entry.module.handleDataRequest(response, {
context: loadContext,
params: match.params,
params,
request
});
if (responses.isRedirectResponse(response)) {
response = createRemixRedirectResponse(response, _build.basename);
}
}
} else if (matches && matches[matches.length - 1].route.module.default == null) {
response = await handleResourceRequestRR(serverMode, staticHandler, matches.slice(-1)[0].route.id, request, loadContext);
} else if (_build.future.unstable_singleFetch && url.pathname.endsWith(".data")) {
let handlerUrl = new URL(request.url);
handlerUrl.pathname = handlerUrl.pathname.replace(/\.data$/, "").replace(/^\/_root$/, "/");
let singleFetchMatches = routeMatching.matchServerRoutes(routes, handlerUrl.pathname, _build.basename);
response = await handleSingleFetchRequest(serverMode, _build, staticHandler, request, handlerUrl, loadContext, handleError);
if (_build.entry.module.handleDataRequest) {
response = await _build.entry.module.handleDataRequest(response, {
context: loadContext,
params: singleFetchMatches ? singleFetchMatches[0].params : {},
request
});
if (responses.isRedirectResponse(response)) {
let result = singleFetch.getSingleFetchRedirect(response.status, response.headers);
if (request.method === "GET") {
result = {
[singleFetch.SingleFetchRedirectSymbol]: result
};
}
let headers = new Headers(response.headers);
headers.set("Content-Type", "text/x-turbo");
return new Response(singleFetch.encodeViaTurboStream(result, request.signal, _build.entry.module.streamTimeout, serverMode), {
status: 200,
headers
});
}
}
} else if (matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
response = await handleResourceRequest(serverMode, _build, staticHandler, matches.slice(-1)[0].route.id, request, loadContext, handleError);
} else {
response = await handleDocumentRequestRR(serverMode, build, staticHandler, request, loadContext);
var _getDevServerHooks2, _getDevServerHooks2$g;
let criticalCss = mode$1 === mode.ServerMode.Development ? await ((_getDevServerHooks2 = dev.getDevServerHooks()) === null || _getDevServerHooks2 === void 0 ? void 0 : (_getDevServerHooks2$g = _getDevServerHooks2.getCriticalCss) === null || _getDevServerHooks2$g === void 0 ? void 0 : _getDevServerHooks2$g.call(_getDevServerHooks2, _build, url.pathname)) : undefined;
response = await handleDocumentRequest(serverMode, _build, staticHandler, request, loadContext, handleError, criticalCss);
}

@@ -80,3 +156,3 @@ if (request.method === "HEAD") {

};
async function handleDataRequestRR(serverMode, staticHandler, routeId, request, loadContext) {
async function handleDataRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {
try {

@@ -88,26 +164,20 @@ let response = await staticHandler.queryRoute(request, {

if (responses.isRedirectResponse(response)) {
// We don't have any way to prevent a fetch request from following
// redirects. So we use the `X-Remix-Redirect` header to indicate the
// next URL, and then "follow" the redirect manually on the client.
let headers = new Headers(response.headers);
headers.set("X-Remix-Redirect", headers.get("Location"));
headers.set("X-Remix-Status", response.status);
headers.delete("Location");
if (response.headers.get("Set-Cookie") !== null) {
headers.set("X-Remix-Revalidate", "yes");
}
return new Response(null, {
status: 204,
headers
});
return createRemixRedirectResponse(response, build.basename);
}
if (router.UNSAFE_DEFERRED_SYMBOL in response) {
let deferredData = response[router.UNSAFE_DEFERRED_SYMBOL];
let body = responses.createDeferredReadableStream(deferredData, request.signal);
let body = responses.createDeferredReadableStream(deferredData, request.signal, serverMode);
let init = deferredData.init || {};
let headers = new Headers(init.headers);
headers.set("Content-Type", "text/remix-deferred");
// Mark successful responses with a header so we can identify in-flight
// network errors that are missing this header
headers.set("X-Remix-Response", "yes");
init.headers = headers;
return new Response(body, init);
}
// Mark all successful responses with a header so we can identify in-flight
// network errors that are missing this header
response.headers.set("X-Remix-Response", "yes");
return response;

@@ -119,61 +189,46 @@ } catch (error) {

}
let status = 500;
let errorInstance = error;
if (router.isRouteErrorResponse(error)) {
status = error.status;
errorInstance = error.error || errorInstance;
handleError(error);
return errorResponseToJson(error, serverMode);
}
if (serverMode !== mode.ServerMode.Test && !request.signal.aborted) {
console.error(errorInstance);
}
if (serverMode === mode.ServerMode.Development && errorInstance instanceof Error) {
return errorBoundaryError(errorInstance, status);
}
return errorBoundaryError(new Error("Unexpected Server Error"), status);
let errorInstance = error instanceof Error || error instanceof DOMException ? error : new Error("Unexpected Server Error");
handleError(errorInstance);
return router.json(errors.serializeError(errorInstance, serverMode), {
status: 500,
headers: {
"X-Remix-Error": "yes"
}
});
}
}
function findParentBoundary(routes, routeId, error) {
// Fall back to the root route if we don't match any routes, since Remix
// has default error/catch boundary handling. This handles the case where
// react-router doesn't have a matching "root" route to assign the error to
// so it returns context.errors = { __shim-error-route__: ErrorResponse }
let route = routes[routeId] || routes["root"];
// Router-thrown ErrorResponses will have the error instance. User-thrown
// Responses will not have an error. The one exception here is internal 404s
// which we handle the same as user-thrown 404s
let isCatch = router.isRouteErrorResponse(error) && (!error.error || error.status === 404);
if (isCatch && route.module.CatchBoundary || !isCatch && route.module.ErrorBoundary || !route.parentId) {
return route.id;
}
return findParentBoundary(routes, route.parentId, error);
}
async function handleSingleFetchRequest(serverMode, build, staticHandler, request, handlerUrl, loadContext, handleError) {
let {
result,
headers,
status
} = request.method !== "GET" ? await singleFetch.singleFetchAction(serverMode, staticHandler, request, handlerUrl, loadContext, handleError) : await singleFetch.singleFetchLoaders(serverMode, staticHandler, request, handlerUrl, loadContext, handleError);
// Re-generate a remix-friendly context.errors structure. The Router only
// handles generic errors and does not distinguish error versus catch. We
// may have a thrown response tagged to a route that only exports an
// ErrorBoundary or vice versa. So we adjust here and ensure that
// data-loading errors are properly associated with routes that have the right
// type of boundaries.
function differentiateCatchVersusErrorBoundaries(build, context) {
if (!context.errors) {
return;
}
let errors = {};
for (let routeId of Object.keys(context.errors)) {
let error = context.errors[routeId];
let handlingRouteId = findParentBoundary(build.routes, routeId, error);
errors[handlingRouteId] = error;
}
context.errors = errors;
// Mark all successful responses with a header so we can identify in-flight
// network errors that are missing this header
let resultHeaders = new Headers(headers);
resultHeaders.set("X-Remix-Response", "yes");
resultHeaders.set("Content-Type", "text/x-turbo");
// Note: Deferred data is already just Promises, so we don't have to mess
// `activeDeferreds` or anything :)
return new Response(singleFetch.encodeViaTurboStream(result, request.signal, build.entry.module.streamTimeout, serverMode), {
status: status || 200,
headers: resultHeaders
});
}
async function handleDocumentRequestRR(serverMode, build, staticHandler, request, loadContext) {
async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, criticalCss) {
let context;
let responseStubs = singleFetch.getResponseStubs();
try {
context = await staticHandler.query(request, {
requestContext: loadContext
requestContext: loadContext,
unstable_dataStrategy: build.future.unstable_singleFetch ? singleFetch.getSingleFetchDataStrategy(responseStubs) : undefined
});
} catch (error) {
if (!request.signal.aborted && serverMode !== mode.ServerMode.Test) {
console.error(error);
}
handleError(error);
return new Response(null, {

@@ -186,8 +241,38 @@ status: 500

}
let statusCode;
let headers$1;
if (build.future.unstable_singleFetch) {
let merged = singleFetch.mergeResponseStubs(context, responseStubs);
statusCode = merged.statusCode;
headers$1 = merged.headers;
if (responses.isRedirectStatusCode(statusCode) && headers$1.has("Location")) {
return new Response(null, {
status: statusCode,
headers: headers$1
});
}
} else {
statusCode = context.statusCode;
headers$1 = headers.getDocumentHeaders(build, context);
}
// Restructure context.errors to the right Catch/Error Boundary
if (build.future.v2_errorBoundary !== true) {
differentiateCatchVersusErrorBoundaries(build, context);
// Sanitize errors outside of development environments
if (context.errors) {
Object.values(context.errors).forEach(err => {
// @ts-expect-error `err.error` is "private" from users but intended for internal use
if ((!router.isRouteErrorResponse(err) || err.error) && !singleFetch.isResponseStub(err)) {
handleError(err);
}
});
context.errors = errors.sanitizeErrors(context.errors, serverMode);
}
let headers$1 = headers.getDocumentHeadersRR(build, context);
// Server UI state to send to the client.
// - When single fetch is enabled, this is streamed down via `serverHandoffStream`
// - Otherwise it's stringified into `serverHandoffString`
let state = {
loaderData: context.loaderData,
actionData: context.actionData,
errors: errors.serializeErrors(context.errors, serverMode)
};
let entryContext = {

@@ -197,26 +282,56 @@ manifest: build.assets,

staticHandlerContext: context,
criticalCss,
serverHandoffString: serverHandoff.createServerHandoffString({
state: {
loaderData: context.loaderData,
actionData: context.actionData,
errors: errors.serializeErrors(context.errors)
},
url: context.location.pathname,
basename: build.basename,
criticalCss,
future: build.future,
dev: build.dev
isSpaMode: build.isSpaMode,
...(!build.future.unstable_singleFetch ? {
state
} : null)
}),
future: build.future
...(build.future.unstable_singleFetch ? {
serverHandoffStream: singleFetch.encodeViaTurboStream(state, request.signal, build.entry.module.streamTimeout, serverMode),
renderMeta: {}
} : null),
future: build.future,
isSpaMode: build.isSpaMode,
serializeError: err => errors.serializeError(err, serverMode)
};
let handleDocumentRequestFunction = build.entry.module.default;
try {
return await handleDocumentRequestFunction(request, context.statusCode, headers$1, entryContext);
return await handleDocumentRequestFunction(request, statusCode, headers$1, entryContext, loadContext);
} catch (error) {
handleError(error);
let errorForSecondRender = error;
// If they threw a response, unwrap it into an ErrorResponse like we would
// have for a loader/action
if (responses.isResponse(error)) {
try {
let data = await unwrapResponse(error);
errorForSecondRender = new router.UNSAFE_ErrorResponseImpl(error.status, error.statusText, data);
} catch (e) {
// If we can't unwrap the response - just leave it as-is
}
}
// Get a new StaticHandlerContext that contains the error at the right boundary
context = router.getStaticContextFromError(staticHandler.dataRoutes, context, error);
context = router.getStaticContextFromError(staticHandler.dataRoutes, context, errorForSecondRender);
// Restructure context.errors to the right Catch/Error Boundary
if (build.future.v2_errorBoundary !== true) {
differentiateCatchVersusErrorBoundaries(build, context);
// Sanitize errors outside of development environments
if (context.errors) {
context.errors = errors.sanitizeErrors(context.errors, serverMode);
}
// Update entryContext for the second render pass
// Get a new entryContext for the second render pass
// Server UI state to send to the client.
// - When single fetch is enabled, this is streamed down via `serverHandoffStream`
// - Otherwise it's stringified into `serverHandoffString`
let state = {
loaderData: context.loaderData,
actionData: context.actionData,
errors: errors.serializeErrors(context.errors, serverMode)
};
entryContext = {

@@ -226,13 +341,19 @@ ...entryContext,

serverHandoffString: serverHandoff.createServerHandoffString({
state: {
loaderData: context.loaderData,
actionData: context.actionData,
errors: errors.serializeErrors(context.errors)
},
future: build.future
})
url: context.location.pathname,
basename: build.basename,
future: build.future,
isSpaMode: build.isSpaMode,
...(!build.future.unstable_singleFetch ? {
state
} : null)
}),
...(build.future.unstable_singleFetch ? {
serverHandoffStream: singleFetch.encodeViaTurboStream(state, request.signal, build.entry.module.streamTimeout, serverMode),
renderMeta: {}
} : null)
};
try {
return await handleDocumentRequestFunction(request, context.statusCode, headers$1, entryContext);
return await handleDocumentRequestFunction(request, context.statusCode, headers$1, entryContext, loadContext);
} catch (error) {
handleError(error);
return returnLastResortErrorResponse(error, serverMode);

@@ -242,4 +363,5 @@ }

}
async function handleResourceRequestRR(serverMode, staticHandler, routeId, request, loadContext) {
async function handleResourceRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {
try {
let responseStubs = build.future.unstable_singleFetch ? singleFetch.getResponseStubs() : {};
// Note we keep the routeId here to align with the Remix handling of

@@ -250,5 +372,34 @@ // resource routes which doesn't take ?index into account and just takes

routeId,
requestContext: loadContext
requestContext: loadContext,
...(build.future.unstable_singleFetch ? {
unstable_dataStrategy: singleFetch.getSingleFetchResourceRouteDataStrategy({
responseStubs
})
} : null)
});
// callRouteLoader/callRouteAction always return responses
if (typeof response === "object") {
invariant["default"](!(router.UNSAFE_DEFERRED_SYMBOL in response), `You cannot return a \`defer()\` response from a Resource Route. Did you ` + `forget to export a default UI component from the "${routeId}" route?`);
}
if (build.future.unstable_singleFetch) {
let stub = responseStubs[routeId];
if (responses.isResponse(response)) {
// If a response was returned, we use it's status and we merge our
// response stub headers onto it
let ops = stub[routeModules.ResponseStubOperationsSymbol];
for (let [op, ...args] of ops) {
// @ts-expect-error
response.headers[op](...args);
}
} else {
console.warn(deprecations.resourceRouteJsonWarning(request.method === "GET" ? "loader" : "action", routeId));
// Otherwise we create a json Response using the stub
response = responses.json(response, {
status: stub.status,
headers: stub.headers
});
}
}
// callRouteLoader/callRouteAction always return responses (w/o single fetch).
// With single fetch, users should always be Responses from resource routes
invariant["default"](responses.isResponse(response), "Expected a Response to be returned from queryRoute");

@@ -263,8 +414,18 @@ return response;

}
if (router.isRouteErrorResponse(error)) {
if (error) {
handleError(error);
}
return errorResponseToJson(error, serverMode);
}
handleError(error);
return returnLastResortErrorResponse(error, serverMode);
}
}
async function errorBoundaryError(error, status) {
return responses.json(await errors.serializeError(error), {
status,
function errorResponseToJson(errorResponse, serverMode) {
return router.json(errors.serializeError(
// @ts-expect-error This is "private" from users but intended for internal use
errorResponse.error || new Error("Unexpected Server Error"), serverMode), {
status: errorResponse.status,
statusText: errorResponse.statusText,
headers: {

@@ -276,5 +437,2 @@ "X-Remix-Error": "yes"

function returnLastResortErrorResponse(error, serverMode) {
if (serverMode !== mode.ServerMode.Test) {
console.error(error);
}
let message = "Unexpected Server Error";

@@ -293,4 +451,26 @@ if (serverMode !== mode.ServerMode.Production) {

}
function unwrapResponse(response) {
let contentType = response.headers.get("Content-Type");
// Check between word boundaries instead of startsWith() due to the last
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
return contentType && /\bapplication\/json\b/.test(contentType) ? response.body == null ? null : response.json() : response.text();
}
function createRemixRedirectResponse(response, basename) {
// We don't have any way to prevent a fetch request from following
// redirects. So we use the `X-Remix-Redirect` header to indicate the
// next URL, and then "follow" the redirect manually on the client.
let headers = new Headers(response.headers);
let redirectUrl = headers.get("Location");
headers.set("X-Remix-Redirect", basename ? router.stripBasename(redirectUrl, basename) || redirectUrl : redirectUrl);
headers.set("X-Remix-Status", String(response.status));
headers.delete("Location");
if (response.headers.get("Set-Cookie") !== null) {
headers.set("X-Remix-Revalidate", "yes");
}
return new Response(null, {
status: 204,
headers
});
}
exports.createRequestHandler = createRequestHandler;
exports.differentiateCatchVersusErrorBoundaries = differentiateCatchVersusErrorBoundaries;
import type { HydrationState } from "@remix-run/router";
import type { FutureConfig } from "./entry";
declare type ValidateShape<T, Shape> = T extends Shape ? Exclude<keyof T, keyof Shape> extends never ? T : never : never;
type ValidateShape<T, Shape> = T extends Shape ? Exclude<keyof T, keyof Shape> extends never ? T : never : never;
export declare function createServerHandoffString<T>(serverHandoff: {
state: ValidateShape<T, HydrationState>;
state?: ValidateShape<T, HydrationState>;
criticalCss?: string;
url: string;
basename: string | undefined;
future: FutureConfig;
dev?: {
liveReloadPort: number;
};
isSpaMode: boolean;
}): string;
export {};
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -14,3 +14,3 @@ import type { CookieParseOptions, CookieSerializeOptions } from "cookie";

*/
export interface Session {
export interface Session<Data = SessionData, FlashData = Data> {
/**

@@ -29,3 +29,3 @@ * A unique identifier for this session.

*/
readonly data: SessionData;
readonly data: FlashSessionData<Data, FlashData>;
/**

@@ -35,11 +35,11 @@ * Returns `true` if the session has a value for the given `name`, `false`

*/
has(name: string): boolean;
has(name: (keyof Data | keyof FlashData) & string): boolean;
/**
* Returns the value for the given `name` in this session.
*/
get(name: string): any;
get<Key extends (keyof Data | keyof FlashData) & string>(name: Key): (Key extends keyof Data ? Data[Key] : undefined) | (Key extends keyof FlashData ? FlashData[Key] : undefined) | undefined;
/**
* Sets a value in the session for the given `name`.
*/
set(name: string, value: any): void;
set<Key extends keyof Data & string>(name: Key, value: Data[Key]): void;
/**

@@ -49,9 +49,13 @@ * Sets a value in the session that is only valid until the next `get()`.

*/
flash(name: string, value: any): void;
flash<Key extends keyof FlashData & string>(name: Key, value: FlashData[Key]): void;
/**
* Removes a value from the session.
*/
unset(name: string): void;
unset(name: keyof Data & string): void;
}
export declare type CreateSessionFunction = (initialData?: SessionData, id?: string) => Session;
export type FlashSessionData<Data, FlashData> = Partial<Data & {
[Key in keyof FlashData as FlashDataKey<Key & string>]: FlashData[Key];
}>;
type FlashDataKey<Key extends string> = `__flash_${Key}__`;
export type CreateSessionFunction = <Data = SessionData, FlashData = Data>(initialData?: Data, id?: string) => Session<Data, FlashData>;
/**

@@ -66,3 +70,3 @@ * Creates a new Session object.

export declare const createSession: CreateSessionFunction;
export declare type IsSessionFunction = (object: any) => object is Session;
export type IsSessionFunction = (object: any) => object is Session;
/**

@@ -81,3 +85,3 @@ * Returns true if an object is a Remix session.

*/
export interface SessionStorage {
export interface SessionStorage<Data = SessionData, FlashData = Data> {
/**

@@ -88,3 +92,3 @@ * Parses a Cookie header from a HTTP request and returns the associated

*/
getSession(cookieHeader?: string | null, options?: CookieParseOptions): Promise<Session>;
getSession: (cookieHeader?: string | null, options?: CookieParseOptions) => Promise<Session<Data, FlashData>>;
/**

@@ -94,3 +98,3 @@ * Stores all data in the Session and returns the Set-Cookie header to be

*/
commitSession(session: Session, options?: CookieSerializeOptions): Promise<string>;
commitSession: (session: Session<Data, FlashData>, options?: CookieSerializeOptions) => Promise<string>;
/**

@@ -100,3 +104,3 @@ * Deletes all data associated with the Session and returns the Set-Cookie

*/
destroySession(session: Session, options?: CookieSerializeOptions): Promise<string>;
destroySession: (session: Session<Data, FlashData>, options?: CookieSerializeOptions) => Promise<string>;
}

@@ -112,3 +116,3 @@ /**

*/
export interface SessionIdStorageStrategy {
export interface SessionIdStorageStrategy<Data = SessionData, FlashData = Data> {
/**

@@ -124,11 +128,11 @@ * The Cookie used to store the session id, or options used to automatically

*/
createData: (data: SessionData, expires?: Date) => Promise<string>;
createData: (data: FlashSessionData<Data, FlashData>, expires?: Date) => Promise<string>;
/**
* Returns data for a given session id, or `null` if there isn't any.
*/
readData: (id: string) => Promise<SessionData | null>;
readData: (id: string) => Promise<FlashSessionData<Data, FlashData> | null>;
/**
* Updates data for the given session id.
*/
updateData: (id: string, data: SessionData, expires?: Date) => Promise<void>;
updateData: (id: string, data: FlashSessionData<Data, FlashData>, expires?: Date) => Promise<void>;
/**

@@ -139,3 +143,3 @@ * Deletes data for a given session id from the data store.

}
export declare type CreateSessionStorageFunction = (strategy: SessionIdStorageStrategy) => SessionStorage;
export type CreateSessionStorageFunction = <Data = SessionData, FlashData = Data>(strategy: SessionIdStorageStrategy<Data, FlashData>) => SessionStorage<Data, FlashData>;
/**

@@ -151,1 +155,2 @@ * Creates a SessionStorage object using a SessionIdStorageStrategy.

export declare function warnOnceAboutSigningSessionCookie(cookie: Cookie): void;
export {};
/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -22,2 +22,8 @@ * Copyright (c) Remix Software Inc.

/**
* Session persists data across HTTP requests.
*
* @see https://remix.run/utils/sessions#session-api
*/
function flash(name) {

@@ -85,2 +91,12 @@ return `__flash_${name}__`;

/**
* SessionIdStorageStrategy is designed to allow anyone to easily build their
* own SessionStorage using `createSessionStorage(strategy)`.
*
* This strategy describes a common scenario where the session id is stored in
* a cookie but the actual session data is stored elsewhere, usually in a
* database or on disk. A set of create, read, update, and delete operations
* are provided for managing the session data.
*/
/**
* Creates a SessionStorage object using a SessionIdStorageStrategy.

@@ -113,6 +129,7 @@ *

} = session;
let expires = (options === null || options === void 0 ? void 0 : options.maxAge) != null ? new Date(Date.now() + options.maxAge * 1000) : (options === null || options === void 0 ? void 0 : options.expires) != null ? options.expires : cookie.expires;
if (id) {
await updateData(id, data, cookie.expires);
await updateData(id, data, expires);
} else {
id = await createData(data, cookie.expires);
id = await createData(data, expires);
}

@@ -125,2 +142,3 @@ return cookie.serialize(id, options);

...options,
maxAge: undefined,
expires: new Date(0)

@@ -127,0 +145,0 @@ });

import type { CreateCookieFunction } from "../cookies";
import type { SessionStorage, SessionIdStorageStrategy } from "../sessions";
import type { SessionStorage, SessionIdStorageStrategy, SessionData } from "../sessions";
interface CookieSessionStorageOptions {

@@ -10,3 +10,3 @@ /**

}
export declare type CreateCookieSessionStorageFunction = (options?: CookieSessionStorageOptions) => SessionStorage;
export type CreateCookieSessionStorageFunction = <Data = SessionData, FlashData = Data>(options?: CookieSessionStorageOptions) => SessionStorage<Data, FlashData>;
/**

@@ -13,0 +13,0 @@ * Creates and returns a SessionStorage object that stores all session data

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -48,2 +48,3 @@ * Copyright (c) Remix Software Inc.

...options,
maxAge: undefined,
expires: new Date(0)

@@ -50,0 +51,0 @@ });

@@ -1,2 +0,2 @@

import type { SessionStorage, SessionIdStorageStrategy, CreateSessionStorageFunction } from "../sessions";
import type { SessionData, SessionStorage, SessionIdStorageStrategy, CreateSessionStorageFunction } from "../sessions";
interface MemorySessionStorageOptions {

@@ -9,3 +9,3 @@ /**

}
export declare type CreateMemorySessionStorageFunction = (options?: MemorySessionStorageOptions) => SessionStorage;
export type CreateMemorySessionStorageFunction = <Data = SessionData, FlashData = Data>(options?: MemorySessionStorageOptions) => SessionStorage<Data, FlashData>;
/**

@@ -12,0 +12,0 @@ * Creates and returns a simple in-memory SessionStorage object, mostly useful

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -27,3 +27,2 @@ * Copyright (c) Remix Software Inc.

} = {}) => {
let uniqueId = 0;
let map = new Map();

@@ -33,3 +32,3 @@ return createSessionStorage({

async createData(data, expires) {
let id = (++uniqueId).toString();
let id = Math.random().toString(36).substring(2, 10);
map.set(id, {

@@ -36,0 +35,0 @@ data,

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -1,3 +0,3 @@

import type { UploadHandler } from "@remix-run/server-runtime";
export declare type MemoryUploadHandlerFilterArgs = {
import type { UploadHandler } from "../formData";
export type MemoryUploadHandlerFilterArgs = {
filename?: string;

@@ -7,3 +7,3 @@ contentType: string;

};
export declare type MemoryUploadHandlerOptions = {
export type MemoryUploadHandlerOptions = {
/**

@@ -10,0 +10,0 @@ * The maximum upload size allowed. If the size is exceeded an error will be thrown.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/server-runtime v0.0.0-nightly-12e88ce-20230120
* @remix-run/server-runtime v0.0.0-nightly-142f47be5-20240507
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -1,7 +0,22 @@

Copyright 2021 Remix Software Inc.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Copyright (c) Remix Software Inc. 2020-2021
Copyright (c) Shopify Inc. 2022-2024
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
"name": "@remix-run/server-runtime",
"version": "0.0.0-nightly-12e88ce-20230120",
"version": "0.0.0-nightly-142f47be5-20240507",
"description": "Server runtime for Remix",

@@ -19,21 +19,24 @@ "bugs": {

"dependencies": {
"@remix-run/router": "1.3.0",
"@types/cookie": "^0.4.0",
"@remix-run/router": "1.16.1-pre.0",
"@types/cookie": "^0.6.0",
"@web3-storage/multipart-parser": "^1.0.0",
"cookie": "^0.4.1",
"cookie": "^0.6.0",
"set-cookie-parser": "^2.4.8",
"source-map": "^0.7.3"
"source-map": "^0.7.3",
"turbo-stream": "^2.0.0"
},
"devDependencies": {
"@remix-run/web-file": "^3.0.2",
"@types/set-cookie-parser": "^2.4.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"typescript": "^5.1.6"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
"typescript": "^5.1.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
},
"engines": {
"node": ">=14"
"node": ">=18.0.0"
},

@@ -45,3 +48,6 @@ "files": [

"README.md"
]
}
],
"scripts": {
"tsc": "tsc"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc