UNPKG

react-router

Version:
180 lines (179 loc) • 6.04 kB
/** * react-router v8.0.0 * * 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 */ import "../../lib/router/utils.js"; import { Deferred, createLineSplittingTransform } from "./utils.js"; import { flatten } from "./flatten.js"; import { unflatten } from "./unflatten.js"; //#region vendor/turbo-stream-v2/turbo-stream.ts async function decode(readable, options) { const { plugins } = options ?? {}; const done = new Deferred(); const reader = readable.pipeThrough(createLineSplittingTransform()).getReader(); const decoder = { values: [], hydrated: [], deferred: {}, plugins }; const decoded = await decodeInitial.call(decoder, reader); let donePromise = done.promise; if (decoded.done) done.resolve(); else donePromise = decodeDeferred.call(decoder, reader).then(done.resolve).catch((reason) => { for (const deferred of Object.values(decoder.deferred)) deferred.reject(reason); done.reject(reason); }); return { done: donePromise.then(() => reader.closed), value: decoded.value }; } async function decodeInitial(reader) { const read = await reader.read(); if (!read.value) throw new SyntaxError(); let line; try { line = JSON.parse(read.value); } catch (reason) { throw new SyntaxError(); } return { done: read.done, value: unflatten.call(this, line) }; } async function decodeDeferred(reader) { let read = await reader.read(); while (!read.done) { if (!read.value) continue; const line = read.value; switch (line[0]) { case "P": { const colonIndex = line.indexOf(":"); const deferredId = Number(line.slice(1, colonIndex)); const deferred = this.deferred[deferredId]; if (!deferred) throw new Error(`Deferred ID ${deferredId} not found in stream`); const lineData = line.slice(colonIndex + 1); let jsonLine; try { jsonLine = JSON.parse(lineData); } catch (reason) { throw new SyntaxError(); } const value = unflatten.call(this, jsonLine); deferred.resolve(value); break; } case "E": { const colonIndex = line.indexOf(":"); const deferredId = Number(line.slice(1, colonIndex)); const deferred = this.deferred[deferredId]; if (!deferred) throw new Error(`Deferred ID ${deferredId} not found in stream`); const lineData = line.slice(colonIndex + 1); let jsonLine; try { jsonLine = JSON.parse(lineData); } catch (reason) { throw new SyntaxError(); } const value = unflatten.call(this, jsonLine); deferred.reject(value); break; } default: throw new SyntaxError(); } read = await reader.read(); } } function encode(input, options) { const { onComplete, plugins, postPlugins, signal } = options ?? {}; const encoder = { deferred: {}, index: 0, indices: /* @__PURE__ */ new Map(), stringified: [], plugins, postPlugins, signal }; const textEncoder = new TextEncoder(); let lastSentIndex = 0; return new ReadableStream({ async start(controller) { const id = await flatten.call(encoder, input); if (Array.isArray(id)) throw new Error("This should never happen"); if (id < 0) controller.enqueue(textEncoder.encode(`${id}\n`)); else { controller.enqueue(textEncoder.encode(`[${encoder.stringified.join(",")}]\n`)); lastSentIndex = encoder.stringified.length - 1; } const seenPromises = /* @__PURE__ */ new WeakSet(); let processingChain = Promise.resolve(); if (Object.keys(encoder.deferred).length) { let raceDone; const racePromise = new Promise((resolve, reject) => { raceDone = resolve; if (signal) { const rejectPromise = () => reject(signal.reason || /* @__PURE__ */ new Error("Signal was aborted.")); if (signal.aborted) rejectPromise(); else signal.addEventListener("abort", (event) => { rejectPromise(); }); } }); while (Object.keys(encoder.deferred).length > 0) { for (const [deferredId, deferred] of Object.entries(encoder.deferred)) { if (seenPromises.has(deferred)) continue; seenPromises.add(encoder.deferred[Number(deferredId)] = Promise.race([racePromise, deferred]).then((resolved) => { processingChain = processingChain.then(async () => { const id = await flatten.call(encoder, resolved); if (Array.isArray(id)) { controller.enqueue(textEncoder.encode(`P${deferredId}:[["Z",${id[0]}]]\n`)); encoder.index++; lastSentIndex++; } else if (id < 0) controller.enqueue(textEncoder.encode(`P${deferredId}:${id}\n`)); else { const values = encoder.stringified.slice(lastSentIndex + 1).join(","); controller.enqueue(textEncoder.encode(`P${deferredId}:[${values}]\n`)); lastSentIndex = encoder.stringified.length - 1; } }); return processingChain; }, (reason) => { processingChain = processingChain.then(async () => { if (!reason || typeof reason !== "object" || !(reason instanceof Error)) reason = /* @__PURE__ */ new Error("An unknown error occurred"); const id = await flatten.call(encoder, reason); if (Array.isArray(id)) { controller.enqueue(textEncoder.encode(`E${deferredId}:[["Z",${id[0]}]]\n`)); encoder.index++; lastSentIndex++; } else if (id < 0) controller.enqueue(textEncoder.encode(`E${deferredId}:${id}\n`)); else { const values = encoder.stringified.slice(lastSentIndex + 1).join(","); controller.enqueue(textEncoder.encode(`E${deferredId}:[${values}]\n`)); lastSentIndex = encoder.stringified.length - 1; } }); return processingChain; }).finally(() => { delete encoder.deferred[Number(deferredId)]; })); } await Promise.race(Object.values(encoder.deferred)); } raceDone(); } await Promise.all(Object.values(encoder.deferred)); await processingChain; controller.close(); onComplete?.(); } }); } //#endregion export { decode, encode };