tasks_manager/frontend/node_modules/turbo-stream/dist/turbo-stream.mjs

674 lines
20 KiB
JavaScript

// src/utils.ts
var HOLE = -1;
var NAN = -2;
var NEGATIVE_INFINITY = -3;
var NEGATIVE_ZERO = -4;
var NULL = -5;
var POSITIVE_INFINITY = -6;
var UNDEFINED = -7;
var TYPE_BIGINT = "B";
var TYPE_DATE = "D";
var TYPE_ERROR = "E";
var TYPE_MAP = "M";
var TYPE_NULL_OBJECT = "N";
var TYPE_PROMISE = "P";
var TYPE_REGEXP = "R";
var TYPE_SET = "S";
var TYPE_SYMBOL = "Y";
var TYPE_URL = "U";
var TYPE_PREVIOUS_RESOLVED = "Z";
var Deferred = class {
promise;
resolve;
reject;
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
};
function createLineSplittingTransform() {
const decoder = new TextDecoder();
let leftover = "";
return new TransformStream({
transform(chunk, controller) {
const str = decoder.decode(chunk, { stream: true });
const parts = (leftover + str).split("\n");
leftover = parts.pop() || "";
for (const part of parts) {
controller.enqueue(part);
}
},
flush(controller) {
if (leftover) {
controller.enqueue(leftover);
}
}
});
}
// src/flatten.ts
function flatten(input) {
const { indices } = this;
const existing = indices.get(input);
if (existing)
return [existing];
if (input === void 0)
return UNDEFINED;
if (input === null)
return NULL;
if (Number.isNaN(input))
return NAN;
if (input === Number.POSITIVE_INFINITY)
return POSITIVE_INFINITY;
if (input === Number.NEGATIVE_INFINITY)
return NEGATIVE_INFINITY;
if (input === 0 && 1 / input < 0)
return NEGATIVE_ZERO;
const index = this.index++;
indices.set(input, index);
stringify.call(this, input, index);
return index;
}
function stringify(input, index) {
const { deferred, plugins, postPlugins } = this;
const str = this.stringified;
const stack = [[input, index]];
while (stack.length > 0) {
const [input2, index2] = stack.pop();
const partsForObj = (obj) => Object.keys(obj).map((k) => `"_${flatten.call(this, k)}":${flatten.call(this, obj[k])}`).join(",");
let error = null;
switch (typeof input2) {
case "boolean":
case "number":
case "string":
str[index2] = JSON.stringify(input2);
break;
case "bigint":
str[index2] = `["${TYPE_BIGINT}","${input2}"]`;
break;
case "symbol": {
const keyFor = Symbol.keyFor(input2);
if (!keyFor) {
error = new Error(
"Cannot encode symbol unless created with Symbol.for()"
);
} else {
str[index2] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
}
break;
}
case "object": {
if (!input2) {
str[index2] = `${NULL}`;
break;
}
const isArray = Array.isArray(input2);
let pluginHandled = false;
if (!isArray && plugins) {
for (const plugin of plugins) {
const pluginResult = plugin(input2);
if (Array.isArray(pluginResult)) {
pluginHandled = true;
const [pluginIdentifier, ...rest] = pluginResult;
str[index2] = `[${JSON.stringify(pluginIdentifier)}`;
if (rest.length > 0) {
str[index2] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
}
str[index2] += "]";
break;
}
}
}
if (!pluginHandled) {
let result = isArray ? "[" : "{";
if (isArray) {
for (let i = 0; i < input2.length; i++)
result += (i ? "," : "") + (i in input2 ? flatten.call(this, input2[i]) : HOLE);
str[index2] = `${result}]`;
} else if (input2 instanceof Date) {
str[index2] = `["${TYPE_DATE}",${input2.getTime()}]`;
} else if (input2 instanceof URL) {
str[index2] = `["${TYPE_URL}",${JSON.stringify(input2.href)}]`;
} else if (input2 instanceof RegExp) {
str[index2] = `["${TYPE_REGEXP}",${JSON.stringify(
input2.source
)},${JSON.stringify(input2.flags)}]`;
} else if (input2 instanceof Set) {
if (input2.size > 0) {
str[index2] = `["${TYPE_SET}",${[...input2].map((val) => flatten.call(this, val)).join(",")}]`;
} else {
str[index2] = `["${TYPE_SET}"]`;
}
} else if (input2 instanceof Map) {
if (input2.size > 0) {
str[index2] = `["${TYPE_MAP}",${[...input2].flatMap(([k, v]) => [
flatten.call(this, k),
flatten.call(this, v)
]).join(",")}]`;
} else {
str[index2] = `["${TYPE_MAP}"]`;
}
} else if (input2 instanceof Promise) {
str[index2] = `["${TYPE_PROMISE}",${index2}]`;
deferred[index2] = input2;
} else if (input2 instanceof Error) {
str[index2] = `["${TYPE_ERROR}",${JSON.stringify(input2.message)}`;
if (input2.name !== "Error") {
str[index2] += `,${JSON.stringify(input2.name)}`;
}
str[index2] += "]";
} else if (Object.getPrototypeOf(input2) === null) {
str[index2] = `["${TYPE_NULL_OBJECT}",{${partsForObj(input2)}}]`;
} else if (isPlainObject(input2)) {
str[index2] = `{${partsForObj(input2)}}`;
} else {
error = new Error("Cannot encode object with prototype");
}
}
break;
}
default: {
const isArray = Array.isArray(input2);
let pluginHandled = false;
if (!isArray && plugins) {
for (const plugin of plugins) {
const pluginResult = plugin(input2);
if (Array.isArray(pluginResult)) {
pluginHandled = true;
const [pluginIdentifier, ...rest] = pluginResult;
str[index2] = `[${JSON.stringify(pluginIdentifier)}`;
if (rest.length > 0) {
str[index2] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
}
str[index2] += "]";
break;
}
}
}
if (!pluginHandled) {
error = new Error("Cannot encode function or unexpected type");
}
}
}
if (error) {
let pluginHandled = false;
if (postPlugins) {
for (const plugin of postPlugins) {
const pluginResult = plugin(input2);
if (Array.isArray(pluginResult)) {
pluginHandled = true;
const [pluginIdentifier, ...rest] = pluginResult;
str[index2] = `[${JSON.stringify(pluginIdentifier)}`;
if (rest.length > 0) {
str[index2] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
}
str[index2] += "]";
break;
}
}
}
if (!pluginHandled) {
throw error;
}
}
}
}
var objectProtoNames = Object.getOwnPropertyNames(Object.prototype).sort().join("\0");
function isPlainObject(thing) {
const proto = Object.getPrototypeOf(thing);
return proto === Object.prototype || proto === null || Object.getOwnPropertyNames(proto).sort().join("\0") === objectProtoNames;
}
// src/unflatten.ts
var globalObj = typeof window !== "undefined" ? window : typeof globalThis !== "undefined" ? globalThis : void 0;
function unflatten(parsed) {
const { hydrated, values } = this;
if (typeof parsed === "number")
return hydrate.call(this, parsed);
if (!Array.isArray(parsed) || !parsed.length)
throw new SyntaxError();
const startIndex = values.length;
for (const value of parsed) {
values.push(value);
}
hydrated.length = values.length;
return hydrate.call(this, startIndex);
}
function hydrate(index) {
const { hydrated, values, deferred, plugins } = this;
let result;
const stack = [
[
index,
(v) => {
result = v;
}
]
];
let postRun = [];
while (stack.length > 0) {
const [index2, set] = stack.pop();
switch (index2) {
case UNDEFINED:
set(void 0);
continue;
case NULL:
set(null);
continue;
case NAN:
set(NaN);
continue;
case POSITIVE_INFINITY:
set(Infinity);
continue;
case NEGATIVE_INFINITY:
set(-Infinity);
continue;
case NEGATIVE_ZERO:
set(-0);
continue;
}
if (hydrated[index2]) {
set(hydrated[index2]);
continue;
}
const value = values[index2];
if (!value || typeof value !== "object") {
hydrated[index2] = value;
set(value);
continue;
}
if (Array.isArray(value)) {
if (typeof value[0] === "string") {
const [type, b, c] = value;
switch (type) {
case TYPE_DATE:
set(hydrated[index2] = new Date(b));
continue;
case TYPE_URL:
set(hydrated[index2] = new URL(b));
continue;
case TYPE_BIGINT:
set(hydrated[index2] = BigInt(b));
continue;
case TYPE_REGEXP:
set(hydrated[index2] = new RegExp(b, c));
continue;
case TYPE_SYMBOL:
set(hydrated[index2] = Symbol.for(b));
continue;
case TYPE_SET:
const newSet = /* @__PURE__ */ new Set();
hydrated[index2] = newSet;
for (let i = 1; i < value.length; i++)
stack.push([
value[i],
(v) => {
newSet.add(v);
}
]);
set(newSet);
continue;
case TYPE_MAP:
const map = /* @__PURE__ */ new Map();
hydrated[index2] = map;
for (let i = 1; i < value.length; i += 2) {
const r = [];
stack.push([
value[i + 1],
(v) => {
r[1] = v;
}
]);
stack.push([
value[i],
(k) => {
r[0] = k;
}
]);
postRun.push(() => {
map.set(r[0], r[1]);
});
}
set(map);
continue;
case TYPE_NULL_OBJECT:
const obj = /* @__PURE__ */ Object.create(null);
hydrated[index2] = obj;
for (const key of Object.keys(b).reverse()) {
const r = [];
stack.push([
b[key],
(v) => {
r[1] = v;
}
]);
stack.push([
Number(key.slice(1)),
(k) => {
r[0] = k;
}
]);
postRun.push(() => {
obj[r[0]] = r[1];
});
}
set(obj);
continue;
case TYPE_PROMISE:
if (hydrated[b]) {
set(hydrated[index2] = hydrated[b]);
} else {
const d = new Deferred();
deferred[b] = d;
set(hydrated[index2] = d.promise);
}
continue;
case TYPE_ERROR:
const [, message, errorType] = value;
let error = errorType && globalObj && globalObj[errorType] ? new globalObj[errorType](message) : new Error(message);
hydrated[index2] = error;
set(error);
continue;
case TYPE_PREVIOUS_RESOLVED:
set(hydrated[index2] = hydrated[b]);
continue;
default:
if (Array.isArray(plugins)) {
const r = [];
const vals = value.slice(1);
for (let i = 0; i < vals.length; i++) {
const v = vals[i];
stack.push([
v,
(v2) => {
r[i] = v2;
}
]);
}
postRun.push(() => {
for (const plugin of plugins) {
const result2 = plugin(value[0], ...r);
if (result2) {
set(hydrated[index2] = result2.value);
return;
}
}
throw new SyntaxError();
});
continue;
}
throw new SyntaxError();
}
} else {
const array = [];
hydrated[index2] = array;
for (let i = 0; i < value.length; i++) {
const n = value[i];
if (n !== HOLE) {
stack.push([
n,
(v) => {
array[i] = v;
}
]);
}
}
set(array);
continue;
}
} else {
const object = {};
hydrated[index2] = object;
for (const key of Object.keys(value).reverse()) {
const r = [];
stack.push([
value[key],
(v) => {
r[1] = v;
}
]);
stack.push([
Number(key.slice(1)),
(k) => {
r[0] = k;
}
]);
postRun.push(() => {
object[r[0]] = r[1];
});
}
set(object);
continue;
}
}
while (postRun.length > 0) {
postRun.pop()();
}
return result;
}
// src/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 TYPE_PROMISE: {
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 TYPE_ERROR: {
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 { plugins, postPlugins, signal } = options ?? {};
const encoder = {
deferred: {},
index: 0,
indices: /* @__PURE__ */ new Map(),
stringified: [],
plugins,
postPlugins,
signal
};
const textEncoder = new TextEncoder();
let lastSentIndex = 0;
const readable = new ReadableStream({
async start(controller) {
const id = flatten.call(encoder, input);
if (Array.isArray(id)) {
throw new Error("This should never happen");
}
if (id < 0) {
controller.enqueue(textEncoder.encode(`${id}
`));
} else {
controller.enqueue(
textEncoder.encode(`[${encoder.stringified.join(",")}]
`)
);
lastSentIndex = encoder.stringified.length - 1;
}
const seenPromises = /* @__PURE__ */ new WeakSet();
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)] = raceSignal(
deferred,
encoder.signal
).then(
(resolved) => {
const id2 = flatten.call(encoder, resolved);
if (Array.isArray(id2)) {
controller.enqueue(
textEncoder.encode(
`${TYPE_PROMISE}${deferredId}:[["${TYPE_PREVIOUS_RESOLVED}",${id2[0]}]]
`
)
);
encoder.index++;
lastSentIndex++;
} else if (id2 < 0) {
controller.enqueue(
textEncoder.encode(`${TYPE_PROMISE}${deferredId}:${id2}
`)
);
} else {
const values = encoder.stringified.slice(lastSentIndex + 1).join(",");
controller.enqueue(
textEncoder.encode(
`${TYPE_PROMISE}${deferredId}:[${values}]
`
)
);
lastSentIndex = encoder.stringified.length - 1;
}
},
(reason) => {
if (!reason || typeof reason !== "object" || !(reason instanceof Error)) {
reason = new Error("An unknown error occurred");
}
const id2 = flatten.call(encoder, reason);
if (Array.isArray(id2)) {
controller.enqueue(
textEncoder.encode(
`${TYPE_ERROR}${deferredId}:[["${TYPE_PREVIOUS_RESOLVED}",${id2[0]}]]
`
)
);
encoder.index++;
lastSentIndex++;
} else if (id2 < 0) {
controller.enqueue(
textEncoder.encode(`${TYPE_ERROR}${deferredId}:${id2}
`)
);
} else {
const values = encoder.stringified.slice(lastSentIndex + 1).join(",");
controller.enqueue(
textEncoder.encode(
`${TYPE_ERROR}${deferredId}:[${values}]
`
)
);
lastSentIndex = encoder.stringified.length - 1;
}
}
).finally(() => {
delete encoder.deferred[Number(deferredId)];
})
);
}
await Promise.race(Object.values(encoder.deferred));
}
await Promise.all(Object.values(encoder.deferred));
controller.close();
}
});
return readable;
}
function raceSignal(promise, signal) {
if (!signal)
return promise;
if (signal.aborted)
return Promise.reject(signal.reason || new Error("Signal was aborted."));
const abort = new Promise((resolve, reject) => {
signal.addEventListener("abort", (event) => {
reject(signal.reason || new Error("Signal was aborted."));
});
promise.then(resolve).catch(reject);
});
abort.catch(() => {
});
return Promise.race([abort, promise]);
}
export {
decode,
encode
};