Socket
Socket
Sign inDemoInstall

@remix-run/server-runtime

Package Overview
Dependencies
Maintainers
2
Versions
1005
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@remix-run/server-runtime - npm Package Compare versions

Comparing version 0.0.0-nightly-8941a69-20230420 to 0.0.0-nightly-8a997a62d-20240604

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;
}
/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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,5 +0,8 @@

import type { ActionFunction, DataFunctionArgs, LoaderFunction } from "./routeModules";
import type { ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs } from "./routeModules";
import type { ResponseStub } from "./single-fetch";
/**
* 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
*/

@@ -11,19 +14,21 @@ export interface AppLoadContext {

* Data for a route that was returned from a `loader()`.
*
* Note: This moves to unknown in ReactRouter and eventually likely in Remix
*/
export 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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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,8 @@ let result = await action({

context: loadContext,
params
params,
// Only provided when single fetch is enabled, and made available via
// `defineAction` types, not `ActionFunctionArgs`
...(singleFetch ? {
response
} : null)
});

@@ -35,5 +53,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 +66,5 @@ loader,

request,
routeId
routeId,
singleFetch,
response
}) {

@@ -49,3 +74,8 @@ let result = await loader({

context: loadContext,
params
params,
// Only provided when single fetch is enabled, and made available via
// `defineLoader` types, not `LoaderFunctionArgs`
...(singleFetch ? {
response
} : null)
});

@@ -61,2 +91,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 +118,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 +133,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,22 +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;
}
type Dev = {
port?: number;
appServerPort?: number;
remixRequestHandlerPath?: string;
rebuildPollIntervalMs?: number;
};
export interface FutureConfig {
unstable_dev: boolean | Dev;
/** @deprecated Use the `postcss` config option instead */
unstable_postcss: boolean;
/** @deprecated Use the `tailwind` config option instead */
unstable_tailwind: boolean;
v2_errorBoundary: boolean;
v2_meta: boolean;
v2_normalizeFormMethod: boolean;
v2_routeConvention: boolean;
v3_fetcherPersist: boolean;
v3_relativeSplatPath: boolean;
v3_throwAbortReason: boolean;
unstable_singleFetch: boolean;
}

@@ -40,2 +44,1 @@ export interface AssetsManifest {

export declare function createEntryRouteModules(manifest: ServerRouteManifest): RouteModules<EntryRouteModule>;
export {};
/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

@@ -44,11 +44,2 @@ import type { StaticHandlerContext } from "@remix-run/router";

*/
/**
* @deprecated in favor of the `ErrorResponse` class in React Router. Please
* enable the `future.v2_errorBoundary` flag to ease your migration to Remix v2.
*/
export interface ThrownResponse<T = any> {
status: number;
statusText: string;
data: T;
}
export declare function sanitizeError<T = unknown>(error: T, serverMode: ServerMode): T | Error;

@@ -55,0 +46,0 @@ export declare function sanitizeErrors(errors: NonNullable<StaticHandlerContext["errors"]>, serverMode: ServerMode): {};

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -60,7 +60,2 @@ * Copyright (c) Remix Software Inc.

/**
* @deprecated in favor of the `ErrorResponse` class in React Router. Please
* enable the `future.v2_errorBoundary` flag to ease your migration to Remix v2.
*/
function sanitizeError(error, serverMode) {

@@ -109,3 +104,10 @@ if (error instanceof Error && serverMode !== mode.ServerMode.Development) {

stack: sanitized.stack,
__type: "Error"
__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
} : {})
};

@@ -112,0 +114,0 @@ } else {

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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,8 @@ let result = await action({

context: loadContext,
params
params,
// Only provided when single fetch is enabled, and made available via
// `defineAction` types, not `ActionFunctionArgs`
...(singleFetch ? {
response
} : null)
});

@@ -31,5 +49,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 +62,5 @@ loader,

request,
routeId
routeId,
singleFetch,
response
}) {

@@ -45,3 +70,8 @@ let result = await loader({

context: loadContext,
params
params,
// Only provided when single fetch is enabled, and made available via
// `defineLoader` types, not `LoaderFunctionArgs`
...(singleFetch ? {
response
} : null)
});

@@ -57,2 +87,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 +114,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 +129,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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -56,7 +56,2 @@ * Copyright (c) Remix Software Inc.

/**
* @deprecated in favor of the `ErrorResponse` class in React Router. Please
* enable the `future.v2_errorBoundary` flag to ease your migration to Remix v2.
*/
function sanitizeError(error, serverMode) {

@@ -105,3 +100,10 @@ if (error instanceof Error && serverMode !== ServerMode.Development) {

stack: sanitized.stack,
__type: "Error"
__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
} : {})
};

@@ -108,0 +110,0 @@ } else {

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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, defineAction as unstable_defineAction, defineLoader as unstable_defineLoader } 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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

*/
import { json as json$1, defer as defer$1, redirect as redirect$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
/**

@@ -28,3 +31,3 @@ * This is a shortcut for creating `application/json` responses. Converts `data`

*
* @see https://remix.run/docs/utils/defer
* @see https://remix.run/utils/defer
*/

@@ -43,2 +46,13 @@ const defer = (data, 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) {

@@ -112,2 +126,2 @@ let deferred = value;

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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

*/
import { callRouteLoaderRR, callRouteActionRR } from './data.js';
import { callRouteLoader, callRouteAction } from './data.js';
// 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) {

@@ -39,9 +43,11 @@ let routes = {};

return (routesByParentId[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;
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,

@@ -51,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,

@@ -59,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,

@@ -62,0 +72,0 @@ handle: route.module.handle

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -11,55 +11,130 @@ * 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 { serializeError, sanitizeErrors, serializeErrors } from './errors.js';
import { getDocumentHeadersRR } from './headers.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, ResponseStubOperationsSymbol, SingleFetchRedirectSymbol } from './single-fetch.js';
import { resourceRouteJsonWarning } from './deprecations.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 === true ? "/__REMIX_ASSETS_MANIFEST" : (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 ? 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 +151,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,16 +159,3 @@ 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);
}

@@ -106,5 +168,12 @@ if (UNSAFE_DEFERRED_SYMBOL in response) {

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;

@@ -116,7 +185,10 @@ } catch (error) {

}
let status = isRouteErrorResponse(error) ? error.status : 500;
let errorInstance = isRouteErrorResponse(error) && error.error ? error.error : error instanceof Error ? error : new Error("Unexpected Server Error");
logServerErrorIfNotAborted(errorInstance, request, serverMode);
if (isRouteErrorResponse(error)) {
handleError(error);
return errorResponseToJson(error, serverMode);
}
let errorInstance = error instanceof Error || error instanceof DOMException ? error : new Error("Unexpected Server Error");
handleError(errorInstance);
return json(serializeError(errorInstance, serverMode), {
status,
status: 500,
headers: {

@@ -128,44 +200,32 @@ "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) {
logServerErrorIfNotAborted(error, request, serverMode);
handleError(error);
return new Response(null, {

@@ -178,13 +238,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);
}
// 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);
}
// Restructure context.errors to the right Catch/Error Boundary
if (build.future.v2_errorBoundary !== true) {
differentiateCatchVersusErrorBoundaries(build, context);
}
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 = {

@@ -194,19 +279,41 @@ manifest: build.assets,

staticHandlerContext: context,
criticalCss,
serverHandoffString: createServerHandoffString({
state: {
loaderData: context.loaderData,
actionData: context.actionData,
errors: serializeErrors(context.errors, serverMode)
},
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);

@@ -218,8 +325,11 @@ // Sanitize errors outside of development environments

// Restructure context.errors to the right Catch/Error Boundary
if (build.future.v2_errorBoundary !== true) {
differentiateCatchVersusErrorBoundaries(build, context);
}
// 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 = {

@@ -229,14 +339,19 @@ ...entryContext,

serverHandoffString: createServerHandoffString({
state: {
loaderData: context.loaderData,
actionData: context.actionData,
errors: serializeErrors(context.errors, serverMode)
},
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) {
logServerErrorIfNotAborted(error, request, serverMode);
handleError(error);
return returnLastResortErrorResponse(error, serverMode);

@@ -246,4 +361,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

@@ -254,5 +370,41 @@ // 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" && response !== null) {
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 if (isResponseStub(response) || response == null) {
// If the stub or null was returned, then there is no body so we just
// proxy along the status/headers to a Response
response = new Response(null, {
status: stub.status,
headers: stub.headers
});
} 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");

@@ -267,10 +419,28 @@ return response;

}
logServerErrorIfNotAborted(error, request, serverMode);
if (isResponseStub(error)) {
return new Response(null, {
status: error.status,
headers: error.headers
});
}
if (isRouteErrorResponse(error)) {
if (error) {
handleError(error);
}
return errorResponseToJson(error, serverMode);
}
handleError(error);
return returnLastResortErrorResponse(error, serverMode);
}
}
function logServerErrorIfNotAborted(error, request, serverMode) {
if (serverMode !== ServerMode.Test && !request.signal.aborted) {
console.error(error);
}
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: {
"X-Remix-Error": "yes"
}
});
}

@@ -291,3 +461,26 @@ function returnLastResortErrorResponse(error, serverMode) {

}
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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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 { SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol, defineLoader as unstable_defineLoader, defineAction as unstable_defineAction, } from "./single-fetch";
export type { Loader as unstable_Loader, Action as unstable_Action, Serialize as unstable_Serialize, SingleFetchResult as UNSAFE_SingleFetchResult, SingleFetchResults as UNSAFE_SingleFetchResults, } 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, FlashSessionData, HandleDataRequestFunction, HandleDocumentRequestFunction, HeadersFunction, HtmlLinkDescriptor, HtmlMetaDescriptor, LinkDescriptor, LinksFunction, LoaderArgs, LoaderFunction, MemoryUploadHandlerFilterArgs, MemoryUploadHandlerOptions, MetaDescriptor, MetaFunction, PageLinkDescriptor, RequestHandler, RouteComponent, RouteHandle, SerializeFrom, ServerBuild, ServerEntryModule, V2_ServerRuntimeMetaArgs, V2_ServerRuntimeMetaDescriptor, V2_ServerRuntimeMetaFunction, 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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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,6 @@

exports.redirect = responses.redirect;
exports.redirectDocument = responses.redirectDocument;
exports.UNSAFE_SingleFetchRedirectSymbol = singleFetch.SingleFetchRedirectSymbol;
exports.unstable_defineAction = singleFetch.defineAction;
exports.unstable_defineLoader = singleFetch.defineLoader;
exports.createRequestHandler = server.createRequestHandler;

@@ -45,1 +51,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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

@@ -94,16 +94,7 @@ type Primitive = null | undefined | string | number | boolean | symbol | bigint;

*/
export 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.

@@ -110,0 +101,0 @@ */

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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, LinksFunction, LoaderArgs, LoaderFunction, MetaDescriptor, MetaFunction, RouteComponent, RouteHandle, V2_ServerRuntimeMetaArgs, V2_ServerRuntimeMetaDescriptor, V2_ServerRuntimeMetaFunction, } 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, FlashSessionData, } from "./sessions";

@@ -9,4 +9,4 @@ import { type UNSAFE_DeferredData as DeferredData } from "@remix-run/router";

export type DeferFunction = <Data extends Record<string, unknown>>(data: Data, init?: number | ResponseInit) => TypedDeferredData<Data>;
export type JsonFunction = <Data extends unknown>(data: Data, init?: number | ResponseInit) => TypedResponse<Data>;
export type TypedResponse<T extends unknown = unknown> = Omit<Response, "json"> & {
export type JsonFunction = <Data>(data: Data, init?: number | ResponseInit) => TypedResponse<Data>;
export type TypedResponse<T = unknown> = Omit<Response, "json"> & {
json(): Promise<T>;

@@ -24,3 +24,3 @@ };

*
* @see https://remix.run/docs/utils/defer
* @see https://remix.run/utils/defer
*/

@@ -36,2 +36,10 @@ export declare const defer: DeferFunction;

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,0 +46,0 @@ export declare function isResponse(value: any): value is Response;

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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
/**

@@ -32,3 +35,3 @@ * This is a shortcut for creating `application/json` responses. Converts `data`

*
* @see https://remix.run/docs/utils/defer
* @see https://remix.run/utils/defer
*/

@@ -47,2 +50,13 @@ const defer = (data, 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) {

@@ -124,1 +138,2 @@ let deferred = value;

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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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,52 +0,70 @@

import type { AgnosticRouteMatch, Location, Params, RouterState } from "@remix-run/router";
import type { ComponentType } from "react";
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 { SerializeFrom } from "./serialize";
type RouteData = RouterState["loaderData"];
import type { ResponseStub } from "./single-fetch";
export interface RouteModules<RouteModule> {
[routeId: string]: RouteModule;
[routeId: string]: RouteModule | undefined;
}
/**
* The arguments passed to ActionFunction and LoaderFunction.
*
* Note this is almost identical to React Router's version but over there the
* context is optional since it's only there during static handler invocations.
* Keeping Remix's own definition for now so it can differentiate between
* client/server
* @deprecated Use `LoaderFunctionArgs`/`ActionFunctionArgs` instead
*/
export interface DataFunctionArgs {
request: Request;
export type DataFunctionArgs = RRActionFunctionArgs<AppLoadContext> & RRLoaderFunctionArgs<AppLoadContext> & {
context: AppLoadContext;
params: Params;
}
export type LoaderArgs = DataFunctionArgs;
export type ActionArgs = DataFunctionArgs;
};
/**
* A function that handles data mutations for a route.
* A function that handles data mutations for a route on the server
*/
export interface ActionFunction {
(args: DataFunctionArgs): Promise<Response> | Response | Promise<AppData> | AppData;
}
export type ActionFunction = (args: ActionFunctionArgs) => ReturnType<RRActionFunction>;
/**
* A React component that is rendered when the server throws a Response.
*
* @deprecated Please enable the v2_errorBoundary flag
* Arguments passed to a route `action` function
*/
export type CatchBoundaryComponent = ComponentType;
export type ActionFunctionArgs = RRActionFunctionArgs<AppLoadContext> & {
context: AppLoadContext;
response?: ResponseStub;
};
/**
* A React component that is rendered when there is an error on a route.
*
* @deprecated Please enable the v2_errorBoundary flag
* A function that handles data mutations for a route on the client
* @private Public API is exported from @remix-run/react
*/
export type ErrorBoundaryComponent = ComponentType<{
error: Error;
}>;
type ClientActionFunction = (args: ClientActionFunctionArgs) => ReturnType<RRActionFunction>;
/**
* V2 version of the ErrorBoundary that eliminates the distinction between
* Error and Catch Boundaries and behaves like RR 6.4 errorElement and captures
* errors with useRouteError()
* Arguments passed to a route `clientAction` function
* @private Public API is exported from @remix-run/react
*/
export type V2_ErrorBoundaryComponent = ComponentType;
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

@@ -56,7 +74,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;
}

@@ -71,14 +85,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
*

@@ -121,10 +131,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"

@@ -134,48 +144,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 type MetaFunction<Loader extends LoaderFunction | unknown = unknown, ParentsLoaders extends Record<string, LoaderFunction> = {}> = V1_MetaFunction<Loader, ParentsLoaders>;
interface V2_ServerRuntimeMetaMatch<RouteId extends string = string, Loader extends LoaderFunction | unknown = unknown> {
interface ServerRuntimeMetaMatch<RouteId extends string = string, Loader extends LoaderFunction | unknown = unknown> {
id: RouteId;
pathname: AgnosticRouteMatch["pathname"];
data: Loader extends LoaderFunction ? SerializeFrom<Loader> : unknown;
handle?: unknown;
handle?: RouteHandle;
params: AgnosticRouteMatch["params"];
meta: V2_ServerRuntimeMetaDescriptor[];
meta: ServerRuntimeMetaDescriptor[];
error?: unknown;
}
type V2_ServerRuntimeMetaMatches<MatchLoaders extends Record<string, unknown> = Record<string, unknown>> = Array<{
[K in keyof MatchLoaders]: V2_ServerRuntimeMetaMatch<Exclude<K, number | symbol>, MatchLoaders[K]>;
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 V2_ServerRuntimeMetaArgs<Loader extends LoaderFunction | unknown = unknown, MatchLoaders extends Record<string, unknown> = Record<string, unknown>> {
data: Loader extends LoaderFunction ? SerializeFrom<Loader> : AppData;
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;
location: Location;
matches: V2_ServerRuntimeMetaMatches<MatchLoaders>;
matches: ServerRuntimeMetaMatches<MatchLoaders>;
error?: unknown;
}
export interface V2_ServerRuntimeMetaFunction<Loader extends LoaderFunction | unknown = unknown, ParentsLoaders extends Record<string, LoaderFunction> = {}> {
(args: V2_ServerRuntimeMetaArgs<Loader, ParentsLoaders>): V2_ServerRuntimeMetaDescriptor[];
}
/**
* 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 type HtmlMetaDescriptor = V1_HtmlMetaDescriptor;
export type MetaDescriptor = HtmlMetaDescriptor;
export type V2_ServerRuntimeMetaDescriptor = {
export type ServerRuntimeMetaDescriptor = {
charSet: "utf-8";

@@ -210,16 +197,15 @@ } | {

/**
* A React component that is rendered for a route.
*/
export type RouteComponent = ComponentType<{}>;
/**
* An arbitrary object that is associated with a route.
*/
export type RouteHandle = any;
export type RouteHandle = unknown;
export interface EntryRouteModule {
CatchBoundary?: CatchBoundaryComponent;
ErrorBoundary?: ErrorBoundaryComponent | V2_ErrorBoundaryComponent;
default: RouteComponent;
clientAction?: ClientActionFunction;
clientLoader?: ClientLoaderFunction;
ErrorBoundary?: any;
HydrateFallback?: any;
Layout?: any;
default: any;
handle?: RouteHandle;
links?: LinksFunction;
meta?: MetaFunction | HtmlMetaDescriptor;
meta?: ServerRuntimeMetaFunction;
}

@@ -226,0 +212,0 @@ export interface ServerRouteModule extends EntryRouteModule {

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

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

@@ -23,0 +25,0 @@ parentId?: string;

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

// 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) {

@@ -43,9 +47,11 @@ let routes = {};

return (routesByParentId[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;
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,

@@ -55,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,

@@ -63,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,

@@ -66,0 +76,0 @@ handle: route.module.handle

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

import type { AppData } from "./data";
import type { Jsonify } from "./jsonify";
import type { TypedDeferredData, TypedResponse } from "./responses";
type JsonPrimitive = string | number | boolean | String | Number | Boolean | null;
type NonJsonPrimitive = undefined | Function | symbol;
type IsAny<T> = 0 extends 1 & T ? true : false;
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) */
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 */
type SerializeObject<T extends object> = {
[k in keyof T as T[k] extends NonJsonPrimitive ? never : k]: Serialize<T[k]>;
};
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]>;
};
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>;
};
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 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 type RequestHandler = (request: Request, loadContext?: AppLoadContext) => Promise<Response>;
export type CreateRequestHandlerFunction = (build: ServerBuild, mode?: string) => RequestHandler;
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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -25,45 +25,120 @@ * 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');
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 === true ? "/__REMIX_ASSETS_MANIFEST" : (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 ? 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 +155,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,16 +163,3 @@ 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);
}

@@ -110,5 +172,12 @@ if (router.UNSAFE_DEFERRED_SYMBOL in response) {

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;

@@ -120,7 +189,10 @@ } catch (error) {

}
let status = router.isRouteErrorResponse(error) ? error.status : 500;
let errorInstance = router.isRouteErrorResponse(error) && error.error ? error.error : error instanceof Error ? error : new Error("Unexpected Server Error");
logServerErrorIfNotAborted(errorInstance, request, serverMode);
return responses.json(errors.serializeError(errorInstance, serverMode), {
status,
if (router.isRouteErrorResponse(error)) {
handleError(error);
return errorResponseToJson(error, serverMode);
}
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: {

@@ -132,44 +204,32 @@ "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) {
logServerErrorIfNotAborted(error, request, serverMode);
handleError(error);
return new Response(null, {

@@ -182,13 +242,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);
}
// 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);
}
// Restructure context.errors to the right Catch/Error Boundary
if (build.future.v2_errorBoundary !== true) {
differentiateCatchVersusErrorBoundaries(build, context);
}
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 = {

@@ -198,19 +283,41 @@ manifest: build.assets,

staticHandlerContext: context,
criticalCss,
serverHandoffString: serverHandoff.createServerHandoffString({
state: {
loaderData: context.loaderData,
actionData: context.actionData,
errors: errors.serializeErrors(context.errors, serverMode)
},
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);

@@ -222,8 +329,11 @@ // Sanitize errors outside of development environments

// Restructure context.errors to the right Catch/Error Boundary
if (build.future.v2_errorBoundary !== true) {
differentiateCatchVersusErrorBoundaries(build, context);
}
// 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 = {

@@ -233,14 +343,19 @@ ...entryContext,

serverHandoffString: serverHandoff.createServerHandoffString({
state: {
loaderData: context.loaderData,
actionData: context.actionData,
errors: errors.serializeErrors(context.errors, serverMode)
},
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) {
logServerErrorIfNotAborted(error, request, serverMode);
handleError(error);
return returnLastResortErrorResponse(error, serverMode);

@@ -250,4 +365,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

@@ -258,5 +374,41 @@ // 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" && response !== null) {
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[singleFetch.ResponseStubOperationsSymbol];
for (let [op, ...args] of ops) {
// @ts-expect-error
response.headers[op](...args);
}
} else if (singleFetch.isResponseStub(response) || response == null) {
// If the stub or null was returned, then there is no body so we just
// proxy along the status/headers to a Response
response = new Response(null, {
status: stub.status,
headers: stub.headers
});
} 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");

@@ -271,10 +423,28 @@ return response;

}
logServerErrorIfNotAborted(error, request, serverMode);
if (singleFetch.isResponseStub(error)) {
return new Response(null, {
status: error.status,
headers: error.headers
});
}
if (router.isRouteErrorResponse(error)) {
if (error) {
handleError(error);
}
return errorResponseToJson(error, serverMode);
}
handleError(error);
return returnLastResortErrorResponse(error, serverMode);
}
}
function logServerErrorIfNotAborted(error, request, serverMode) {
if (serverMode !== mode.ServerMode.Test && !request.signal.aborted) {
console.error(error);
}
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: {
"X-Remix-Error": "yes"
}
});
}

@@ -295,4 +465,26 @@ function returnLastResortErrorResponse(error, serverMode) {

}
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;

@@ -5,8 +5,9 @@ import type { HydrationState } from "@remix-run/router";

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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

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

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

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

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

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

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

@@ -101,0 +101,0 @@ /**

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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 @@ });

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

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

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

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

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

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-8941a69-20230420
* @remix-run/server-runtime v0.0.0-nightly-8a997a62d-20240604
*

@@ -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-8941a69-20230420",
"version": "0.0.0-nightly-8a997a62d-20240604",
"description": "Server runtime for Remix",

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

"dependencies": {
"@remix-run/router": "1.5.0",
"@remix-run/router": "1.16.1",
"@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/cookie": "^0.4.0",
"@types/react": "^18.0.15",
"@types/set-cookie-parser": "^2.4.1"
"@types/set-cookie-parser": "^2.4.1",
"typescript": "^5.1.6"
},
"peerDependencies": {
"typescript": "^5.1.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
},
"engines": {
"node": ">=14"
"node": ">=18.0.0"
},

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

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

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc