Website Structure
This commit is contained in:
parent
62812f2090
commit
71f0676a62
22365 changed files with 4265753 additions and 791 deletions
346
Frontend-Learner/node_modules/nitropack/dist/runtime/internal/cache.mjs
generated
vendored
Normal file
346
Frontend-Learner/node_modules/nitropack/dist/runtime/internal/cache.mjs
generated
vendored
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
import {
|
||||
createEvent,
|
||||
defineEventHandler,
|
||||
fetchWithEvent,
|
||||
handleCacheHeaders,
|
||||
isEvent,
|
||||
splitCookiesString
|
||||
} from "h3";
|
||||
import { parseURL } from "ufo";
|
||||
import { useNitroApp } from "./app.mjs";
|
||||
import { useStorage } from "./storage.mjs";
|
||||
import { hash } from "./hash.mjs";
|
||||
function defaultCacheOptions() {
|
||||
return {
|
||||
name: "_",
|
||||
base: "/cache",
|
||||
swr: true,
|
||||
maxAge: 1
|
||||
};
|
||||
}
|
||||
export function defineCachedFunction(fn, opts = {}) {
|
||||
opts = { ...defaultCacheOptions(), ...opts };
|
||||
const pending = {};
|
||||
const group = opts.group || "nitro/functions";
|
||||
const name = opts.name || fn.name || "_";
|
||||
const integrity = opts.integrity || hash([fn, opts]);
|
||||
const validate = opts.validate || ((entry) => entry.value !== void 0);
|
||||
async function get(key, resolver, shouldInvalidateCache, event) {
|
||||
const cacheKey = [opts.base, group, name, key + ".json"].filter(Boolean).join(":").replace(/:\/$/, ":index");
|
||||
let entry = await useStorage().getItem(cacheKey).catch((error) => {
|
||||
console.error(`[cache] Cache read error.`, error);
|
||||
useNitroApp().captureError(error, { event, tags: ["cache"] });
|
||||
}) || {};
|
||||
if (typeof entry !== "object") {
|
||||
entry = {};
|
||||
const error = new Error("Malformed data read from cache.");
|
||||
console.error("[cache]", error);
|
||||
useNitroApp().captureError(error, { event, tags: ["cache"] });
|
||||
}
|
||||
const ttl = (opts.maxAge ?? 0) * 1e3;
|
||||
if (ttl) {
|
||||
entry.expires = Date.now() + ttl;
|
||||
}
|
||||
const expired = shouldInvalidateCache || entry.integrity !== integrity || ttl && Date.now() - (entry.mtime || 0) > ttl || validate(entry) === false;
|
||||
const _resolve = async () => {
|
||||
const isPending = pending[key];
|
||||
if (!isPending) {
|
||||
if (entry.value !== void 0 && (opts.staleMaxAge || 0) >= 0 && opts.swr === false) {
|
||||
entry.value = void 0;
|
||||
entry.integrity = void 0;
|
||||
entry.mtime = void 0;
|
||||
entry.expires = void 0;
|
||||
}
|
||||
pending[key] = Promise.resolve(resolver());
|
||||
}
|
||||
try {
|
||||
entry.value = await pending[key];
|
||||
} catch (error) {
|
||||
if (!isPending) {
|
||||
delete pending[key];
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (!isPending) {
|
||||
entry.mtime = Date.now();
|
||||
entry.integrity = integrity;
|
||||
delete pending[key];
|
||||
if (validate(entry) !== false) {
|
||||
let setOpts;
|
||||
if (opts.maxAge && !opts.swr) {
|
||||
setOpts = { ttl: opts.maxAge };
|
||||
}
|
||||
const promise = useStorage().setItem(cacheKey, entry, setOpts).catch((error) => {
|
||||
console.error(`[cache] Cache write error.`, error);
|
||||
useNitroApp().captureError(error, { event, tags: ["cache"] });
|
||||
});
|
||||
if (event?.waitUntil) {
|
||||
event.waitUntil(promise);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const _resolvePromise = expired ? _resolve() : Promise.resolve();
|
||||
if (entry.value === void 0) {
|
||||
await _resolvePromise;
|
||||
} else if (expired && event && event.waitUntil) {
|
||||
event.waitUntil(_resolvePromise);
|
||||
}
|
||||
if (opts.swr && validate(entry) !== false) {
|
||||
_resolvePromise.catch((error) => {
|
||||
console.error(`[cache] SWR handler error.`, error);
|
||||
useNitroApp().captureError(error, { event, tags: ["cache"] });
|
||||
});
|
||||
return entry;
|
||||
}
|
||||
return _resolvePromise.then(() => entry);
|
||||
}
|
||||
return async (...args) => {
|
||||
const shouldBypassCache = await opts.shouldBypassCache?.(...args);
|
||||
if (shouldBypassCache) {
|
||||
return fn(...args);
|
||||
}
|
||||
const key = await (opts.getKey || getKey)(...args);
|
||||
const shouldInvalidateCache = await opts.shouldInvalidateCache?.(...args);
|
||||
const entry = await get(
|
||||
key,
|
||||
() => fn(...args),
|
||||
shouldInvalidateCache,
|
||||
args[0] && isEvent(args[0]) ? args[0] : void 0
|
||||
);
|
||||
let value = entry.value;
|
||||
if (opts.transform) {
|
||||
value = await opts.transform(entry, ...args) || value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
export function cachedFunction(fn, opts = {}) {
|
||||
return defineCachedFunction(fn, opts);
|
||||
}
|
||||
function getKey(...args) {
|
||||
return args.length > 0 ? hash(args) : "";
|
||||
}
|
||||
function escapeKey(key) {
|
||||
return String(key).replace(/\W/g, "");
|
||||
}
|
||||
export function defineCachedEventHandler(handler, opts = defaultCacheOptions()) {
|
||||
const variableHeaderNames = (opts.varies || []).filter(Boolean).map((h) => h.toLowerCase()).sort();
|
||||
const _opts = {
|
||||
...opts,
|
||||
getKey: async (event) => {
|
||||
const customKey = await opts.getKey?.(event);
|
||||
if (customKey) {
|
||||
return escapeKey(customKey);
|
||||
}
|
||||
const _path = event.node.req.originalUrl || event.node.req.url || event.path;
|
||||
let _pathname;
|
||||
try {
|
||||
_pathname = escapeKey(decodeURI(parseURL(_path).pathname)).slice(0, 16) || "index";
|
||||
} catch {
|
||||
_pathname = "-";
|
||||
}
|
||||
const _hashedPath = `${_pathname}.${hash(_path)}`;
|
||||
const _headers = variableHeaderNames.map((header) => [header, event.node.req.headers[header]]).map(([name, value]) => `${escapeKey(name)}.${hash(value)}`);
|
||||
return [_hashedPath, ..._headers].join(":");
|
||||
},
|
||||
validate: (entry) => {
|
||||
if (!entry.value) {
|
||||
return false;
|
||||
}
|
||||
if (entry.value.code >= 400) {
|
||||
return false;
|
||||
}
|
||||
if (entry.value.body === void 0) {
|
||||
return false;
|
||||
}
|
||||
if (entry.value.headers.etag === "undefined" || entry.value.headers["last-modified"] === "undefined") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
group: opts.group || "nitro/handlers",
|
||||
integrity: opts.integrity || hash([handler, opts])
|
||||
};
|
||||
const _cachedHandler = cachedFunction(
|
||||
async (incomingEvent) => {
|
||||
const variableHeaders = {};
|
||||
for (const header of variableHeaderNames) {
|
||||
const value = incomingEvent.node.req.headers[header];
|
||||
if (value !== void 0) {
|
||||
variableHeaders[header] = value;
|
||||
}
|
||||
}
|
||||
const reqProxy = cloneWithProxy(incomingEvent.node.req, {
|
||||
headers: variableHeaders
|
||||
});
|
||||
const resHeaders = {};
|
||||
let _resSendBody;
|
||||
const resProxy = cloneWithProxy(incomingEvent.node.res, {
|
||||
statusCode: 200,
|
||||
writableEnded: false,
|
||||
writableFinished: false,
|
||||
headersSent: false,
|
||||
closed: false,
|
||||
getHeader(name) {
|
||||
return resHeaders[name];
|
||||
},
|
||||
setHeader(name, value) {
|
||||
resHeaders[name] = value;
|
||||
return this;
|
||||
},
|
||||
getHeaderNames() {
|
||||
return Object.keys(resHeaders);
|
||||
},
|
||||
hasHeader(name) {
|
||||
return name in resHeaders;
|
||||
},
|
||||
removeHeader(name) {
|
||||
delete resHeaders[name];
|
||||
},
|
||||
getHeaders() {
|
||||
return resHeaders;
|
||||
},
|
||||
end(chunk, arg2, arg3) {
|
||||
if (typeof chunk === "string") {
|
||||
_resSendBody = chunk;
|
||||
}
|
||||
if (typeof arg2 === "function") {
|
||||
arg2();
|
||||
}
|
||||
if (typeof arg3 === "function") {
|
||||
arg3();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
write(chunk, arg2, arg3) {
|
||||
if (typeof chunk === "string") {
|
||||
_resSendBody = chunk;
|
||||
}
|
||||
if (typeof arg2 === "function") {
|
||||
arg2(void 0);
|
||||
}
|
||||
if (typeof arg3 === "function") {
|
||||
arg3();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
writeHead(statusCode, headers2) {
|
||||
this.statusCode = statusCode;
|
||||
if (headers2) {
|
||||
if (Array.isArray(headers2) || typeof headers2 === "string") {
|
||||
throw new TypeError("Raw headers is not supported.");
|
||||
}
|
||||
for (const header in headers2) {
|
||||
const value = headers2[header];
|
||||
if (value !== void 0) {
|
||||
this.setHeader(
|
||||
header,
|
||||
value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
const event = createEvent(reqProxy, resProxy);
|
||||
event.fetch = (url, fetchOptions) => fetchWithEvent(event, url, fetchOptions, {
|
||||
fetch: useNitroApp().localFetch
|
||||
});
|
||||
event.$fetch = (url, fetchOptions) => fetchWithEvent(event, url, fetchOptions, {
|
||||
fetch: globalThis.$fetch
|
||||
});
|
||||
event.waitUntil = incomingEvent.waitUntil;
|
||||
event.context = incomingEvent.context;
|
||||
event.context.cache = {
|
||||
options: _opts
|
||||
};
|
||||
const body = await handler(event) || _resSendBody;
|
||||
const headers = event.node.res.getHeaders();
|
||||
headers.etag = String(
|
||||
headers.Etag || headers.etag || `W/"${hash(body)}"`
|
||||
);
|
||||
headers["last-modified"] = String(
|
||||
headers["Last-Modified"] || headers["last-modified"] || (/* @__PURE__ */ new Date()).toUTCString()
|
||||
);
|
||||
const cacheControl = [];
|
||||
if (opts.swr) {
|
||||
if (opts.maxAge) {
|
||||
cacheControl.push(`s-maxage=${opts.maxAge}`);
|
||||
}
|
||||
if (opts.staleMaxAge) {
|
||||
cacheControl.push(`stale-while-revalidate=${opts.staleMaxAge}`);
|
||||
} else {
|
||||
cacheControl.push("stale-while-revalidate");
|
||||
}
|
||||
} else if (opts.maxAge) {
|
||||
cacheControl.push(`max-age=${opts.maxAge}`);
|
||||
}
|
||||
if (cacheControl.length > 0) {
|
||||
headers["cache-control"] = cacheControl.join(", ");
|
||||
}
|
||||
const cacheEntry = {
|
||||
code: event.node.res.statusCode,
|
||||
headers,
|
||||
body
|
||||
};
|
||||
return cacheEntry;
|
||||
},
|
||||
_opts
|
||||
);
|
||||
return defineEventHandler(async (event) => {
|
||||
if (opts.headersOnly) {
|
||||
if (handleCacheHeaders(event, { maxAge: opts.maxAge })) {
|
||||
return;
|
||||
}
|
||||
return handler(event);
|
||||
}
|
||||
const response = await _cachedHandler(
|
||||
event
|
||||
);
|
||||
if (event.node.res.headersSent || event.node.res.writableEnded) {
|
||||
return response.body;
|
||||
}
|
||||
if (handleCacheHeaders(event, {
|
||||
modifiedTime: new Date(response.headers["last-modified"]),
|
||||
etag: response.headers.etag,
|
||||
maxAge: opts.maxAge
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
event.node.res.statusCode = response.code;
|
||||
for (const name in response.headers) {
|
||||
const value = response.headers[name];
|
||||
if (name === "set-cookie") {
|
||||
event.node.res.appendHeader(
|
||||
name,
|
||||
splitCookiesString(value)
|
||||
);
|
||||
} else {
|
||||
if (value !== void 0) {
|
||||
event.node.res.setHeader(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return response.body;
|
||||
});
|
||||
}
|
||||
function cloneWithProxy(obj, overrides) {
|
||||
return new Proxy(obj, {
|
||||
get(target, property, receiver) {
|
||||
if (property in overrides) {
|
||||
return overrides[property];
|
||||
}
|
||||
return Reflect.get(target, property, receiver);
|
||||
},
|
||||
set(target, property, value, receiver) {
|
||||
if (property in overrides) {
|
||||
overrides[property] = value;
|
||||
return true;
|
||||
}
|
||||
return Reflect.set(target, property, value, receiver);
|
||||
}
|
||||
});
|
||||
}
|
||||
export const cachedEventHandler = defineCachedEventHandler;
|
||||
Loading…
Add table
Add a link
Reference in a new issue