UNPKG

@remix-run/server-runtime

Version:
161 lines (150 loc) 5.62 kB
/** * @remix-run/server-runtime v2.16.8 * * Copyright (c) Remix Software Inc. * * This source code is licensed under the MIT license found in the * LICENSE.md file in the root directory of this source tree. * * @license MIT */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var router = require('@remix-run/router'); var errors = require('./errors.js'); // must be a type since this is a subtype of response // interfaces must conform to the types they extend /** * This is a shortcut for creating `application/json` responses. Converts `data` * to JSON and sets the `Content-Type` header. * * @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 custom headers or status code, you can use the new `data` * utility (https://remix.run/docs/en/main/utils/data). * * If you need to return a JSON Response from a resource route, you can use * `Response.json` (https://developer.mozilla.org/en-US/docs/Web/API/Response/json_static). * * @see https://remix.run/utils/json */ const json = (data, init = {}) => { return router.json(data, init); }; /** * This is a shortcut for creating Remix deferred responses * * @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 */ const defer = (data, init = {}) => { return router.defer(data, init); }; /** * A redirect response. Sets the status code and the `Location` header. * Defaults to "302 Found". * * @see https://remix.run/utils/redirect */ const redirect = (url, init = 302) => { return router.redirect(url, init); }; /** * 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. * 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) { let deferred = value; return deferred && typeof deferred === "object" && typeof deferred.data === "object" && typeof deferred.subscribe === "function" && typeof deferred.cancel === "function" && typeof deferred.resolveData === "function"; } function isResponse(value) { return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined"; } const redirectStatusCodes = new Set([301, 302, 303, 307, 308]); function isRedirectStatusCode(statusCode) { return redirectStatusCodes.has(statusCode); } function isRedirectResponse(response) { return isRedirectStatusCode(response.status); } function isTrackedPromise(value) { return value != null && typeof value.then === "function" && value._tracked === true; } // TODO: Figure out why ReadableStream types are borked sooooooo badly // in this file. Probably related to our TS configurations and configs // bleeding into each other. const DEFERRED_VALUE_PLACEHOLDER_PREFIX = "__deferred_promise:"; function createDeferredReadableStream(deferredData, signal, serverMode) { let encoder = new TextEncoder(); let stream = new ReadableStream({ async start(controller) { let criticalData = {}; let preresolvedKeys = []; for (let [key, value] of Object.entries(deferredData.data)) { if (isTrackedPromise(value)) { criticalData[key] = `${DEFERRED_VALUE_PLACEHOLDER_PREFIX}${key}`; if (typeof value._data !== "undefined" || typeof value._error !== "undefined") { preresolvedKeys.push(key); } } else { criticalData[key] = value; } } // Send the critical data controller.enqueue(encoder.encode(JSON.stringify(criticalData) + "\n\n")); for (let preresolvedKey of preresolvedKeys) { enqueueTrackedPromise(controller, encoder, preresolvedKey, deferredData.data[preresolvedKey], serverMode); } let unsubscribe = deferredData.subscribe((aborted, settledKey) => { if (settledKey) { enqueueTrackedPromise(controller, encoder, settledKey, deferredData.data[settledKey], serverMode); } }); await deferredData.resolveData(signal); unsubscribe(); controller.close(); } }); return stream; } function enqueueTrackedPromise(controller, encoder, settledKey, promise, serverMode) { if ("_error" in promise) { controller.enqueue(encoder.encode("error:" + JSON.stringify({ [settledKey]: promise._error instanceof Error ? errors.serializeError(promise._error, serverMode) : promise._error }) + "\n\n")); } else { controller.enqueue(encoder.encode("data:" + JSON.stringify({ [settledKey]: promise._data ?? null }) + "\n\n")); } } exports.createDeferredReadableStream = createDeferredReadableStream; exports.defer = defer; exports.isDeferredData = isDeferredData; exports.isRedirectResponse = isRedirectResponse; exports.isRedirectStatusCode = isRedirectStatusCode; exports.isResponse = isResponse; exports.json = json; exports.redirect = redirect; exports.redirectDocument = redirectDocument; exports.replace = replace;