UNPKG

elysia-react-router

Version:

Use React Router v7 or Remix with Elysia with HMR support!

940 lines (924 loc) 30.1 kB
import { Elysia, NotFoundError } from 'elysia'; import { stat, readdir } from 'fs/promises'; import { resolve, sep, join } from 'path'; import require$$1 from 'events'; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var nodeCache$1 = {exports: {}}; var node_cache$1 = {exports: {}}; var clone = {exports: {}}; var hasRequiredClone; function requireClone () { if (hasRequiredClone) return clone.exports; hasRequiredClone = 1; (function (module) { var clone = function() { function _instanceof(obj, type) { return type != null && obj instanceof type; } var nativeMap; try { nativeMap = Map; } catch (_) { nativeMap = function() { }; } var nativeSet; try { nativeSet = Set; } catch (_) { nativeSet = function() { }; } var nativePromise; try { nativePromise = Promise; } catch (_) { nativePromise = function() { }; } function clone2(parent, circular, depth, prototype, includeNonEnumerable) { if (typeof circular === "object") { depth = circular.depth; prototype = circular.prototype; includeNonEnumerable = circular.includeNonEnumerable; circular = circular.circular; } var allParents = []; var allChildren = []; var useBuffer = typeof Buffer != "undefined"; if (typeof circular == "undefined") circular = true; if (typeof depth == "undefined") depth = Infinity; function _clone(parent2, depth2) { if (parent2 === null) return null; if (depth2 === 0) return parent2; var child; var proto; if (typeof parent2 != "object") { return parent2; } if (_instanceof(parent2, nativeMap)) { child = new nativeMap(); } else if (_instanceof(parent2, nativeSet)) { child = new nativeSet(); } else if (_instanceof(parent2, nativePromise)) { child = new nativePromise(function(resolve, reject) { parent2.then(function(value) { resolve(_clone(value, depth2 - 1)); }, function(err) { reject(_clone(err, depth2 - 1)); }); }); } else if (clone2.__isArray(parent2)) { child = []; } else if (clone2.__isRegExp(parent2)) { child = new RegExp(parent2.source, __getRegExpFlags(parent2)); if (parent2.lastIndex) child.lastIndex = parent2.lastIndex; } else if (clone2.__isDate(parent2)) { child = new Date(parent2.getTime()); } else if (useBuffer && Buffer.isBuffer(parent2)) { if (Buffer.allocUnsafe) { child = Buffer.allocUnsafe(parent2.length); } else { child = new Buffer(parent2.length); } parent2.copy(child); return child; } else if (_instanceof(parent2, Error)) { child = Object.create(parent2); } else { if (typeof prototype == "undefined") { proto = Object.getPrototypeOf(parent2); child = Object.create(proto); } else { child = Object.create(prototype); proto = prototype; } } if (circular) { var index = allParents.indexOf(parent2); if (index != -1) { return allChildren[index]; } allParents.push(parent2); allChildren.push(child); } if (_instanceof(parent2, nativeMap)) { parent2.forEach(function(value, key) { var keyChild = _clone(key, depth2 - 1); var valueChild = _clone(value, depth2 - 1); child.set(keyChild, valueChild); }); } if (_instanceof(parent2, nativeSet)) { parent2.forEach(function(value) { var entryChild = _clone(value, depth2 - 1); child.add(entryChild); }); } for (var i in parent2) { var attrs; if (proto) { attrs = Object.getOwnPropertyDescriptor(proto, i); } if (attrs && attrs.set == null) { continue; } child[i] = _clone(parent2[i], depth2 - 1); } if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(parent2); for (var i = 0; i < symbols.length; i++) { var symbol = symbols[i]; var descriptor = Object.getOwnPropertyDescriptor(parent2, symbol); if (descriptor && !descriptor.enumerable && !includeNonEnumerable) { continue; } child[symbol] = _clone(parent2[symbol], depth2 - 1); if (!descriptor.enumerable) { Object.defineProperty(child, symbol, { enumerable: false }); } } } if (includeNonEnumerable) { var allPropertyNames = Object.getOwnPropertyNames(parent2); for (var i = 0; i < allPropertyNames.length; i++) { var propertyName = allPropertyNames[i]; var descriptor = Object.getOwnPropertyDescriptor(parent2, propertyName); if (descriptor && descriptor.enumerable) { continue; } child[propertyName] = _clone(parent2[propertyName], depth2 - 1); Object.defineProperty(child, propertyName, { enumerable: false }); } } return child; } return _clone(parent, depth); } clone2.clonePrototype = function clonePrototype(parent) { if (parent === null) return null; var c = function() { }; c.prototype = parent; return new c(); }; function __objToStr(o) { return Object.prototype.toString.call(o); } clone2.__objToStr = __objToStr; function __isDate(o) { return typeof o === "object" && __objToStr(o) === "[object Date]"; } clone2.__isDate = __isDate; function __isArray(o) { return typeof o === "object" && __objToStr(o) === "[object Array]"; } clone2.__isArray = __isArray; function __isRegExp(o) { return typeof o === "object" && __objToStr(o) === "[object RegExp]"; } clone2.__isRegExp = __isRegExp; function __getRegExpFlags(re) { var flags = ""; if (re.global) flags += "g"; if (re.ignoreCase) flags += "i"; if (re.multiline) flags += "m"; return flags; } clone2.__getRegExpFlags = __getRegExpFlags; return clone2; }(); if (module.exports) { module.exports = clone; } } (clone)); return clone.exports; } var node_cache = node_cache$1.exports; var hasRequiredNode_cache; function requireNode_cache () { if (hasRequiredNode_cache) return node_cache$1.exports; hasRequiredNode_cache = 1; (function() { var EventEmitter, clone, splice = [].splice, boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error("Bound instance method accessed before binding"); } }, indexOf = [].indexOf; clone = requireClone(); EventEmitter = require$$1.EventEmitter; node_cache$1.exports = function() { class NodeCache2 extends EventEmitter { constructor(options = {}) { super(); this.get = this.get.bind(this); this.mget = this.mget.bind(this); this.set = this.set.bind(this); this.mset = this.mset.bind(this); this.del = this.del.bind(this); this.take = this.take.bind(this); this.ttl = this.ttl.bind(this); this.getTtl = this.getTtl.bind(this); this.keys = this.keys.bind(this); this.has = this.has.bind(this); this.getStats = this.getStats.bind(this); this.flushAll = this.flushAll.bind(this); this.flushStats = this.flushStats.bind(this); this.close = this.close.bind(this); this._checkData = this._checkData.bind(this); this._check = this._check.bind(this); this._isInvalidKey = this._isInvalidKey.bind(this); this._wrap = this._wrap.bind(this); this._getValLength = this._getValLength.bind(this); this._error = this._error.bind(this); this._initErrors = this._initErrors.bind(this); this.options = options; this._initErrors(); this.data = {}; this.options = Object.assign({ // convert all elements to string forceString: false, // used standard size for calculating value size objectValueSize: 80, promiseValueSize: 80, arrayValueSize: 40, // standard time to live in seconds. 0 = infinity; stdTTL: 0, // time in seconds to check all data and delete expired keys checkperiod: 600, // en/disable cloning of variables. If `true` you'll get a copy of the cached variable. If `false` you'll save and get just the reference useClones: true, // whether values should be deleted automatically at expiration deleteOnExpire: true, // enable legacy callbacks enableLegacyCallbacks: false, // max amount of keys that are being stored maxKeys: -1 }, this.options); if (this.options.enableLegacyCallbacks) { console.warn("WARNING! node-cache legacy callback support will drop in v6.x"); ["get", "mget", "set", "del", "ttl", "getTtl", "keys", "has"].forEach((methodKey) => { var oldMethod; oldMethod = this[methodKey]; this[methodKey] = function(...args) { var cb, err, ref, res; ref = args, [...args] = ref, [cb] = splice.call(args, -1); if (typeof cb === "function") { try { res = oldMethod(...args); cb(null, res); } catch (error1) { err = error1; cb(err); } } else { return oldMethod(...args, cb); } }; }); } this.stats = { hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0 }; this.validKeyTypes = ["string", "number"]; this._checkData(); return; } get(key) { var _ret, err; boundMethodCheck(this, NodeCache2); if ((err = this._isInvalidKey(key)) != null) { throw err; } if (this.data[key] != null && this._check(key, this.data[key])) { this.stats.hits++; _ret = this._unwrap(this.data[key]); return _ret; } else { this.stats.misses++; return void 0; } } mget(keys) { var _err, err, i, key, len, oRet; boundMethodCheck(this, NodeCache2); if (!Array.isArray(keys)) { _err = this._error("EKEYSTYPE"); throw _err; } oRet = {}; for (i = 0, len = keys.length; i < len; i++) { key = keys[i]; if ((err = this._isInvalidKey(key)) != null) { throw err; } if (this.data[key] != null && this._check(key, this.data[key])) { this.stats.hits++; oRet[key] = this._unwrap(this.data[key]); } else { this.stats.misses++; } } return oRet; } set(key, value, ttl) { var _err, err, existent; boundMethodCheck(this, NodeCache2); if (this.options.maxKeys > -1 && this.stats.keys >= this.options.maxKeys) { _err = this._error("ECACHEFULL"); throw _err; } if (this.options.forceString && false) ; if (ttl == null) { ttl = this.options.stdTTL; } if ((err = this._isInvalidKey(key)) != null) { throw err; } existent = false; if (this.data[key]) { existent = true; this.stats.vsize -= this._getValLength(this._unwrap(this.data[key], false)); } this.data[key] = this._wrap(value, ttl); this.stats.vsize += this._getValLength(value); if (!existent) { this.stats.ksize += this._getKeyLength(key); this.stats.keys++; } this.emit("set", key, value); return true; } mset(keyValueSet) { var _err, err, i, j, key, keyValuePair, len, len1, ttl, val; boundMethodCheck(this, NodeCache2); if (this.options.maxKeys > -1 && this.stats.keys + keyValueSet.length >= this.options.maxKeys) { _err = this._error("ECACHEFULL"); throw _err; } for (i = 0, len = keyValueSet.length; i < len; i++) { keyValuePair = keyValueSet[i]; ({ key, val, ttl } = keyValuePair); if (ttl && typeof ttl !== "number") { _err = this._error("ETTLTYPE"); throw _err; } if ((err = this._isInvalidKey(key)) != null) { throw err; } } for (j = 0, len1 = keyValueSet.length; j < len1; j++) { keyValuePair = keyValueSet[j]; ({ key, val, ttl } = keyValuePair); this.set(key, val, ttl); } return true; } del(keys) { var delCount, err, i, key, len, oldVal; boundMethodCheck(this, NodeCache2); if (!Array.isArray(keys)) { keys = [keys]; } delCount = 0; for (i = 0, len = keys.length; i < len; i++) { key = keys[i]; if ((err = this._isInvalidKey(key)) != null) { throw err; } if (this.data[key] != null) { this.stats.vsize -= this._getValLength(this._unwrap(this.data[key], false)); this.stats.ksize -= this._getKeyLength(key); this.stats.keys--; delCount++; oldVal = this.data[key]; delete this.data[key]; this.emit("del", key, oldVal.v); } } return delCount; } take(key) { var _ret; boundMethodCheck(this, NodeCache2); _ret = this.get(key); if (_ret != null) { this.del(key); } return _ret; } ttl(key, ttl) { var err; boundMethodCheck(this, NodeCache2); ttl || (ttl = this.options.stdTTL); if (!key) { return false; } if ((err = this._isInvalidKey(key)) != null) { throw err; } if (this.data[key] != null && this._check(key, this.data[key])) { if (ttl >= 0) { this.data[key] = this._wrap(this.data[key].v, ttl, false); } else { this.del(key); } return true; } else { return false; } } getTtl(key) { var _ttl, err; boundMethodCheck(this, NodeCache2); if (!key) { return void 0; } if ((err = this._isInvalidKey(key)) != null) { throw err; } if (this.data[key] != null && this._check(key, this.data[key])) { _ttl = this.data[key].t; return _ttl; } else { return void 0; } } keys() { var _keys; boundMethodCheck(this, NodeCache2); _keys = Object.keys(this.data); return _keys; } has(key) { var _exists; boundMethodCheck(this, NodeCache2); _exists = this.data[key] != null && this._check(key, this.data[key]); return _exists; } getStats() { boundMethodCheck(this, NodeCache2); return this.stats; } flushAll(_startPeriod = true) { boundMethodCheck(this, NodeCache2); this.data = {}; this.stats = { hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0 }; this._killCheckPeriod(); this._checkData(_startPeriod); this.emit("flush"); } flushStats() { boundMethodCheck(this, NodeCache2); this.stats = { hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0 }; this.emit("flush_stats"); } close() { boundMethodCheck(this, NodeCache2); this._killCheckPeriod(); } _checkData(startPeriod = true) { var key, ref, value; boundMethodCheck(this, NodeCache2); ref = this.data; for (key in ref) { value = ref[key]; this._check(key, value); } if (startPeriod && this.options.checkperiod > 0) { this.checkTimeout = setTimeout(this._checkData, this.options.checkperiod * 1e3, startPeriod); if (this.checkTimeout != null && this.checkTimeout.unref != null) { this.checkTimeout.unref(); } } } // ## _killCheckPeriod // stop the checkdata period. Only needed to abort the script in testing mode. _killCheckPeriod() { if (this.checkTimeout != null) { return clearTimeout(this.checkTimeout); } } _check(key, data) { var _retval; boundMethodCheck(this, NodeCache2); _retval = true; if (data.t !== 0 && data.t < Date.now()) { if (this.options.deleteOnExpire) { _retval = false; this.del(key); } this.emit("expired", key, this._unwrap(data)); } return _retval; } _isInvalidKey(key) { var ref; boundMethodCheck(this, NodeCache2); if (ref = typeof key, indexOf.call(this.validKeyTypes, ref) < 0) { return this._error("EKEYTYPE", { type: typeof key }); } } _wrap(value, ttl, asClone = true) { var livetime, now, ttlMultiplicator; boundMethodCheck(this, NodeCache2); if (!this.options.useClones) { asClone = false; } now = Date.now(); livetime = 0; ttlMultiplicator = 1e3; if (ttl === 0) { livetime = 0; } else if (ttl) { livetime = now + ttl * ttlMultiplicator; } else { if (this.options.stdTTL === 0) { livetime = this.options.stdTTL; } else { livetime = now + this.options.stdTTL * ttlMultiplicator; } } return { t: livetime, v: asClone ? clone(value) : value }; } // ## _unwrap // internal method to extract get the value out of the wrapped value _unwrap(value, asClone = true) { if (!this.options.useClones) { asClone = false; } if (value.v != null) { if (asClone) { return clone(value.v); } else { return value.v; } } return null; } // ## _getKeyLength // internal method the calculate the key length _getKeyLength(key) { return key.toString().length; } _getValLength(value) { boundMethodCheck(this, NodeCache2); if (typeof value === "string") { return value.length; } else if (this.options.forceString) { return JSON.stringify(value).length; } else if (Array.isArray(value)) { return this.options.arrayValueSize * value.length; } else if (typeof value === "number") { return 8; } else if (typeof (value != null ? value.then : void 0) === "function") { return this.options.promiseValueSize; } else if (typeof Buffer !== "undefined" && Buffer !== null ? Buffer.isBuffer(value) : void 0) { return value.length; } else if (value != null && typeof value === "object") { return this.options.objectValueSize * Object.keys(value).length; } else if (typeof value === "boolean") { return 8; } else { return 0; } } _error(type, data = {}) { var error; boundMethodCheck(this, NodeCache2); error = new Error(); error.name = type; error.errorcode = type; error.message = this.ERRORS[type] != null ? this.ERRORS[type](data) : "-"; error.data = data; return error; } _initErrors() { var _errMsg, _errT, ref; boundMethodCheck(this, NodeCache2); this.ERRORS = {}; ref = this._ERRORS; for (_errT in ref) { _errMsg = ref[_errT]; this.ERRORS[_errT] = this.createErrorMessage(_errMsg); } } createErrorMessage(errMsg) { return function(args) { return errMsg.replace("__key", args.type); }; } } NodeCache2.prototype._ERRORS = { "ENOTFOUND": "Key `__key` not found", "ECACHEFULL": "Cache max keys amount exceeded", "EKEYTYPE": "The key argument has to be of type `string` or `number`. Found: `__key`", "EKEYSTYPE": "The keys argument has to be an array.", "ETTLTYPE": "The ttl argument has to be a number." }; return NodeCache2; }.call(this); }).call(node_cache); return node_cache$1.exports; } var nodeCache = nodeCache$1.exports; var hasRequiredNodeCache; function requireNodeCache () { if (hasRequiredNodeCache) return nodeCache$1.exports; hasRequiredNodeCache = 1; (function() { var exports; exports = nodeCache$1.exports = requireNode_cache(); exports.version = "5.1.2"; }).call(nodeCache); return nodeCache$1.exports; } var nodeCacheExports = requireNodeCache(); var Cache = /*@__PURE__*/getDefaultExportFromCjs(nodeCacheExports); async function isCached(headers, etag, filePath) { if (headers["cache-control"] && headers["cache-control"].indexOf("no-cache") !== -1) return false; if ("if-none-match" in headers) { const ifNoneMatch = headers["if-none-match"]; if (ifNoneMatch === "*") return true; if (ifNoneMatch === null) return false; if (typeof etag !== "string") return false; const isMatching = ifNoneMatch === etag; if (isMatching) return true; return false; } if (headers["if-modified-since"]) { const ifModifiedSince = headers["if-modified-since"]; let lastModified; try { lastModified = (await stat(filePath)).mtime; } catch { } if (lastModified !== void 0 && lastModified.getTime() <= Date.parse(ifModifiedSince)) return true; } return false; } async function generateETag(file) { const hash = new Bun.CryptoHasher("md5"); hash.update(await file.arrayBuffer()); return hash.digest("base64"); } var URL_PATH_SEP = "/"; var fileExists = (path) => stat(path).then( () => true, () => false ); var statCache = new Cache({ useClones: false, checkperiod: 5 * 60, stdTTL: 3 * 60 * 60, maxKeys: 250 }); var fileCache = new Cache({ useClones: false, checkperiod: 5 * 60, stdTTL: 3 * 60 * 60, maxKeys: 250 }); var htmlCache = new Cache({ useClones: false, checkperiod: 5 * 60, stdTTL: 3 * 60 * 60, maxKeys: 250 }); var listFiles = async (dir) => { const files = await readdir(dir); const all = await Promise.all( files.map(async (name) => { const file = dir + sep + name; const stats = await stat(file); return stats && stats.isDirectory() ? await listFiles(file) : [resolve(dir, file)]; }) ); return all.flat(); }; var staticPlugin = async ({ assets = "public", prefix = "/public", staticLimit = 1024, alwaysStatic = process.env.NODE_ENV === "production", ignorePatterns = [".DS_Store", ".git", ".env"], noExtension = false, enableDecodeURI = false, resolve: resolve2 = resolve, headers = {}, noCache = false, maxAge = 86400, directive = "public", indexHTML = true } = { assets: "public", prefix: "/public", staticLimit: 1024, alwaysStatic: process.env.NODE_ENV === "production", ignorePatterns: [], noExtension: false, enableDecodeURI: false, resolve: resolve, headers: {}, noCache: false, indexHTML: true }) => { const files = await listFiles(resolve(assets)); const isFSSepUnsafe = sep !== URL_PATH_SEP; if (prefix === URL_PATH_SEP) prefix = ""; const shouldIgnore = (file) => { if (!ignorePatterns.length) return false; return ignorePatterns.find((pattern) => { if (typeof pattern === "string") return pattern.includes(file); else return pattern.test(file); }); }; const app = new Elysia({ name: "static", seed: { assets, prefix, staticLimit, alwaysStatic, ignorePatterns, noExtension, enableDecodeURI, resolve: resolve2.toString(), headers, noCache, maxAge, directive, indexHTML } }); const assetsDir = assets[0] === sep ? assets : resolve2() + sep + assets; if (alwaysStatic || process.env.ENV === "production" && files.length <= staticLimit) for (const absolutePath of files) { if (!absolutePath || shouldIgnore(absolutePath)) continue; let relativePath = absolutePath.replace(assetsDir, ""); if (noExtension) { const temp = relativePath.split("."); temp.splice(-1); relativePath = temp.join("."); } const file = Bun.file(absolutePath); const etag = await generateETag(file); const pathName = isFSSepUnsafe ? prefix + relativePath.split(sep).join(URL_PATH_SEP) : join(prefix, relativePath); app.get( pathName, noCache ? new Response(file, { headers }) : async ({ headers: reqHeaders }) => { if (await isCached(reqHeaders, etag, absolutePath)) { return new Response(null, { status: 304, headers }); } headers["Etag"] = etag; headers["Cache-Control"] = directive; if (maxAge !== null) headers["Cache-Control"] += `, max-age=${maxAge}`; return new Response(file, { headers }); } ); if (indexHTML && pathName.endsWith("/index.html")) app.get( pathName.replace("/index.html", ""), noCache ? new Response(file, { headers }) : async ({ headers: reqHeaders }) => { if (await isCached(reqHeaders, etag, pathName)) { return new Response(null, { status: 304, headers }); } headers["Etag"] = etag; headers["Cache-Control"] = directive; if (maxAge !== null) headers["Cache-Control"] += `, max-age=${maxAge}`; return new Response(file, { headers }); } ); } else { if (!app.router.history.find( ({ method, path }) => path === `${prefix}/*` && method === "GET" )) app.onError(() => { }).get( `${prefix}/*`, async ({ params, headers: reqHeaders }) => { let path = enableDecodeURI ? ( // @ts-ignore decodeURI(`${assets}/${decodeURI(params["*"])}`) ) : ( // @ts-ignore `${assets}/${params["*"]}` ); if (isFSSepUnsafe) { path = path.replace(URL_PATH_SEP, sep); } if (shouldIgnore(path)) throw new NotFoundError(); try { let status = statCache.get(path); if (!status) { status = await stat(path); statCache.set(path, status); } if (!indexHTML && status.isDirectory()) throw new NotFoundError(); let file = fileCache.get( path ); if (!file) { if (status.isDirectory()) { let hasCache = false; if (indexHTML && (hasCache = htmlCache.get( `${path}${sep}index.html` ) ?? await fileExists( `${path}${sep}index.html` ))) { if (hasCache === void 0) htmlCache.set( `${path}${sep}index.html`, true ); file = Bun.file(`${path}${sep}index.html`); } else { if (indexHTML && hasCache === void 0) htmlCache.set( `${path}${sep}index.html`, false ); throw new NotFoundError(); } } file ??= Bun.file(path); fileCache.set(path, file); } if (noCache) return new Response(file, { headers }); const etag = await generateETag(file); if (await isCached(reqHeaders, etag, path)) return new Response(null, { status: 304, headers }); headers["Etag"] = etag; headers["Cache-Control"] = directive; if (maxAge !== null) headers["Cache-Control"] += `, max-age=${maxAge}`; return new Response(file, { headers }); } catch (error) { throw new NotFoundError(); } } ); } return app; }; export { getDefaultExportFromCjs as g, staticPlugin as s };