Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@remix-run/server-runtime

Package Overview
Dependencies
Maintainers
2
Versions
1031
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-430d4b5f8-20240521 to 0.0.0-nightly-435cbd1da-20241118

dist/future.d.ts

2

dist/cookies.js
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

import type { ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs } from "./routeModules";
import type { ResponseStub } from "./single-fetch";
/**

@@ -16,3 +15,3 @@ * An object of unknown type for route loaders and actions provided by the

export type AppData = unknown;
export declare function callRouteAction({ loadContext, action, params, request, routeId, singleFetch, response, }: {
export declare function callRouteAction({ loadContext, action, params, request, routeId, singleFetch, }: {
request: Request;

@@ -24,5 +23,4 @@ action: ActionFunction;

singleFetch: boolean;
response?: ResponseStub;
}): Promise<{} | Response | null>;
export declare function callRouteLoader({ loadContext, loader, params, request, routeId, singleFetch, response, }: {
export declare function callRouteLoader({ loadContext, loader, params, request, routeId, singleFetch, }: {
request: Request;

@@ -34,3 +32,2 @@ loader: LoaderFunction;

singleFetch: boolean;
response?: ResponseStub;
}): Promise<{} | Response | null>;
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

routeId,
singleFetch,
response
singleFetch
}) {
let result = await action({
request: stripDataParam(stripIndexParam(request)),
request: singleFetch ? stripRoutesParam(stripIndexParam(request)) : stripDataParam(stripIndexParam(request)),
context: loadContext,
params,
// Only provided when single fetch is enabled, and made available via
// `defineAction` types, not `ActionFunctionArgs`
...(singleFetch ? {
response
} : null)
params
});

@@ -64,14 +58,8 @@ if (result === undefined) {

routeId,
singleFetch,
response
singleFetch
}) {
let result = await loader({
request: stripDataParam(stripIndexParam(request)),
request: singleFetch ? stripRoutesParam(stripIndexParam(request)) : stripDataParam(stripIndexParam(request)),
context: loadContext,
params,
// Only provided when single fetch is enabled, and made available via
// `defineLoader` types, not `LoaderFunctionArgs`
...(singleFetch ? {
response
} : null)
params
});

@@ -138,4 +126,18 @@ if (result === undefined) {

}
function stripRoutesParam(request) {
let url = new URL(request.url);
url.searchParams.delete("_routes");
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.callRouteAction = callRouteAction;
exports.callRouteLoader = callRouteLoader;
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

function resourceRouteJsonWarning(type, routeId) {
return "⚠️ REMIX FUTURE CHANGE: Resource routes will no longer be able to " + "return raw JavaScript objects in v3 when Single Fetch becomes the default. " + "You can prepare for this change at your convenience by wrapping the data " + `returned from your \`${type}\` function in the \`${routeId}\` route with ` + "`json()`. For instructions on making this change see " + "https://remix.run/docs/en/v2.9.2/guides/single-fetch#resource-routes";
return "⚠️ REMIX FUTURE CHANGE: Externally-accessed resource routes will no longer be " + "able to return raw JavaScript objects or `null` in React Router v7 when " + "Single Fetch becomes the default. You can prepare for this change at your " + `convenience by wrapping the data returned from your \`${type}\` function in ` + `the \`${routeId}\` route with \`json()\`. For instructions on making this ` + "change, see https://remix.run/docs/en/v2.13.1/guides/single-fetch#resource-routes";
}
exports.resourceRouteJsonWarning = resourceRouteJsonWarning;
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

@@ -30,3 +30,4 @@ import type { StaticHandlerContext } from "@remix-run/router";

v3_throwAbortReason: boolean;
unstable_singleFetch: boolean;
v3_lazyRouteDiscovery: boolean;
v3_singleFetch: boolean;
}

@@ -33,0 +34,0 @@ export interface AssetsManifest {

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

routeId,
singleFetch,
response
singleFetch
}) {
let result = await action({
request: stripDataParam(stripIndexParam(request)),
request: singleFetch ? stripRoutesParam(stripIndexParam(request)) : stripDataParam(stripIndexParam(request)),
context: loadContext,
params,
// Only provided when single fetch is enabled, and made available via
// `defineAction` types, not `ActionFunctionArgs`
...(singleFetch ? {
response
} : null)
params
});

@@ -60,14 +54,8 @@ if (result === undefined) {

routeId,
singleFetch,
response
singleFetch
}) {
let result = await loader({
request: stripDataParam(stripIndexParam(request)),
request: singleFetch ? stripRoutesParam(stripIndexParam(request)) : stripDataParam(stripIndexParam(request)),
context: loadContext,
params,
// Only provided when single fetch is enabled, and made available via
// `defineLoader` types, not `LoaderFunctionArgs`
...(singleFetch ? {
response
} : null)
params
});

@@ -134,3 +122,17 @@ if (result === undefined) {

}
function stripRoutesParam(request) {
let url = new URL(request.url);
url.searchParams.delete("_routes");
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 { callRouteAction, callRouteLoader };
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

function resourceRouteJsonWarning(type, routeId) {
return "⚠️ REMIX FUTURE CHANGE: Resource routes will no longer be able to " + "return raw JavaScript objects in v3 when Single Fetch becomes the default. " + "You can prepare for this change at your convenience by wrapping the data " + `returned from your \`${type}\` function in the \`${routeId}\` route with ` + "`json()`. For instructions on making this change see " + "https://remix.run/docs/en/v2.9.2/guides/single-fetch#resource-routes";
return "⚠️ REMIX FUTURE CHANGE: Externally-accessed resource routes will no longer be " + "able to return raw JavaScript objects or `null` in React Router v7 when " + "Single Fetch becomes the default. You can prepare for this change at your " + `convenience by wrapping the data returned from your \`${type}\` function in ` + `the \`${routeId}\` route with \`json()\`. For instructions on making this ` + "change, see https://remix.run/docs/en/v2.13.1/guides/single-fetch#resource-routes";
}
export { resourceRouteJsonWarning };
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

export { composeUploadHandlers as unstable_composeUploadHandlers, parseMultipartFormData as unstable_parseMultipartFormData } from './formData.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 { defer, json, redirect, redirectDocument, replace } from './responses.js';
export { SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol, data } from './single-fetch.js';
export { createRequestHandler } from './server.js';

@@ -17,0 +17,0 @@ export { createSession, createSessionStorageFactory, isSession } from './sessions.js';

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

*/
import { json as json$1, defer as defer$1, redirect as redirect$1, redirectDocument as redirectDocument$1 } from '@remix-run/router';
import { json as json$1, defer as defer$1, redirect as redirect$1, replace as replace$1, redirectDocument as redirectDocument$1 } from '@remix-run/router';
import { serializeError } from './errors.js';

@@ -22,2 +22,7 @@

*
* @deprecated This utility is deprecated in favor of opting into Single Fetch
* via `future.v3_singleFetch` and returning raw objects. This method will be
* removed in React Router v7. If you need to return a JSON Response, you can
* use `Response.json()`.
*
* @see https://remix.run/utils/json

@@ -32,2 +37,6 @@ */

*
* @deprecated This utility is deprecated in favor of opting into Single Fetch
* via `future.v3_singleFetch` and returning raw objects. This method will be
* removed in React Router v7.
*
* @see https://remix.run/utils/defer

@@ -49,2 +58,12 @@ */

/**
* A redirect response. Sets the status code and the `Location` header.
* Defaults to "302 Found".
*
* @see https://remix.run/utils/redirect
*/
const replace = (url, init = 302) => {
return replace$1(url, init);
};
/**
* A redirect response that will force a document reload to the new location.

@@ -127,2 +146,2 @@ * Sets the status code and the `Location` header.

export { createDeferredReadableStream, defer, isDeferredData, isRedirectResponse, isRedirectStatusCode, isResponse, json, redirect, redirectDocument };
export { createDeferredReadableStream, defer, isDeferredData, isRedirectResponse, isRedirectStatusCode, isResponse, json, redirect, redirectDocument, replace };
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

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

@@ -66,4 +65,3 @@ action: route.module.action ? (args, dataStrategyCtx) => callRouteAction({

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

@@ -70,0 +68,0 @@ handle: route.module.handle

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

*/
import { UNSAFE_DEFERRED_SYMBOL, isRouteErrorResponse, json, UNSAFE_ErrorResponseImpl, getStaticContextFromError, stripBasename, createStaticHandler } from '@remix-run/router';
import { UNSAFE_DEFERRED_SYMBOL, isRouteErrorResponse, json as json$1, UNSAFE_ErrorResponseImpl, getStaticContextFromError, stripBasename, createStaticHandler } from '@remix-run/router';
import { createEntryRouteModules } from './entry.js';

@@ -20,6 +20,6 @@ import { serializeError, sanitizeErrors, serializeErrors } from './errors.js';

import { createRoutes, createStaticHandlerDataRoutes } from './routes.js';
import { isRedirectResponse, createDeferredReadableStream, isResponse, isRedirectStatusCode, json as json$1 } from './responses.js';
import { isRedirectResponse, json, createDeferredReadableStream, isResponse } 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 { getSingleFetchRedirect, encodeViaTurboStream, SINGLE_FETCH_REDIRECT_STATUS, singleFetchAction, singleFetchLoaders, SingleFetchRedirectSymbol } from './single-fetch.js';
import { resourceRouteJsonWarning } from './deprecations.js';

@@ -79,4 +79,3 @@

let url = new URL(request.url);
let matches = matchServerRoutes(routes, url.pathname, _build.basename);
let params = matches && matches.length > 0 ? matches[0].params : {};
let params = {};
let handleError = error => {

@@ -93,5 +92,24 @@ if (mode === ServerMode.Development) {

};
// Manifest request for fog of war
let manifestUrl = `${_build.basename ?? "/"}/__manifest`.replace(/\/+/g, "/");
if (url.pathname === manifestUrl) {
try {
let res = await handleManifestRequest(_build, routes, url);
return res;
} catch (e) {
handleError(e);
return new Response("Unknown Server Error", {
status: 500
});
}
}
let matches = matchServerRoutes(routes, url.pathname, _build.basename);
if (matches && matches.length > 0) {
Object.assign(params, matches[0].params);
}
let response;
if (url.searchParams.has("_data")) {
if (_build.future.unstable_singleFetch) {
if (_build.future.v3_singleFetch) {
handleError(new Error("Warning: Single fetch-enabled apps should not be making ?_data requests, " + "this is likely to break in the future"));

@@ -111,3 +129,3 @@ }

}
} else if (_build.future.unstable_singleFetch && url.pathname.endsWith(".data")) {
} else if (_build.future.v3_singleFetch && url.pathname.endsWith(".data")) {
let handlerUrl = new URL(request.url);

@@ -124,3 +142,3 @@ handlerUrl.pathname = handlerUrl.pathname.replace(/\.data$/, "").replace(/^\/_root$/, "/");

if (isRedirectResponse(response)) {
let result = getSingleFetchRedirect(response.status, response.headers);
let result = getSingleFetchRedirect(response.status, response.headers, _build.basename);
if (request.method === "GET") {

@@ -132,5 +150,5 @@ result = {

let headers = new Headers(response.headers);
headers.set("Content-Type", "text/x-turbo");
headers.set("Content-Type", "text/x-script");
return new Response(encodeViaTurboStream(result, request.signal, _build.entry.module.streamTimeout, serverMode), {
status: 200,
status: SINGLE_FETCH_REDIRECT_STATUS,
headers

@@ -157,2 +175,24 @@ });

};
async function handleManifestRequest(build, routes, url) {
let patches = {};
if (url.searchParams.has("p")) {
for (let path of url.searchParams.getAll("p")) {
let matches = matchServerRoutes(routes, path, build.basename);
if (matches) {
for (let match of matches) {
let routeId = match.route.id;
patches[routeId] = build.assets.routes[routeId];
}
}
}
return json(patches, {
headers: {
"Cache-Control": "public, max-age=31536000, immutable"
}
}); // Override the TypedResponse stuff from json()
}
return new Response("Invalid Request", {
status: 400
});
}
async function handleDataRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {

@@ -182,8 +222,8 @@ try {

// network errors that are missing this header
response.headers.set("X-Remix-Response", "yes");
response = safelySetHeader(response, "X-Remix-Response", "yes");
return response;
} catch (error) {
if (isResponse(error)) {
error.headers.set("X-Remix-Catch", "yes");
return error;
let response = safelySetHeader(error, "X-Remix-Catch", "yes");
return response;
}

@@ -196,3 +236,3 @@ if (isRouteErrorResponse(error)) {

handleError(errorInstance);
return json(serializeError(errorInstance, serverMode), {
return json$1(serializeError(errorInstance, serverMode), {
status: 500,

@@ -210,3 +250,3 @@ headers: {

status
} = request.method !== "GET" ? await singleFetchAction(serverMode, staticHandler, request, handlerUrl, loadContext, handleError) : await singleFetchLoaders(serverMode, staticHandler, request, handlerUrl, loadContext, handleError);
} = request.method !== "GET" ? await singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) : await singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError);

@@ -217,4 +257,17 @@ // Mark all successful responses with a header so we can identify in-flight

resultHeaders.set("X-Remix-Response", "yes");
resultHeaders.set("Content-Type", "text/x-turbo");
// 304 responses should not have a body
if (status === 304) {
return new Response(null, {
status: 304,
headers: resultHeaders
});
}
// We use a less-descriptive `text/x-script` here instead of something like
// `text/x-turbo` to enable compression when deployed via Cloudflare. See:
// - https://github.com/remix-run/remix/issues/9884
// - https://developers.cloudflare.com/speed/optimization/content/brotli/content-compression/
resultHeaders.set("Content-Type", "text/x-script");
// Note: Deferred data is already just Promises, so we don't have to mess

@@ -229,7 +282,5 @@ // `activeDeferreds` or anything :)

let context;
let responseStubs = getResponseStubs();
try {
context = await staticHandler.query(request, {
requestContext: loadContext,
unstable_dataStrategy: build.future.unstable_singleFetch ? getSingleFetchDataStrategy(responseStubs) : undefined
requestContext: loadContext
});

@@ -245,17 +296,10 @@ } catch (error) {

}
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);
let headers = getDocumentHeaders(build, context);
// 304 responses should not have a body or a content-type
if (context.statusCode === 304) {
return new Response(null, {
status: 304,
headers
});
}

@@ -267,3 +311,3 @@

// @ts-expect-error `err.error` is "private" from users but intended for internal use
if ((!isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) {
if (!isRouteErrorResponse(err) || err.error) {
handleError(err);

@@ -289,3 +333,2 @@ }

serverHandoffString: createServerHandoffString({
url: context.location.pathname,
basename: build.basename,

@@ -295,7 +338,7 @@ criticalCss,

isSpaMode: build.isSpaMode,
...(!build.future.unstable_singleFetch ? {
...(!build.future.v3_singleFetch ? {
state
} : null)
}),
...(build.future.unstable_singleFetch ? {
...(build.future.v3_singleFetch ? {
serverHandoffStream: encodeViaTurboStream(state, request.signal, build.entry.module.streamTimeout, serverMode),

@@ -310,3 +353,3 @@ renderMeta: {}

try {
return await handleDocumentRequestFunction(request, statusCode, headers, entryContext, loadContext);
return await handleDocumentRequestFunction(request, context.statusCode, headers, entryContext, loadContext);
} catch (error) {

@@ -348,11 +391,10 @@ handleError(error);

serverHandoffString: createServerHandoffString({
url: context.location.pathname,
basename: build.basename,
future: build.future,
isSpaMode: build.isSpaMode,
...(!build.future.unstable_singleFetch ? {
...(!build.future.v3_singleFetch ? {
state
} : null)
}),
...(build.future.unstable_singleFetch ? {
...(build.future.v3_singleFetch ? {
serverHandoffStream: encodeViaTurboStream(state, request.signal, build.entry.module.streamTimeout, serverMode),

@@ -372,3 +414,2 @@ renderMeta: {}

try {
let responseStubs = build.future.unstable_singleFetch ? getResponseStubs() : {};
// Note we keep the routeId here to align with the Remix handling of

@@ -379,30 +420,10 @@ // resource routes which doesn't take ?index into account and just takes

routeId,
requestContext: loadContext,
...(build.future.unstable_singleFetch ? {
unstable_dataStrategy: getSingleFetchResourceRouteDataStrategy({
responseStubs
})
} : null)
requestContext: loadContext
});
if (typeof response === "object") {
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 {
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
});
}
if (build.future.v3_singleFetch && !isResponse(response)) {
console.warn(resourceRouteJsonWarning(request.method === "GET" ? "loader" : "action", routeId));
response = json(response);
}

@@ -418,4 +439,4 @@

// match identically to what Remix returns
error.headers.set("X-Remix-Catch", "yes");
return error;
let response = safelySetHeader(error, "X-Remix-Catch", "yes");
return response;
}

@@ -433,3 +454,3 @@ if (isRouteErrorResponse(error)) {

function errorResponseToJson(errorResponse, serverMode) {
return json(serializeError(
return json$1(serializeError(
// @ts-expect-error This is "private" from users but intended for internal use

@@ -482,2 +503,18 @@ errorResponse.error || new Error("Unexpected Server Error"), serverMode), {

// Anytime we are setting a header on a `Response` created in the loader/action,
// we have to so it in this manner since in an `undici` world, if the `Response`
// came directly from a `fetch` call, the headers are immutable will throw if
// we try to set a new header. This is a sort of shallow clone of the `Response`
// so we can safely set our own header.
function safelySetHeader(response, name, value) {
let headers = new Headers(response.headers);
headers.set(name, value);
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers,
duplex: response.body ? "half" : undefined
});
}
export { createRequestHandler };
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

*/
import { UNSAFE_ErrorResponseImpl, isRouteErrorResponse } from '@remix-run/router';
import { data as data$1, isRouteErrorResponse, stripBasename, UNSAFE_ErrorResponseImpl } from '@remix-run/router';
import { encode } from 'turbo-stream';
import { sanitizeError, sanitizeErrors } from './errors.js';
import { sanitizeErrors, sanitizeError } from './errors.js';
import { getDocumentHeaders } from './headers.js';
import { ServerMode } from './mode.js';
import { isResponse, isDeferredData, isRedirectStatusCode } from './responses.js';
import { isResponse, isRedirectStatusCode } from './responses.js';
const SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect");
const ResponseStubActionSymbol = Symbol("ResponseStubAction");
function getSingleFetchDataStrategy(responseStubs, {
// We can't use a 3xx status or else the `fetch()` would follow the redirect.
// We need to communicate the redirect back as data so we can act on it in the
// client side router. We use a 202 to avoid any automatic caching we might
// get from a 200 since a "temporary" redirect should not be cached. This lets
// the user control cache behavior via Cache-Control
const SINGLE_FETCH_REDIRECT_STATUS = 202;
function getSingleFetchDataStrategy({
isActionDataRequest,

@@ -30,63 +36,14 @@ loadRouteIds

if (isActionDataRequest && request.method === "GET") {
return await Promise.all(matches.map(m => m.resolve(async () => ({
type: "data",
result: null
}))));
return {};
}
let results = await Promise.all(matches.map(async match => {
let responseStub;
if (request.method !== "GET") {
responseStub = responseStubs[ResponseStubActionSymbol];
} else {
responseStub = responseStubs[match.route.id];
}
let result = await match.resolve(async handler => {
// Cast `ResponseStubImpl -> ResponseStub` to hide the symbol in userland
let ctx = {
response: responseStub
};
// Only run opt-in loaders when fine-grained revalidation is enabled
let data = loadRouteIds && !loadRouteIds.includes(match.route.id) ? null : await handler(ctx);
return {
type: "data",
result: data
};
});
// Transfer raw Response status/headers to responseStubs
if (isResponse(result.result)) {
proxyResponseToResponseStub(result.result.status, result.result.headers, responseStub);
} else if (isDeferredData(result.result) && result.result.init) {
proxyResponseToResponseStub(result.result.init.status, new Headers(result.result.init.headers), responseStub);
}
return result;
}));
return results;
// Only run opt-in loaders when fine-grained revalidation is enabled
let matchesToLoad = loadRouteIds ? matches.filter(m => loadRouteIds.includes(m.route.id)) : matches;
let results = await Promise.all(matchesToLoad.map(match => match.resolve()));
return results.reduce((acc, result, i) => Object.assign(acc, {
[matchesToLoad[i].route.id]: result
}), {});
};
}
function getSingleFetchResourceRouteDataStrategy({
responseStubs
}) {
return async ({
matches
}) => {
let results = await Promise.all(matches.map(async match => {
let responseStub = match.shouldLoad ? responseStubs[match.route.id] : null;
let result = await match.resolve(async handler => {
// Cast `ResponseStubImpl -> ResponseStub` to hide the symbol in userland
let ctx = {
response: responseStub
};
let data = await handler(ctx);
return {
type: "data",
result: data
};
});
return result;
}));
return results;
};
}
async function singleFetchAction(serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
async function singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
try {

@@ -102,7 +59,6 @@ let handlerRequest = new Request(handlerUrl, {

});
let responseStubs = getResponseStubs();
let result = await staticHandler.query(handlerRequest, {
requestContext: loadContext,
skipLoaderErrorBubbling: true,
unstable_dataStrategy: getSingleFetchDataStrategy(responseStubs, {
dataStrategy: getSingleFetchDataStrategy({
isActionDataRequest: true

@@ -116,20 +72,14 @@ })

return {
result: getSingleFetchRedirect(result.status, result.headers),
result: getSingleFetchRedirect(result.status, result.headers, build.basename),
headers: result.headers,
status: 200
status: SINGLE_FETCH_REDIRECT_STATUS
};
}
let context = result;
let singleFetchResult;
let {
statusCode,
headers
} = mergeResponseStubs(context, responseStubs, {
isActionDataRequest: true
});
if (isRedirectStatusCode(statusCode) && headers.has("Location")) {
let headers = getDocumentHeaders(build, context);
if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
return {
result: getSingleFetchRedirect(statusCode, headers),
result: getSingleFetchRedirect(context.statusCode, headers, build.basename),
headers,
status: 200 // Don't want the `fetch` call to follow the redirect
status: SINGLE_FETCH_REDIRECT_STATUS
};

@@ -142,3 +92,3 @@ }

// @ts-expect-error This is "private" from users but intended for internal use
if ((!isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) {
if (!isRouteErrorResponse(err) || err.error) {
handleError(err);

@@ -149,6 +99,6 @@ }

}
let singleFetchResult;
if (context.errors) {
let error = Object.values(context.errors)[0];
singleFetchResult = {
error: isResponseStub(error) ? null : error
error: Object.values(context.errors)[0]
};

@@ -163,3 +113,3 @@ } else {

headers,
status: statusCode
status: context.statusCode
};

@@ -178,3 +128,3 @@ } catch (error) {

}
async function singleFetchLoaders(serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
async function singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
try {

@@ -187,7 +137,6 @@ var _URL$searchParams$get;

let loadRouteIds = ((_URL$searchParams$get = new URL(request.url).searchParams.get("_routes")) === null || _URL$searchParams$get === void 0 ? void 0 : _URL$searchParams$get.split(",")) || undefined;
let responseStubs = getResponseStubs();
let result = await staticHandler.query(handlerRequest, {
requestContext: loadContext,
skipLoaderErrorBubbling: true,
unstable_dataStrategy: getSingleFetchDataStrategy(responseStubs, {
dataStrategy: getSingleFetchDataStrategy({
loadRouteIds

@@ -199,20 +148,17 @@ })

result: {
[SingleFetchRedirectSymbol]: getSingleFetchRedirect(result.status, result.headers)
[SingleFetchRedirectSymbol]: getSingleFetchRedirect(result.status, result.headers, build.basename)
},
headers: result.headers,
status: 200 // Don't want the `fetch` call to follow the redirect
status: SINGLE_FETCH_REDIRECT_STATUS
};
}
let context = result;
let {
statusCode,
headers
} = mergeResponseStubs(context, responseStubs);
if (isRedirectStatusCode(statusCode) && headers.has("Location")) {
let headers = getDocumentHeaders(build, context);
if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
return {
result: {
[SingleFetchRedirectSymbol]: getSingleFetchRedirect(statusCode, headers)
[SingleFetchRedirectSymbol]: getSingleFetchRedirect(context.statusCode, headers, build.basename)
},
headers,
status: 200 // Don't want the `fetch` call to follow the redirect
status: SINGLE_FETCH_REDIRECT_STATUS
};

@@ -225,3 +171,3 @@ }

// @ts-expect-error This is "private" from users but intended for internal use
if ((!isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) {
if (!isRouteErrorResponse(err) || err.error) {
handleError(err);

@@ -242,11 +188,5 @@ }

if (error !== undefined) {
if (isResponseStub(error)) {
results[m.route.id] = {
error: null
};
} else {
results[m.route.id] = {
error
};
}
results[m.route.id] = {
error
};
} else if (data !== undefined) {

@@ -261,3 +201,3 @@ results[m.route.id] = {

headers,
status: statusCode
status: context.statusCode
};

@@ -278,102 +218,9 @@ } catch (error) {

}
function isResponseStub(value) {
return value && typeof value === "object" && ResponseStubOperationsSymbol in value;
}
function getResponseStub(status) {
let headers = new Headers();
let operations = [];
let headersProxy = new Proxy(headers, {
get(target, prop, receiver) {
if (prop === "set" || prop === "append" || prop === "delete") {
return (name, value) => {
operations.push([prop, name, value]);
Reflect.apply(target[prop], target, [name, value]);
};
}
return Reflect.get(target, prop, receiver);
}
});
return {
status,
headers: headersProxy,
[ResponseStubOperationsSymbol]: operations
};
}
function getResponseStubs() {
return new Proxy({}, {
get(responseStubCache, prop) {
let cached = responseStubCache[prop];
if (!cached) {
responseStubCache[prop] = cached = getResponseStub();
}
return cached;
}
});
}
function proxyResponseToResponseStub(status, headers, responseStub) {
if (status != null && responseStub.status == null) {
responseStub.status = status;
function getSingleFetchRedirect(status, headers, basename) {
let redirect = headers.get("Location");
if (basename) {
redirect = stripBasename(redirect, basename) || redirect;
}
for (let [k, v] of headers) {
if (k.toLowerCase() !== "set-cookie") {
responseStub.headers.set(k, v);
}
}
// Unsure why this is complaining? It's fine in VSCode but fails with tsc...
// @ts-ignore - ignoring instead of expecting because otherwise build fails locally
for (let v of headers.getSetCookie()) {
responseStub.headers.append("Set-Cookie", v);
}
}
function mergeResponseStubs(context, responseStubs, {
isActionDataRequest
} = {}) {
let statusCode = undefined;
let headers = new Headers();
// Action followed by top-down loaders
let actionStub = responseStubs[ResponseStubActionSymbol];
let stubs = [actionStub];
// Nothing to merge at the route level on action data requests
if (!isActionDataRequest) {
stubs.push(...context.matches.map(m => responseStubs[m.route.id]));
}
for (let stub of stubs) {
// Take the highest error/redirect, or the lowest success value - preferring
// action 200's over loader 200s
if (
// first status found on the way down
statusCode === undefined && stub.status ||
// deeper 2xx status found while not overriding the action status
statusCode !== undefined && statusCode < 300 && stub.status && statusCode !== (actionStub === null || actionStub === void 0 ? void 0 : actionStub.status)) {
statusCode = stub.status;
}
// Replay headers operations in order
let ops = stub[ResponseStubOperationsSymbol];
for (let [op, ...args] of ops) {
// @ts-expect-error
headers[op](...args);
}
}
// If no response stubs set it, use whatever we got back from the router
// context which handles internal ErrorResponse cases like 404/405's where
// we may never run a loader/action
if (statusCode === undefined) {
statusCode = context.statusCode;
}
if (statusCode === undefined) {
statusCode = 200;
}
return {
statusCode,
headers
};
}
function getSingleFetchRedirect(status, headers) {
return {
redirect: headers.get("Location"),
redirect,
status,

@@ -389,3 +236,4 @@ revalidate:

headers.has("X-Remix-Revalidate") || headers.has("Set-Cookie"),
reload: headers.has("X-Remix-Reload-Document")
reload: headers.has("X-Remix-Reload-Document"),
replace: headers.has("X-Remix-Replace")
};

@@ -431,27 +279,17 @@ }

}
}]
}],
postPlugins: [value => {
if (!value) return;
if (typeof value !== "object") return;
return ["SingleFetchClassInstance", Object.fromEntries(Object.entries(value))];
}, () => ["SingleFetchFallback"]]
});
}
function data(value, init) {
return data$1(value, init);
}
// Backwards-compatible type for Remix v2 where json/defer still use the old types,
// and only non-json/defer returns use the new types. This allows for incremental
// migration of loaders to return naked objects. In the next major version,
// json/defer will be removed so everything will use the new simplified typings.
// prettier-ignore
// eslint-disable-next-line
const ResponseStubOperationsSymbol = Symbol("ResponseStubOperations");
/**
* A stubbed response to let you set the status/headers of your response from
* loader/action functions
*/
// loader
let defineLoader = loader => loader;
// action
let defineAction = action => action;
export { ResponseStubOperationsSymbol, SingleFetchRedirectSymbol, defineAction, defineLoader, encodeViaTurboStream, getResponseStubs, getSingleFetchDataStrategy, getSingleFetchRedirect, getSingleFetchResourceRouteDataStrategy, isResponseStub, mergeResponseStubs, singleFetchAction, singleFetchLoaders };
export { SINGLE_FETCH_REDIRECT_STATUS, SingleFetchRedirectSymbol, data, encodeViaTurboStream, getSingleFetchDataStrategy, getSingleFetchRedirect, singleFetchAction, singleFetchLoaders };
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

export { createCookieFactory, isCookie } from "./cookies";
export { composeUploadHandlers as unstable_composeUploadHandlers, parseMultipartFormData as unstable_parseMultipartFormData, } from "./formData";
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 { defer, json, redirect, redirectDocument, replace } from "./responses";
export { SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol, data, } from "./single-fetch";
export type { SingleFetchResult as UNSAFE_SingleFetchResult, SingleFetchResults as UNSAFE_SingleFetchResults, } from "./single-fetch";
export { createRequestHandler } from "./server";

@@ -14,2 +14,3 @@ export { createSession, createSessionStorageFactory, isSession, } from "./sessions";

export type { CreateCookieFunction, CreateCookieSessionStorageFunction, CreateMemorySessionStorageFunction, CreateRequestHandlerFunction, CreateSessionFunction, CreateSessionStorageFunction, IsCookieFunction, IsSessionFunction, JsonFunction, RedirectFunction, } from "./interface";
export type { Future } from "./future";
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-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

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

@@ -42,0 +42,0 @@ exports.createSession = sessions.createSession;

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

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

@@ -4,0 +5,0 @@ export type { MemoryUploadHandlerOptions, MemoryUploadHandlerFilterArgs, } from "./upload/memoryUploadHandler";

@@ -17,2 +17,7 @@ import { type UNSAFE_DeferredData as DeferredData } from "@remix-run/router";

*
* @deprecated This utility is deprecated in favor of opting into Single Fetch
* via `future.v3_singleFetch` and returning raw objects. This method will be
* removed in React Router v7. If you need to return a JSON Response, you can
* use `Response.json()`.
*
* @see https://remix.run/utils/json

@@ -24,2 +29,6 @@ */

*
* @deprecated This utility is deprecated in favor of opting into Single Fetch
* via `future.v3_singleFetch` and returning raw objects. This method will be
* removed in React Router v7.
*
* @see https://remix.run/utils/defer

@@ -37,2 +46,9 @@ */

/**
* A redirect response. Sets the status code and the `Location` header.
* Defaults to "302 Found".
*
* @see https://remix.run/utils/redirect
*/
export declare const replace: RedirectFunction;
/**
* A redirect response that will force a document reload to the new location.

@@ -39,0 +55,0 @@ * Sets the status code and the `Location` header.

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

*
* @deprecated This utility is deprecated in favor of opting into Single Fetch
* via `future.v3_singleFetch` and returning raw objects. This method will be
* removed in React Router v7. If you need to return a JSON Response, you can
* use `Response.json()`.
*
* @see https://remix.run/utils/json

@@ -35,2 +40,6 @@ */

*
* @deprecated This utility is deprecated in favor of opting into Single Fetch
* via `future.v3_singleFetch` and returning raw objects. This method will be
* removed in React Router v7.
*
* @see https://remix.run/utils/defer

@@ -52,2 +61,12 @@ */

/**
* A redirect response. Sets the status code and the `Location` header.
* Defaults to "302 Found".
*
* @see https://remix.run/utils/redirect
*/
const replace = (url, init = 302) => {
return router.replace(url, init);
};
/**
* A redirect response that will force a document reload to the new location.

@@ -139,1 +158,2 @@ * Sets the status code and the `Location` header.

exports.redirectDocument = redirectDocument;
exports.replace = replace;
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

@@ -5,3 +5,2 @@ import type { ActionFunction as RRActionFunction, ActionFunctionArgs as RRActionFunctionArgs, AgnosticRouteMatch, LoaderFunction as RRLoaderFunction, LoaderFunctionArgs as RRLoaderFunctionArgs, Location, Params } from "@remix-run/router";

import type { SerializeFrom } from "./serialize";
import type { ResponseStub } from "./single-fetch";
export interface RouteModules<RouteModule> {

@@ -25,3 +24,2 @@ [routeId: string]: RouteModule | undefined;

context: AppLoadContext;
response?: ResponseStub;
};

@@ -49,3 +47,2 @@ /**

context: AppLoadContext;
response?: ResponseStub;
};

@@ -52,0 +49,0 @@ /**

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

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

@@ -70,4 +69,3 @@ action: route.module.action ? (args, dataStrategyCtx) => data.callRouteAction({

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

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

import type { Jsonify } from "./jsonify";
import type { TypedDeferredData, TypedResponse } from "./responses";
import type { ClientActionFunctionArgs, ClientLoaderFunctionArgs } from "./routeModules";
import { type SerializeFrom as SingleFetch_SerializeFrom } from "./single-fetch";
import type { Future } from "./future";
type SingleFetchEnabled = Future extends {
v3_singleFetch: infer T extends boolean;
} ? T : false;
/**

@@ -11,4 +16,9 @@ * Infer JSON serialized data type returned by a loader or action, while

* `type LoaderData = SerializeFrom<typeof loader>`
*
* @deprecated SerializeFrom is deprecated and will be removed in React Router
* v7. Please use the generics on `useLoaderData`/etc. instead of manually
* deserializing in Remix v2. You can convert to the generated types once you
* migrate to React Router v7.
*/
export type SerializeFrom<T> = T extends (...args: any[]) => infer Output ? Parameters<T> extends [ClientLoaderFunctionArgs | ClientActionFunctionArgs] ? SerializeClient<Awaited<Output>> : Serialize<Awaited<Output>> : Jsonify<Awaited<T>>;
export type SerializeFrom<T> = SingleFetchEnabled extends true ? SingleFetch_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> ? {

@@ -15,0 +25,0 @@ [K in keyof U as K extends symbol ? never : Promise<any> extends U[K] ? K : never]: DeferValueClient<U[K]>;

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

let url = new URL(request.url);
let matches = routeMatching.matchServerRoutes(routes, url.pathname, _build.basename);
let params = matches && matches.length > 0 ? matches[0].params : {};
let params = {};
let handleError = error => {

@@ -95,5 +94,24 @@ if (mode$1 === mode.ServerMode.Development) {

};
// Manifest request for fog of war
let manifestUrl = `${_build.basename ?? "/"}/__manifest`.replace(/\/+/g, "/");
if (url.pathname === manifestUrl) {
try {
let res = await handleManifestRequest(_build, routes, url);
return res;
} catch (e) {
handleError(e);
return new Response("Unknown Server Error", {
status: 500
});
}
}
let matches = routeMatching.matchServerRoutes(routes, url.pathname, _build.basename);
if (matches && matches.length > 0) {
Object.assign(params, matches[0].params);
}
let response;
if (url.searchParams.has("_data")) {
if (_build.future.unstable_singleFetch) {
if (_build.future.v3_singleFetch) {
handleError(new Error("Warning: Single fetch-enabled apps should not be making ?_data requests, " + "this is likely to break in the future"));

@@ -113,3 +131,3 @@ }

}
} else if (_build.future.unstable_singleFetch && url.pathname.endsWith(".data")) {
} else if (_build.future.v3_singleFetch && url.pathname.endsWith(".data")) {
let handlerUrl = new URL(request.url);

@@ -126,3 +144,3 @@ handlerUrl.pathname = handlerUrl.pathname.replace(/\.data$/, "").replace(/^\/_root$/, "/");

if (responses.isRedirectResponse(response)) {
let result = singleFetch.getSingleFetchRedirect(response.status, response.headers);
let result = singleFetch.getSingleFetchRedirect(response.status, response.headers, _build.basename);
if (request.method === "GET") {

@@ -134,5 +152,5 @@ result = {

let headers = new Headers(response.headers);
headers.set("Content-Type", "text/x-turbo");
headers.set("Content-Type", "text/x-script");
return new Response(singleFetch.encodeViaTurboStream(result, request.signal, _build.entry.module.streamTimeout, serverMode), {
status: 200,
status: singleFetch.SINGLE_FETCH_REDIRECT_STATUS,
headers

@@ -159,2 +177,24 @@ });

};
async function handleManifestRequest(build, routes, url) {
let patches = {};
if (url.searchParams.has("p")) {
for (let path of url.searchParams.getAll("p")) {
let matches = routeMatching.matchServerRoutes(routes, path, build.basename);
if (matches) {
for (let match of matches) {
let routeId = match.route.id;
patches[routeId] = build.assets.routes[routeId];
}
}
}
return responses.json(patches, {
headers: {
"Cache-Control": "public, max-age=31536000, immutable"
}
}); // Override the TypedResponse stuff from json()
}
return new Response("Invalid Request", {
status: 400
});
}
async function handleDataRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {

@@ -184,8 +224,8 @@ try {

// network errors that are missing this header
response.headers.set("X-Remix-Response", "yes");
response = safelySetHeader(response, "X-Remix-Response", "yes");
return response;
} catch (error) {
if (responses.isResponse(error)) {
error.headers.set("X-Remix-Catch", "yes");
return error;
let response = safelySetHeader(error, "X-Remix-Catch", "yes");
return response;
}

@@ -211,3 +251,3 @@ if (router.isRouteErrorResponse(error)) {

status
} = request.method !== "GET" ? await singleFetch.singleFetchAction(serverMode, staticHandler, request, handlerUrl, loadContext, handleError) : await singleFetch.singleFetchLoaders(serverMode, staticHandler, request, handlerUrl, loadContext, handleError);
} = request.method !== "GET" ? await singleFetch.singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) : await singleFetch.singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError);

@@ -218,4 +258,17 @@ // Mark all successful responses with a header so we can identify in-flight

resultHeaders.set("X-Remix-Response", "yes");
resultHeaders.set("Content-Type", "text/x-turbo");
// 304 responses should not have a body
if (status === 304) {
return new Response(null, {
status: 304,
headers: resultHeaders
});
}
// We use a less-descriptive `text/x-script` here instead of something like
// `text/x-turbo` to enable compression when deployed via Cloudflare. See:
// - https://github.com/remix-run/remix/issues/9884
// - https://developers.cloudflare.com/speed/optimization/content/brotli/content-compression/
resultHeaders.set("Content-Type", "text/x-script");
// Note: Deferred data is already just Promises, so we don't have to mess

@@ -230,7 +283,5 @@ // `activeDeferreds` or anything :)

let context;
let responseStubs = singleFetch.getResponseStubs();
try {
context = await staticHandler.query(request, {
requestContext: loadContext,
unstable_dataStrategy: build.future.unstable_singleFetch ? singleFetch.getSingleFetchDataStrategy(responseStubs) : undefined
requestContext: loadContext
});

@@ -246,17 +297,10 @@ } catch (error) {

}
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);
let headers$1 = headers.getDocumentHeaders(build, context);
// 304 responses should not have a body or a content-type
if (context.statusCode === 304) {
return new Response(null, {
status: 304,
headers: headers$1
});
}

@@ -268,3 +312,3 @@

// @ts-expect-error `err.error` is "private" from users but intended for internal use
if ((!router.isRouteErrorResponse(err) || err.error) && !singleFetch.isResponseStub(err)) {
if (!router.isRouteErrorResponse(err) || err.error) {
handleError(err);

@@ -290,3 +334,2 @@ }

serverHandoffString: serverHandoff.createServerHandoffString({
url: context.location.pathname,
basename: build.basename,

@@ -296,7 +339,7 @@ criticalCss,

isSpaMode: build.isSpaMode,
...(!build.future.unstable_singleFetch ? {
...(!build.future.v3_singleFetch ? {
state
} : null)
}),
...(build.future.unstable_singleFetch ? {
...(build.future.v3_singleFetch ? {
serverHandoffStream: singleFetch.encodeViaTurboStream(state, request.signal, build.entry.module.streamTimeout, serverMode),

@@ -311,3 +354,3 @@ renderMeta: {}

try {
return await handleDocumentRequestFunction(request, statusCode, headers$1, entryContext, loadContext);
return await handleDocumentRequestFunction(request, context.statusCode, headers$1, entryContext, loadContext);
} catch (error) {

@@ -349,11 +392,10 @@ handleError(error);

serverHandoffString: serverHandoff.createServerHandoffString({
url: context.location.pathname,
basename: build.basename,
future: build.future,
isSpaMode: build.isSpaMode,
...(!build.future.unstable_singleFetch ? {
...(!build.future.v3_singleFetch ? {
state
} : null)
}),
...(build.future.unstable_singleFetch ? {
...(build.future.v3_singleFetch ? {
serverHandoffStream: singleFetch.encodeViaTurboStream(state, request.signal, build.entry.module.streamTimeout, serverMode),

@@ -373,3 +415,2 @@ renderMeta: {}

try {
let responseStubs = build.future.unstable_singleFetch ? singleFetch.getResponseStubs() : {};
// Note we keep the routeId here to align with the Remix handling of

@@ -380,30 +421,10 @@ // resource routes which doesn't take ?index into account and just takes

routeId,
requestContext: loadContext,
...(build.future.unstable_singleFetch ? {
unstable_dataStrategy: singleFetch.getSingleFetchResourceRouteDataStrategy({
responseStubs
})
} : null)
requestContext: loadContext
});
if (typeof response === "object") {
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 {
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
});
}
if (build.future.v3_singleFetch && !responses.isResponse(response)) {
console.warn(deprecations.resourceRouteJsonWarning(request.method === "GET" ? "loader" : "action", routeId));
response = responses.json(response);
}

@@ -419,4 +440,4 @@

// match identically to what Remix returns
error.headers.set("X-Remix-Catch", "yes");
return error;
let response = safelySetHeader(error, "X-Remix-Catch", "yes");
return response;
}

@@ -482,2 +503,18 @@ if (router.isRouteErrorResponse(error)) {

// Anytime we are setting a header on a `Response` created in the loader/action,
// we have to so it in this manner since in an `undici` world, if the `Response`
// came directly from a `fetch` call, the headers are immutable will throw if
// we try to set a new header. This is a sort of shallow clone of the `Response`
// so we can safely set our own header.
function safelySetHeader(response, name, value) {
let headers = new Headers(response.headers);
headers.set(name, value);
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers,
duplex: response.body ? "half" : undefined
});
}
exports.createRequestHandler = createRequestHandler;

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

criticalCss?: string;
url: string;
basename: string | undefined;

@@ -10,0 +9,0 @@ future: FutureConfig;

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

@@ -1,6 +0,8 @@

import type { ActionFunctionArgs as RRActionArgs, LoaderFunctionArgs as RRLoaderArgs, StaticHandler, unstable_DataStrategyFunction as DataStrategyFunction, StaticHandlerContext } from "@remix-run/router";
import type { StaticHandler, DataStrategyFunction, UNSAFE_DataWithResponseInit as DataWithResponseInit } from "@remix-run/router";
import type { ServerBuild } from "./build";
import type { AppLoadContext } from "./data";
import { ServerMode } from "./mode";
import type { TypedDeferredData, TypedResponse } from "./responses";
import type { SerializeFrom } from "./serialize";
import type { Jsonify } from "./jsonify";
import type { ClientActionFunctionArgs, ClientLoaderFunctionArgs } from "./routeModules";
export declare const SingleFetchRedirectSymbol: unique symbol;

@@ -12,2 +14,3 @@ type SingleFetchRedirectResult = {

reload: boolean;
replace: boolean;
};

@@ -23,13 +26,8 @@ export type SingleFetchResult = {

};
export type DataStrategyCtx = {
response: ResponseStub;
};
export declare function getSingleFetchDataStrategy(responseStubs: ReturnType<typeof getResponseStubs>, { isActionDataRequest, loadRouteIds, }?: {
export declare const SINGLE_FETCH_REDIRECT_STATUS = 202;
export declare function getSingleFetchDataStrategy({ isActionDataRequest, loadRouteIds, }?: {
isActionDataRequest?: boolean;
loadRouteIds?: string[];
}): DataStrategyFunction;
export declare function getSingleFetchResourceRouteDataStrategy({ responseStubs, }: {
responseStubs: ReturnType<typeof getResponseStubs>;
}): DataStrategyFunction;
export declare function singleFetchAction(serverMode: ServerMode, staticHandler: StaticHandler, request: Request, handlerUrl: URL, loadContext: AppLoadContext, handleError: (err: unknown) => void): Promise<{
export declare function singleFetchAction(build: ServerBuild, serverMode: ServerMode, staticHandler: StaticHandler, request: Request, handlerUrl: URL, loadContext: AppLoadContext, handleError: (err: unknown) => void): Promise<{
result: SingleFetchResult;

@@ -39,3 +37,3 @@ headers: Headers;

}>;
export declare function singleFetchLoaders(serverMode: ServerMode, staticHandler: StaticHandler, request: Request, handlerUrl: URL, loadContext: AppLoadContext, handleError: (err: unknown) => void): Promise<{
export declare function singleFetchLoaders(build: ServerBuild, serverMode: ServerMode, staticHandler: StaticHandler, request: Request, handlerUrl: URL, loadContext: AppLoadContext, handleError: (err: unknown) => void): Promise<{
result: SingleFetchResults;

@@ -45,47 +43,14 @@ headers: Headers;

}>;
export declare function isResponseStub(value: any): value is ResponseStubImpl;
export declare function getResponseStubs(): Record<string | symbol, ResponseStubImpl>;
export declare function mergeResponseStubs(context: StaticHandlerContext, responseStubs: ReturnType<typeof getResponseStubs>, { isActionDataRequest }?: {
isActionDataRequest?: boolean;
}): {
statusCode: number;
headers: Headers;
};
export declare function getSingleFetchRedirect(status: number, headers: Headers): SingleFetchRedirectResult;
export declare function getSingleFetchRedirect(status: number, headers: Headers, basename: string | undefined): SingleFetchRedirectResult;
export declare function encodeViaTurboStream(data: any, requestSignal: AbortSignal, streamTimeout: number | undefined, serverMode: ServerMode): ReadableStream<Uint8Array>;
type MaybePromise<T> = T | Promise<T>;
type Serializable = undefined | null | boolean | string | symbol | number | Array<Serializable> | {
export declare function data<T>(value: T, init?: number | ResponseInit): DataWithResponseInit<T>;
type Serializable = undefined | null | boolean | string | symbol | number | bigint | Date | URL | RegExp | Error | ReadonlyArray<Serializable> | Array<Serializable> | {
[key: PropertyKey]: Serializable;
} | bigint | Date | URL | RegExp | Error | Map<Serializable, Serializable> | Set<Serializable> | Promise<Serializable>;
type DataFunctionReturnValue = Serializable | TypedDeferredData<Record<string, unknown>> | TypedResponse<Record<string, unknown>>;
export type Serialize<T extends Loader | Action> = Awaited<ReturnType<T>> extends TypedDeferredData<infer D> ? D : Awaited<ReturnType<T>> extends TypedResponse<Record<string, unknown>> ? SerializeFrom<T> : Awaited<ReturnType<T>>;
export declare const ResponseStubOperationsSymbol: unique symbol;
export type ResponseStubOperation = [
"set" | "append" | "delete",
string,
string?
];
/**
* A stubbed response to let you set the status/headers of your response from
* loader/action functions
*/
export type ResponseStub = {
status: number | undefined;
headers: Headers;
};
export type ResponseStubImpl = ResponseStub & {
[ResponseStubOperationsSymbol]: ResponseStubOperation[];
};
type LoaderArgs = RRLoaderArgs<AppLoadContext> & {
context: AppLoadContext;
response: ResponseStub;
};
export type Loader = (args: LoaderArgs) => MaybePromise<DataFunctionReturnValue>;
export declare let defineLoader: <T extends Loader>(loader: T) => T;
type ActionArgs = RRActionArgs<AppLoadContext> & {
context: AppLoadContext;
response: ResponseStub;
};
export type Action = (args: ActionArgs) => MaybePromise<DataFunctionReturnValue>;
export declare let defineAction: <T extends Action>(action: T) => T;
} | Map<Serializable, Serializable> | Set<Serializable> | Promise<Serializable>;
type Serialize<T> = T extends void ? undefined : T extends Serializable ? T : T extends (...args: any[]) => unknown ? undefined : T extends Promise<infer U> ? Promise<Serialize<U>> : T extends Map<infer K, infer V> ? Map<Serialize<K>, Serialize<V>> : T extends Set<infer U> ? Set<Serialize<U>> : T extends [] ? [] : T extends readonly [infer F, ...infer R] ? [Serialize<F>, ...Serialize<R>] : T extends Array<infer U> ? Array<Serialize<U>> : T extends readonly unknown[] ? readonly Serialize<T[number]>[] : T extends Record<any, any> ? {
[K in keyof T]: Serialize<T[K]>;
} : undefined;
type ClientData<T> = T extends TypedResponse<infer U> ? Jsonify<U> : T extends TypedDeferredData<infer U> ? U : T;
type ServerData<T> = T extends TypedResponse<infer U> ? Jsonify<U> : T extends TypedDeferredData<infer U> ? Serialize<U> : T extends DataWithResponseInit<infer U> ? Serialize<U> : Serialize<T>;
export type SerializeFrom<T> = T extends (...args: infer Args) => infer Return ? Args extends [ClientLoaderFunctionArgs | ClientActionFunctionArgs] ? ClientData<Awaited<Return>> : ServerData<Awaited<Return>> : T;
export {};
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

var errors = require('./errors.js');
var headers = require('./headers.js');
var mode = require('./mode.js');

@@ -23,4 +24,9 @@ var responses = require('./responses.js');

const SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect");
const ResponseStubActionSymbol = Symbol("ResponseStubAction");
function getSingleFetchDataStrategy(responseStubs, {
// We can't use a 3xx status or else the `fetch()` would follow the redirect.
// We need to communicate the redirect back as data so we can act on it in the
// client side router. We use a 202 to avoid any automatic caching we might
// get from a 200 since a "temporary" redirect should not be cached. This lets
// the user control cache behavior via Cache-Control
const SINGLE_FETCH_REDIRECT_STATUS = 202;
function getSingleFetchDataStrategy({
isActionDataRequest,

@@ -35,63 +41,14 @@ loadRouteIds

if (isActionDataRequest && request.method === "GET") {
return await Promise.all(matches.map(m => m.resolve(async () => ({
type: "data",
result: null
}))));
return {};
}
let results = await Promise.all(matches.map(async match => {
let responseStub;
if (request.method !== "GET") {
responseStub = responseStubs[ResponseStubActionSymbol];
} else {
responseStub = responseStubs[match.route.id];
}
let result = await match.resolve(async handler => {
// Cast `ResponseStubImpl -> ResponseStub` to hide the symbol in userland
let ctx = {
response: responseStub
};
// Only run opt-in loaders when fine-grained revalidation is enabled
let data = loadRouteIds && !loadRouteIds.includes(match.route.id) ? null : await handler(ctx);
return {
type: "data",
result: data
};
});
// Transfer raw Response status/headers to responseStubs
if (responses.isResponse(result.result)) {
proxyResponseToResponseStub(result.result.status, result.result.headers, responseStub);
} else if (responses.isDeferredData(result.result) && result.result.init) {
proxyResponseToResponseStub(result.result.init.status, new Headers(result.result.init.headers), responseStub);
}
return result;
}));
return results;
// Only run opt-in loaders when fine-grained revalidation is enabled
let matchesToLoad = loadRouteIds ? matches.filter(m => loadRouteIds.includes(m.route.id)) : matches;
let results = await Promise.all(matchesToLoad.map(match => match.resolve()));
return results.reduce((acc, result, i) => Object.assign(acc, {
[matchesToLoad[i].route.id]: result
}), {});
};
}
function getSingleFetchResourceRouteDataStrategy({
responseStubs
}) {
return async ({
matches
}) => {
let results = await Promise.all(matches.map(async match => {
let responseStub = match.shouldLoad ? responseStubs[match.route.id] : null;
let result = await match.resolve(async handler => {
// Cast `ResponseStubImpl -> ResponseStub` to hide the symbol in userland
let ctx = {
response: responseStub
};
let data = await handler(ctx);
return {
type: "data",
result: data
};
});
return result;
}));
return results;
};
}
async function singleFetchAction(serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
async function singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
try {

@@ -107,7 +64,6 @@ let handlerRequest = new Request(handlerUrl, {

});
let responseStubs = getResponseStubs();
let result = await staticHandler.query(handlerRequest, {
requestContext: loadContext,
skipLoaderErrorBubbling: true,
unstable_dataStrategy: getSingleFetchDataStrategy(responseStubs, {
dataStrategy: getSingleFetchDataStrategy({
isActionDataRequest: true

@@ -121,20 +77,14 @@ })

return {
result: getSingleFetchRedirect(result.status, result.headers),
result: getSingleFetchRedirect(result.status, result.headers, build.basename),
headers: result.headers,
status: 200
status: SINGLE_FETCH_REDIRECT_STATUS
};
}
let context = result;
let singleFetchResult;
let {
statusCode,
headers
} = mergeResponseStubs(context, responseStubs, {
isActionDataRequest: true
});
if (responses.isRedirectStatusCode(statusCode) && headers.has("Location")) {
let headers$1 = headers.getDocumentHeaders(build, context);
if (responses.isRedirectStatusCode(context.statusCode) && headers$1.has("Location")) {
return {
result: getSingleFetchRedirect(statusCode, headers),
headers,
status: 200 // Don't want the `fetch` call to follow the redirect
result: getSingleFetchRedirect(context.statusCode, headers$1, build.basename),
headers: headers$1,
status: SINGLE_FETCH_REDIRECT_STATUS
};

@@ -147,3 +97,3 @@ }

// @ts-expect-error This is "private" from users but intended for internal use
if ((!router.isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) {
if (!router.isRouteErrorResponse(err) || err.error) {
handleError(err);

@@ -154,6 +104,6 @@ }

}
let singleFetchResult;
if (context.errors) {
let error = Object.values(context.errors)[0];
singleFetchResult = {
error: isResponseStub(error) ? null : error
error: Object.values(context.errors)[0]
};

@@ -167,4 +117,4 @@ } else {

result: singleFetchResult,
headers,
status: statusCode
headers: headers$1,
status: context.statusCode
};

@@ -183,3 +133,3 @@ } catch (error) {

}
async function singleFetchLoaders(serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
async function singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
try {

@@ -192,7 +142,6 @@ var _URL$searchParams$get;

let loadRouteIds = ((_URL$searchParams$get = new URL(request.url).searchParams.get("_routes")) === null || _URL$searchParams$get === void 0 ? void 0 : _URL$searchParams$get.split(",")) || undefined;
let responseStubs = getResponseStubs();
let result = await staticHandler.query(handlerRequest, {
requestContext: loadContext,
skipLoaderErrorBubbling: true,
unstable_dataStrategy: getSingleFetchDataStrategy(responseStubs, {
dataStrategy: getSingleFetchDataStrategy({
loadRouteIds

@@ -204,20 +153,17 @@ })

result: {
[SingleFetchRedirectSymbol]: getSingleFetchRedirect(result.status, result.headers)
[SingleFetchRedirectSymbol]: getSingleFetchRedirect(result.status, result.headers, build.basename)
},
headers: result.headers,
status: 200 // Don't want the `fetch` call to follow the redirect
status: SINGLE_FETCH_REDIRECT_STATUS
};
}
let context = result;
let {
statusCode,
headers
} = mergeResponseStubs(context, responseStubs);
if (responses.isRedirectStatusCode(statusCode) && headers.has("Location")) {
let headers$1 = headers.getDocumentHeaders(build, context);
if (responses.isRedirectStatusCode(context.statusCode) && headers$1.has("Location")) {
return {
result: {
[SingleFetchRedirectSymbol]: getSingleFetchRedirect(statusCode, headers)
[SingleFetchRedirectSymbol]: getSingleFetchRedirect(context.statusCode, headers$1, build.basename)
},
headers,
status: 200 // Don't want the `fetch` call to follow the redirect
headers: headers$1,
status: SINGLE_FETCH_REDIRECT_STATUS
};

@@ -230,3 +176,3 @@ }

// @ts-expect-error This is "private" from users but intended for internal use
if ((!router.isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) {
if (!router.isRouteErrorResponse(err) || err.error) {
handleError(err);

@@ -247,11 +193,5 @@ }

if (error !== undefined) {
if (isResponseStub(error)) {
results[m.route.id] = {
error: null
};
} else {
results[m.route.id] = {
error
};
}
results[m.route.id] = {
error
};
} else if (data !== undefined) {

@@ -265,4 +205,4 @@ results[m.route.id] = {

result: results,
headers,
status: statusCode
headers: headers$1,
status: context.statusCode
};

@@ -283,102 +223,9 @@ } catch (error) {

}
function isResponseStub(value) {
return value && typeof value === "object" && ResponseStubOperationsSymbol in value;
}
function getResponseStub(status) {
let headers = new Headers();
let operations = [];
let headersProxy = new Proxy(headers, {
get(target, prop, receiver) {
if (prop === "set" || prop === "append" || prop === "delete") {
return (name, value) => {
operations.push([prop, name, value]);
Reflect.apply(target[prop], target, [name, value]);
};
}
return Reflect.get(target, prop, receiver);
}
});
return {
status,
headers: headersProxy,
[ResponseStubOperationsSymbol]: operations
};
}
function getResponseStubs() {
return new Proxy({}, {
get(responseStubCache, prop) {
let cached = responseStubCache[prop];
if (!cached) {
responseStubCache[prop] = cached = getResponseStub();
}
return cached;
}
});
}
function proxyResponseToResponseStub(status, headers, responseStub) {
if (status != null && responseStub.status == null) {
responseStub.status = status;
function getSingleFetchRedirect(status, headers, basename) {
let redirect = headers.get("Location");
if (basename) {
redirect = router.stripBasename(redirect, basename) || redirect;
}
for (let [k, v] of headers) {
if (k.toLowerCase() !== "set-cookie") {
responseStub.headers.set(k, v);
}
}
// Unsure why this is complaining? It's fine in VSCode but fails with tsc...
// @ts-ignore - ignoring instead of expecting because otherwise build fails locally
for (let v of headers.getSetCookie()) {
responseStub.headers.append("Set-Cookie", v);
}
}
function mergeResponseStubs(context, responseStubs, {
isActionDataRequest
} = {}) {
let statusCode = undefined;
let headers = new Headers();
// Action followed by top-down loaders
let actionStub = responseStubs[ResponseStubActionSymbol];
let stubs = [actionStub];
// Nothing to merge at the route level on action data requests
if (!isActionDataRequest) {
stubs.push(...context.matches.map(m => responseStubs[m.route.id]));
}
for (let stub of stubs) {
// Take the highest error/redirect, or the lowest success value - preferring
// action 200's over loader 200s
if (
// first status found on the way down
statusCode === undefined && stub.status ||
// deeper 2xx status found while not overriding the action status
statusCode !== undefined && statusCode < 300 && stub.status && statusCode !== (actionStub === null || actionStub === void 0 ? void 0 : actionStub.status)) {
statusCode = stub.status;
}
// Replay headers operations in order
let ops = stub[ResponseStubOperationsSymbol];
for (let [op, ...args] of ops) {
// @ts-expect-error
headers[op](...args);
}
}
// If no response stubs set it, use whatever we got back from the router
// context which handles internal ErrorResponse cases like 404/405's where
// we may never run a loader/action
if (statusCode === undefined) {
statusCode = context.statusCode;
}
if (statusCode === undefined) {
statusCode = 200;
}
return {
statusCode,
headers
};
}
function getSingleFetchRedirect(status, headers) {
return {
redirect: headers.get("Location"),
redirect,
status,

@@ -394,3 +241,4 @@ revalidate:

headers.has("X-Remix-Revalidate") || headers.has("Set-Cookie"),
reload: headers.has("X-Remix-Reload-Document")
reload: headers.has("X-Remix-Reload-Document"),
replace: headers.has("X-Remix-Replace")
};

@@ -436,39 +284,24 @@ }

}
}]
}],
postPlugins: [value => {
if (!value) return;
if (typeof value !== "object") return;
return ["SingleFetchClassInstance", Object.fromEntries(Object.entries(value))];
}, () => ["SingleFetchFallback"]]
});
}
function data(value, init) {
return router.data(value, init);
}
// Backwards-compatible type for Remix v2 where json/defer still use the old types,
// and only non-json/defer returns use the new types. This allows for incremental
// migration of loaders to return naked objects. In the next major version,
// json/defer will be removed so everything will use the new simplified typings.
// prettier-ignore
// eslint-disable-next-line
const ResponseStubOperationsSymbol = Symbol("ResponseStubOperations");
/**
* A stubbed response to let you set the status/headers of your response from
* loader/action functions
*/
// loader
let defineLoader = loader => loader;
// action
let defineAction = action => action;
exports.ResponseStubOperationsSymbol = ResponseStubOperationsSymbol;
exports.SINGLE_FETCH_REDIRECT_STATUS = SINGLE_FETCH_REDIRECT_STATUS;
exports.SingleFetchRedirectSymbol = SingleFetchRedirectSymbol;
exports.defineAction = defineAction;
exports.defineLoader = defineLoader;
exports.data = data;
exports.encodeViaTurboStream = encodeViaTurboStream;
exports.getResponseStubs = getResponseStubs;
exports.getSingleFetchDataStrategy = getSingleFetchDataStrategy;
exports.getSingleFetchRedirect = getSingleFetchRedirect;
exports.getSingleFetchResourceRouteDataStrategy = getSingleFetchResourceRouteDataStrategy;
exports.isResponseStub = isResponseStub;
exports.mergeResponseStubs = mergeResponseStubs;
exports.singleFetchAction = singleFetchAction;
exports.singleFetchLoaders = singleFetchLoaders;
/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

/**
* @remix-run/server-runtime v0.0.0-nightly-430d4b5f8-20240521
* @remix-run/server-runtime v0.0.0-nightly-435cbd1da-20241118
*

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

{
"name": "@remix-run/server-runtime",
"version": "0.0.0-nightly-430d4b5f8-20240521",
"version": "0.0.0-nightly-435cbd1da-20241118",
"description": "Server runtime for Remix",

@@ -19,3 +19,3 @@ "bugs": {

"dependencies": {
"@remix-run/router": "1.16.1",
"@remix-run/router": "1.21.0",
"@types/cookie": "^0.6.0",

@@ -26,3 +26,3 @@ "@web3-storage/multipart-parser": "^1.0.0",

"source-map": "^0.7.3",
"turbo-stream": "^2.0.0"
"turbo-stream": "2.4.0"
},

@@ -29,0 +29,0 @@ "devDependencies": {

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