FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

17
node_modules/@solidjs/router/dist/data/action.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import { JSX } from "solid-js";
import type { Submission, SubmissionStub, NarrowResponse } from "../types.js";
export type Action<T extends Array<any>, U, V = T> = (T extends [FormData | URLSearchParams] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<NarrowResponse<U>>) & {
url: string;
with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => Promise<NarrowResponse<U>>, ...args: A): Action<B, U, V>;
};
export declare const actions: Map<string, Action<any, any, any>>;
export declare function useSubmissions<T extends Array<any>, U, V>(fn: Action<T, U, V>, filter?: (input: V) => boolean): Submission<T, NarrowResponse<U>>[] & {
pending: boolean;
};
export declare function useSubmission<T extends Array<any>, U, V>(fn: Action<T, U, V>, filter?: (input: V) => boolean): Submission<T, NarrowResponse<U>> | SubmissionStub;
export declare function useAction<T extends Array<any>, U, V>(action: Action<T, U, V>): (...args: Parameters<Action<T, U, V>>) => Promise<NarrowResponse<U>>;
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U>;
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, options?: {
name?: string;
onComplete?: (s: Submission<T, U>) => void;
}): Action<T, U>;

163
node_modules/@solidjs/router/dist/data/action.js generated vendored Normal file
View File

@@ -0,0 +1,163 @@
import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
import { isServer } from "solid-js/web";
import { useRouter } from "../routing.js";
import { mockBase, setFunctionName } from "../utils.js";
import { cacheKeyOp, hashKey, revalidate, query } from "./query.js";
export const actions = /* #__PURE__ */ new Map();
export function useSubmissions(fn, filter) {
const router = useRouter();
const subs = createMemo(() => router.submissions[0]().filter(s => s.url === fn.base && (!filter || filter(s.input))));
return new Proxy([], {
get(_, property) {
if (property === $TRACK)
return subs();
if (property === "pending")
return subs().some(sub => !sub.result);
return subs()[property];
},
has(_, property) {
return property in subs();
}
});
}
export function useSubmission(fn, filter) {
const submissions = useSubmissions(fn, filter);
return new Proxy({}, {
get(_, property) {
if ((submissions.length === 0 && property === "clear") || property === "retry")
return () => { };
return submissions[submissions.length - 1]?.[property];
}
});
}
export function useAction(action) {
const r = useRouter();
return (...args) => action.apply({ r }, args);
}
export function action(fn, options = {}) {
function mutate(...variables) {
const router = this.r;
const form = this.f;
const p = (router.singleFlight && fn.withOptions
? fn.withOptions({ headers: { "X-Single-Flight": "true" } })
: fn)(...variables);
const [result, setResult] = createSignal();
let submission;
function handler(error) {
return async (res) => {
const result = await handleResponse(res, error, router.navigatorFactory());
let retry = null;
o.onComplete?.({
...submission,
result: result?.data,
error: result?.error,
pending: false,
retry() {
return (retry = submission.retry());
}
});
if (retry)
return retry;
if (!result)
return submission.clear();
setResult(result);
if (result.error && !form)
throw result.error;
return result.data;
};
}
router.submissions[1](s => [
...s,
(submission = {
input: variables,
url,
get result() {
return result()?.data;
},
get error() {
return result()?.error;
},
get pending() {
return !result();
},
clear() {
router.submissions[1](v => v.filter(i => i !== submission));
},
retry() {
setResult(undefined);
const p = fn(...variables);
return p.then(handler(), handler(true));
}
})
]);
return p.then(handler(), handler(true));
}
const o = typeof options === "string" ? { name: options } : options;
const name = o.name || (!isServer ? String(hashString(fn.toString())) : undefined);
const url = fn.url || (name && `https://action/${name}`) || "";
mutate.base = url;
if (name)
setFunctionName(mutate, name);
return toAction(mutate, url);
}
function toAction(fn, url) {
fn.toString = () => {
if (!url)
throw new Error("Client Actions need explicit names if server rendered");
return url;
};
fn.with = function (...args) {
const newFn = function (...passedArgs) {
return fn.call(this, ...args, ...passedArgs);
};
newFn.base = fn.base;
const uri = new URL(url, mockBase);
uri.searchParams.set("args", hashKey(args));
return toAction(newFn, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search);
};
fn.url = url;
if (!isServer) {
actions.set(url, fn);
getOwner() && onCleanup(() => actions.delete(url));
}
return fn;
}
const hashString = (s) => s.split("").reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0);
async function handleResponse(response, error, navigate) {
let data;
let custom;
let keys;
let flightKeys;
if (response instanceof Response) {
if (response.headers.has("X-Revalidate"))
keys = response.headers.get("X-Revalidate").split(",");
if (response.customBody) {
data = custom = await response.customBody();
if (response.headers.has("X-Single-Flight")) {
data = data._$value;
delete custom._$value;
flightKeys = Object.keys(custom);
}
}
if (response.headers.has("Location")) {
const locationUrl = response.headers.get("Location") || "/";
if (locationUrl.startsWith("http")) {
window.location.href = locationUrl;
}
else {
navigate(locationUrl);
}
}
}
else if (error)
return { error: response };
else
data = response;
// invalidate
cacheKeyOp(keys, entry => (entry[0] = 0));
// set cache
flightKeys && flightKeys.forEach(k => query.set(k, custom[k]));
// trigger revalidation
await revalidate(keys, false);
return data != null ? { data } : undefined;
}

View File

@@ -0,0 +1,32 @@
import { type ReconcileOptions } from "solid-js/store";
/**
* As `createAsync` and `createAsyncStore` are wrappers for `createResource`,
* this type allows to support `latest` field for these primitives.
* It will be removed in the future.
*/
export type AccessorWithLatest<T> = {
(): T;
latest: T;
};
export declare function createAsync<T>(fn: (prev: T) => Promise<T>, options: {
name?: string;
initialValue: T;
deferStream?: boolean;
}): AccessorWithLatest<T>;
export declare function createAsync<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
name?: string;
initialValue?: T;
deferStream?: boolean;
}): AccessorWithLatest<T | undefined>;
export declare function createAsyncStore<T>(fn: (prev: T) => Promise<T>, options: {
name?: string;
initialValue: T;
deferStream?: boolean;
reconcile?: ReconcileOptions;
}): AccessorWithLatest<T>;
export declare function createAsyncStore<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
name?: string;
initialValue?: T;
deferStream?: boolean;
reconcile?: ReconcileOptions;
}): AccessorWithLatest<T | undefined>;

96
node_modules/@solidjs/router/dist/data/createAsync.js generated vendored Normal file
View File

@@ -0,0 +1,96 @@
/**
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
*/
import { createResource, sharedConfig, untrack, catchError } from "solid-js";
import { createStore, reconcile, unwrap } from "solid-js/store";
import { isServer } from "solid-js/web";
import { setFunctionName } from "../utils.js";
export function createAsync(fn, options) {
let resource;
let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
[resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, options);
const resultAccessor = (() => resource());
if (options?.name)
setFunctionName(resultAccessor, options.name);
Object.defineProperty(resultAccessor, "latest", {
get() {
return resource.latest;
}
});
return resultAccessor;
}
export function createAsyncStore(fn, options = {}) {
let resource;
let prev = () => !resource || resource.state === "unresolved"
? undefined
: unwrap(resource.latest);
[resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, {
...options,
storage: (init) => createDeepSignal(init, options.reconcile)
});
const resultAccessor = (() => resource());
Object.defineProperty(resultAccessor, "latest", {
get() {
return resource.latest;
}
});
return resultAccessor;
}
function createDeepSignal(value, options) {
const [store, setStore] = createStore({
value: structuredClone(value)
});
return [
() => store.value,
(v) => {
typeof v === "function" && (v = v());
setStore("value", reconcile(structuredClone(v), options));
return store.value;
}
];
}
// mock promise while hydrating to prevent fetching
class MockPromise {
static all() {
return new MockPromise();
}
static allSettled() {
return new MockPromise();
}
static any() {
return new MockPromise();
}
static race() {
return new MockPromise();
}
static reject() {
return new MockPromise();
}
static resolve() {
return new MockPromise();
}
catch() {
return new MockPromise();
}
then() {
return new MockPromise();
}
finally() {
return new MockPromise();
}
}
function subFetch(fn, prev) {
if (isServer || !sharedConfig.context)
return fn(prev);
const ogFetch = fetch;
const ogPromise = Promise;
try {
window.fetch = () => new MockPromise();
Promise = MockPromise;
return fn(prev);
}
finally {
window.fetch = ogFetch;
Promise = ogPromise;
}
}

9
node_modules/@solidjs/router/dist/data/events.d.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import type { RouterContext } from "../types.js";
type NativeEventConfig = {
preload?: boolean;
explicitLinks?: boolean;
actionBase?: string;
transformUrl?: (url: string) => string;
};
export declare function setupNativeEvents({ preload, explicitLinks, actionBase, transformUrl }?: NativeEventConfig): (router: RouterContext) => void;
export {};

123
node_modules/@solidjs/router/dist/data/events.js generated vendored Normal file
View File

@@ -0,0 +1,123 @@
import { delegateEvents } from "solid-js/web";
import { onCleanup } from "solid-js";
import { actions } from "./action.js";
import { mockBase } from "../utils.js";
export function setupNativeEvents({ preload = true, explicitLinks = false, actionBase = "/_server", transformUrl } = {}) {
return (router) => {
const basePath = router.base.path();
const navigateFromRoute = router.navigatorFactory(router.base);
let preloadTimeout;
let lastElement;
function isSvg(el) {
return el.namespaceURI === "http://www.w3.org/2000/svg";
}
function handleAnchor(evt) {
if (evt.defaultPrevented ||
evt.button !== 0 ||
evt.metaKey ||
evt.altKey ||
evt.ctrlKey ||
evt.shiftKey)
return;
const a = evt
.composedPath()
.find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
if (!a || (explicitLinks && !a.hasAttribute("link")))
return;
const svg = isSvg(a);
const href = svg ? a.href.baseVal : a.href;
const target = svg ? a.target.baseVal : a.target;
if (target || (!href && !a.hasAttribute("state")))
return;
const rel = (a.getAttribute("rel") || "").split(/\s+/);
if (a.hasAttribute("download") || (rel && rel.includes("external")))
return;
const url = svg ? new URL(href, document.baseURI) : new URL(href);
if (url.origin !== window.location.origin ||
(basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())))
return;
return [a, url];
}
function handleAnchorClick(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
const to = router.parsePath(url.pathname + url.search + url.hash);
const state = a.getAttribute("state");
evt.preventDefault();
navigateFromRoute(to, {
resolve: false,
replace: a.hasAttribute("replace"),
scroll: !a.hasAttribute("noscroll"),
state: state ? JSON.parse(state) : undefined
});
}
function handleAnchorPreload(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
transformUrl && (url.pathname = transformUrl(url.pathname));
router.preloadRoute(url, a.getAttribute("preload") !== "false");
}
function handleAnchorMove(evt) {
clearTimeout(preloadTimeout);
const res = handleAnchor(evt);
if (!res)
return (lastElement = null);
const [a, url] = res;
if (lastElement === a)
return;
transformUrl && (url.pathname = transformUrl(url.pathname));
preloadTimeout = setTimeout(() => {
router.preloadRoute(url, a.getAttribute("preload") !== "false");
lastElement = a;
}, 20);
}
function handleFormSubmit(evt) {
if (evt.defaultPrevented)
return;
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction")
? evt.submitter.getAttribute("formaction")
: evt.target.getAttribute("action");
if (!actionRef)
return;
if (!actionRef.startsWith("https://action/")) {
// normalize server actions
const url = new URL(actionRef, mockBase);
actionRef = router.parsePath(url.pathname + url.search);
if (!actionRef.startsWith(actionBase))
return;
}
if (evt.target.method.toUpperCase() !== "POST")
throw new Error("Only POST forms are supported for Actions");
const handler = actions.get(actionRef);
if (handler) {
evt.preventDefault();
const data = new FormData(evt.target, evt.submitter);
handler.call({ r: router, f: evt.target }, evt.target.enctype === "multipart/form-data"
? data
: new URLSearchParams(data));
}
}
// ensure delegated event run first
delegateEvents(["click", "submit"]);
document.addEventListener("click", handleAnchorClick);
if (preload) {
document.addEventListener("mousemove", handleAnchorMove, { passive: true });
document.addEventListener("focusin", handleAnchorPreload, { passive: true });
document.addEventListener("touchstart", handleAnchorPreload, { passive: true });
}
document.addEventListener("submit", handleFormSubmit);
onCleanup(() => {
document.removeEventListener("click", handleAnchorClick);
if (preload) {
document.removeEventListener("mousemove", handleAnchorMove);
document.removeEventListener("focusin", handleAnchorPreload);
document.removeEventListener("touchstart", handleAnchorPreload);
}
document.removeEventListener("submit", handleFormSubmit);
});
};
}

4
node_modules/@solidjs/router/dist/data/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
export { createAsync, createAsyncStore, type AccessorWithLatest } from "./createAsync.js";
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action.js";
export { query, revalidate, cache, type CachedFunction } from "./query.js";
export { redirect, reload, json } from "./response.js";

4
node_modules/@solidjs/router/dist/data/index.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
export { createAsync, createAsyncStore } from "./createAsync.js";
export { action, useSubmission, useSubmissions, useAction } from "./action.js";
export { query, revalidate, cache } from "./query.js";
export { redirect, reload, json } from "./response.js";

23
node_modules/@solidjs/router/dist/data/query.d.ts generated vendored Normal file
View File

@@ -0,0 +1,23 @@
import type { CacheEntry, NarrowResponse } from "../types.js";
/**
* Revalidates the given cache entry/entries.
*/
export declare function revalidate(key?: string | string[] | void, force?: boolean): Promise<void>;
export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void;
export type CachedFunction<T extends (...args: any) => any> = T extends (...args: infer A) => infer R ? ([] extends {
[K in keyof A]-?: A[K];
} ? (...args: never[]) => R extends Promise<infer P> ? Promise<NarrowResponse<P>> : NarrowResponse<R> : (...args: A) => R extends Promise<infer P> ? Promise<NarrowResponse<P>> : NarrowResponse<R>) & {
keyFor: (...args: A) => string;
key: string;
} : never;
export declare function query<T extends (...args: any) => any>(fn: T, name: string): CachedFunction<T>;
export declare namespace query {
export var get: (key: string) => any;
export var set: <T>(key: string, value: T extends Promise<any> ? never : T) => void;
var _a: (key: string) => boolean;
export var clear: () => void;
export { _a as delete };
}
/** @deprecated use query instead */
export declare const cache: typeof query;
export declare function hashKey<T extends Array<any>>(args: T): string;

232
node_modules/@solidjs/router/dist/data/query.js generated vendored Normal file
View File

@@ -0,0 +1,232 @@
import { createSignal, getListener, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js";
import { getRequestEvent, isServer } from "solid-js/web";
import { useNavigate, getIntent, getInPreloadFn } from "../routing.js";
const LocationHeader = "Location";
const PRELOAD_TIMEOUT = 5000;
const CACHE_TIMEOUT = 180000;
let cacheMap = new Map();
// cleanup forward/back cache
if (!isServer) {
setInterval(() => {
const now = Date.now();
for (let [k, v] of cacheMap.entries()) {
if (!v[4].count && now - v[0] > CACHE_TIMEOUT) {
cacheMap.delete(k);
}
}
}, 300000);
}
function getCache() {
if (!isServer)
return cacheMap;
const req = getRequestEvent();
if (!req)
throw new Error("Cannot find cache context");
return (req.router || (req.router = {})).cache || (req.router.cache = new Map());
}
/**
* Revalidates the given cache entry/entries.
*/
export function revalidate(key, force = true) {
return startTransition(() => {
const now = Date.now();
cacheKeyOp(key, entry => {
force && (entry[0] = 0); //force cache miss
entry[4][1](now); // retrigger live signals
});
});
}
export function cacheKeyOp(key, fn) {
key && !Array.isArray(key) && (key = [key]);
for (let k of cacheMap.keys()) {
if (key === undefined || matchKey(k, key))
fn(cacheMap.get(k));
}
}
export function query(fn, name) {
// prioritize GET for server functions
if (fn.GET)
fn = fn.GET;
const cachedFn = ((...args) => {
const cache = getCache();
const intent = getIntent();
const inPreloadFn = getInPreloadFn();
const owner = getOwner();
const navigate = owner ? useNavigate() : undefined;
const now = Date.now();
const key = name + hashKey(args);
let cached = cache.get(key);
let tracking;
if (isServer) {
const e = getRequestEvent();
if (e) {
const dataOnly = (e.router || (e.router = {})).dataOnly;
if (dataOnly) {
const data = e && (e.router.data || (e.router.data = {}));
if (data && key in data)
return data[key];
if (Array.isArray(dataOnly) && !matchKey(key, dataOnly)) {
data[key] = undefined;
return Promise.resolve();
}
}
}
}
if (getListener() && !isServer) {
tracking = true;
onCleanup(() => cached[4].count--);
}
if (cached &&
cached[0] &&
(isServer ||
intent === "native" ||
cached[4].count ||
Date.now() - cached[0] < PRELOAD_TIMEOUT)) {
if (tracking) {
cached[4].count++;
cached[4][0](); // track
}
if (cached[3] === "preload" && intent !== "preload") {
cached[0] = now;
}
let res = cached[1];
if (intent !== "preload") {
res =
"then" in cached[1]
? cached[1].then(handleResponse(false), handleResponse(true))
: handleResponse(false)(cached[1]);
!isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version
}
inPreloadFn && "then" in res && res.catch(() => { });
return res;
}
let res;
if (!isServer && sharedConfig.has && sharedConfig.has(key)) {
res = sharedConfig.load(key); // hydrating
// @ts-ignore at least until we add a delete method to sharedConfig
delete globalThis._$HY.r[key];
}
else
res = fn(...args);
if (cached) {
cached[0] = now;
cached[1] = res;
cached[3] = intent;
!isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version
}
else {
cache.set(key, (cached = [now, res, , intent, createSignal(now)]));
cached[4].count = 0;
}
if (tracking) {
cached[4].count++;
cached[4][0](); // track
}
if (isServer) {
const e = getRequestEvent();
if (e && e.router.dataOnly)
return (e.router.data[key] = res);
}
if (intent !== "preload") {
res =
"then" in res
? res.then(handleResponse(false), handleResponse(true))
: handleResponse(false)(res);
}
inPreloadFn && "then" in res && res.catch(() => { });
// serialize on server
if (isServer &&
sharedConfig.context &&
sharedConfig.context.async &&
!sharedConfig.context.noHydrate) {
const e = getRequestEvent();
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
}
return res;
function handleResponse(error) {
return async (v) => {
if (v instanceof Response) {
const e = getRequestEvent();
if (e) {
for (const [key, value] of v.headers) {
if (key == "set-cookie")
e.response.headers.append("set-cookie", value);
else
e.response.headers.set(key, value);
}
}
const url = v.headers.get(LocationHeader);
if (url !== null) {
// client + server relative redirect
if (navigate && url.startsWith("/"))
startTransition(() => {
navigate(url, { replace: true });
});
else if (!isServer)
window.location.href = url;
else if (e)
e.response.status = 302;
return;
}
if (v.customBody)
v = await v.customBody();
}
if (error)
throw v;
cached[2] = v;
return v;
};
}
});
cachedFn.keyFor = (...args) => name + hashKey(args);
cachedFn.key = name;
return cachedFn;
}
query.get = (key) => {
const cached = getCache().get(key);
return cached[2];
};
query.set = (key, value) => {
const cache = getCache();
const now = Date.now();
let cached = cache.get(key);
if (cached) {
cached[0] = now;
cached[1] = Promise.resolve(value);
cached[2] = value;
cached[3] = "preload";
}
else {
cache.set(key, (cached = [now, Promise.resolve(value), value, "preload", createSignal(now)]));
cached[4].count = 0;
}
};
query.delete = (key) => getCache().delete(key);
query.clear = () => getCache().clear();
/** @deprecated use query instead */
export const cache = query;
function matchKey(key, keys) {
for (let k of keys) {
if (k && key.startsWith(k))
return true;
}
return false;
}
// Modified from the amazing Tanstack Query library (MIT)
// https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts#L168
export function hashKey(args) {
return JSON.stringify(args, (_, val) => isPlainObject(val)
? Object.keys(val)
.sort()
.reduce((result, key) => {
result[key] = val[key];
return result;
}, {})
: val);
}
function isPlainObject(obj) {
let proto;
return (obj != null &&
typeof obj === "object" &&
(!(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype));
}

4
node_modules/@solidjs/router/dist/data/response.d.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
import type { RouterResponseInit, CustomResponse } from "../types.js";
export declare function redirect(url: string, init?: number | RouterResponseInit): CustomResponse<never>;
export declare function reload(init?: RouterResponseInit): CustomResponse<never>;
export declare function json<T>(data: T, init?: RouterResponseInit): CustomResponse<T>;

42
node_modules/@solidjs/router/dist/data/response.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
export function redirect(url, init = 302) {
let responseInit;
let revalidate;
if (typeof init === "number") {
responseInit = { status: init };
}
else {
({ revalidate, ...responseInit } = init);
if (typeof responseInit.status === "undefined") {
responseInit.status = 302;
}
}
const headers = new Headers(responseInit.headers);
headers.set("Location", url);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
const response = new Response(null, {
...responseInit,
headers: headers
});
return response;
}
export function reload(init = {}) {
const { revalidate, ...responseInit } = init;
const headers = new Headers(responseInit.headers);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
return new Response(null, {
...responseInit,
headers
});
}
export function json(data, init = {}) {
const { revalidate, ...responseInit } = init;
const headers = new Headers(responseInit.headers);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
headers.set("Content-Type", "application/json");
const response = new Response(JSON.stringify(data), {
...responseInit,
headers
});
response.customBody = () => data;
return response;
}