UNPKG

@zpg6-test-pkgs/better-auth

Version:

The most comprehensive authentication library for TypeScript.

784 lines (773 loc) 21.4 kB
import { AsyncLocalStorage } from 'node:async_hooks'; import 'defu'; function parse(str, options) { if (typeof str !== "string") { throw new TypeError("argument str must be a string"); } const obj = {}; const opt = {}; const dec = opt.decode || decode; let index = 0; while (index < str.length) { const eqIdx = str.indexOf("=", index); if (eqIdx === -1) { break; } let endIdx = str.indexOf(";", index); if (endIdx === -1) { endIdx = str.length; } else if (endIdx < eqIdx) { index = str.lastIndexOf(";", eqIdx - 1) + 1; continue; } const key = str.slice(index, eqIdx).trim(); if (opt?.filter && !opt?.filter(key)) { index = endIdx + 1; continue; } if (void 0 === obj[key]) { let val = str.slice(eqIdx + 1, endIdx).trim(); if (val.codePointAt(0) === 34) { val = val.slice(1, -1); } obj[key] = tryDecode(val, dec); } index = endIdx + 1; } return obj; } function decode(str) { return str.includes("%") ? decodeURIComponent(str) : str; } function tryDecode(str, decode2) { try { return decode2(str); } catch { return str; } } const fieldContentRegExp = /^[\u0009\u0020-\u007E\u0080-\u00FF]+$/; function serialize(name, value, options) { const opt = options || {}; const enc = opt.encode || encodeURIComponent; if (typeof enc !== "function") { throw new TypeError("option encode is invalid"); } if (!fieldContentRegExp.test(name)) { throw new TypeError("argument name is invalid"); } const encodedValue = enc(value); if (encodedValue && !fieldContentRegExp.test(encodedValue)) { throw new TypeError("argument val is invalid"); } let str = name + "=" + encodedValue; if (void 0 !== opt.maxAge && opt.maxAge !== null) { const maxAge = opt.maxAge - 0; if (Number.isNaN(maxAge) || !Number.isFinite(maxAge)) { throw new TypeError("option maxAge is invalid"); } str += "; Max-Age=" + Math.floor(maxAge); } if (opt.domain) { if (!fieldContentRegExp.test(opt.domain)) { throw new TypeError("option domain is invalid"); } str += "; Domain=" + opt.domain; } if (opt.path) { if (!fieldContentRegExp.test(opt.path)) { throw new TypeError("option path is invalid"); } str += "; Path=" + opt.path; } if (opt.expires) { if (!isDate(opt.expires) || Number.isNaN(opt.expires.valueOf())) { throw new TypeError("option expires is invalid"); } str += "; Expires=" + opt.expires.toUTCString(); } if (opt.httpOnly) { str += "; HttpOnly"; } if (opt.secure) { str += "; Secure"; } if (opt.priority) { const priority = typeof opt.priority === "string" ? opt.priority.toLowerCase() : opt.priority; switch (priority) { case "low": { str += "; Priority=Low"; break; } case "medium": { str += "; Priority=Medium"; break; } case "high": { str += "; Priority=High"; break; } default: { throw new TypeError("option priority is invalid"); } } } if (opt.sameSite) { const sameSite = typeof opt.sameSite === "string" ? opt.sameSite.toLowerCase() : opt.sameSite; switch (sameSite) { case true: { str += "; SameSite=Strict"; break; } case "lax": { str += "; SameSite=Lax"; break; } case "strict": { str += "; SameSite=Strict"; break; } case "none": { str += "; SameSite=None"; break; } default: { throw new TypeError("option sameSite is invalid"); } } } if (opt.partitioned) { str += "; Partitioned"; } return str; } function isDate(val) { return Object.prototype.toString.call(val) === "[object Date]" || val instanceof Date; } const defaults = Object.freeze({ ignoreUnknown: false, respectType: false, respectFunctionNames: false, respectFunctionProperties: false, unorderedObjects: true, unorderedArrays: false, unorderedSets: false, excludeKeys: void 0, excludeValues: void 0, replacer: void 0 }); function objectHash(object, options) { if (options) { options = { ...defaults, ...options }; } else { options = defaults; } const hasher = createHasher(options); hasher.dispatch(object); return hasher.toString(); } const defaultPrototypesKeys = Object.freeze([ "prototype", "__proto__", "constructor" ]); function createHasher(options) { let buff = ""; let context = /* @__PURE__ */ new Map(); const write = (str) => { buff += str; }; return { toString() { return buff; }, getContext() { return context; }, dispatch(value) { if (options.replacer) { value = options.replacer(value); } const type = value === null ? "null" : typeof value; return this[type](value); }, object(object) { if (object && typeof object.toJSON === "function") { return this.object(object.toJSON()); } const objString = Object.prototype.toString.call(object); let objType = ""; const objectLength = objString.length; if (objectLength < 10) { objType = "unknown:[" + objString + "]"; } else { objType = objString.slice(8, objectLength - 1); } objType = objType.toLowerCase(); let objectNumber = null; if ((objectNumber = context.get(object)) === void 0) { context.set(object, context.size); } else { return this.dispatch("[CIRCULAR:" + objectNumber + "]"); } if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(object)) { write("buffer:"); return write(object.toString("utf8")); } if (objType !== "object" && objType !== "function" && objType !== "asyncfunction") { if (this[objType]) { this[objType](object); } else if (!options.ignoreUnknown) { this.unkown(object, objType); } } else { let keys = Object.keys(object); if (options.unorderedObjects) { keys = keys.sort(); } let extraKeys = []; if (options.respectType !== false && !isNativeFunction(object)) { extraKeys = defaultPrototypesKeys; } if (options.excludeKeys) { keys = keys.filter((key) => { return !options.excludeKeys(key); }); extraKeys = extraKeys.filter((key) => { return !options.excludeKeys(key); }); } write("object:" + (keys.length + extraKeys.length) + ":"); const dispatchForKey = (key) => { this.dispatch(key); write(":"); if (!options.excludeValues) { this.dispatch(object[key]); } write(","); }; for (const key of keys) { dispatchForKey(key); } for (const key of extraKeys) { dispatchForKey(key); } } }, array(arr, unordered) { unordered = unordered === void 0 ? options.unorderedArrays !== false : unordered; write("array:" + arr.length + ":"); if (!unordered || arr.length <= 1) { for (const entry of arr) { this.dispatch(entry); } return; } const contextAdditions = /* @__PURE__ */ new Map(); const entries = arr.map((entry) => { const hasher = createHasher(options); hasher.dispatch(entry); for (const [key, value] of hasher.getContext()) { contextAdditions.set(key, value); } return hasher.toString(); }); context = contextAdditions; entries.sort(); return this.array(entries, false); }, date(date) { return write("date:" + date.toJSON()); }, symbol(sym) { return write("symbol:" + sym.toString()); }, unkown(value, type) { write(type); if (!value) { return; } write(":"); if (value && typeof value.entries === "function") { return this.array( Array.from(value.entries()), true /* ordered */ ); } }, error(err) { return write("error:" + err.toString()); }, boolean(bool) { return write("bool:" + bool); }, string(string) { write("string:" + string.length + ":"); write(string); }, function(fn) { write("fn:"); if (isNativeFunction(fn)) { this.dispatch("[native]"); } else { this.dispatch(fn.toString()); } if (options.respectFunctionNames !== false) { this.dispatch("function-name:" + String(fn.name)); } if (options.respectFunctionProperties) { this.object(fn); } }, number(number) { return write("number:" + number); }, xml(xml) { return write("xml:" + xml.toString()); }, null() { return write("Null"); }, undefined() { return write("Undefined"); }, regexp(regex) { return write("regex:" + regex.toString()); }, uint8array(arr) { write("uint8array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, uint8clampedarray(arr) { write("uint8clampedarray:"); return this.dispatch(Array.prototype.slice.call(arr)); }, int8array(arr) { write("int8array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, uint16array(arr) { write("uint16array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, int16array(arr) { write("int16array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, uint32array(arr) { write("uint32array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, int32array(arr) { write("int32array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, float32array(arr) { write("float32array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, float64array(arr) { write("float64array:"); return this.dispatch(Array.prototype.slice.call(arr)); }, arraybuffer(arr) { write("arraybuffer:"); return this.dispatch(new Uint8Array(arr)); }, url(url) { return write("url:" + url.toString()); }, map(map) { write("map:"); const arr = [...map]; return this.array(arr, options.unorderedSets !== false); }, set(set) { write("set:"); const arr = [...set]; return this.array(arr, options.unorderedSets !== false); }, file(file) { write("file:"); return this.dispatch([file.name, file.size, file.type, file.lastModfied]); }, blob() { if (options.ignoreUnknown) { return write("[blob]"); } throw new Error( 'Hashing Blob objects is currently not supported\nUse "options.replacer" or "options.ignoreUnknown"\n' ); }, domwindow() { return write("domwindow"); }, bigint(number) { return write("bigint:" + number.toString()); }, /* Node.js standard native objects */ process() { return write("process"); }, timer() { return write("timer"); }, pipe() { return write("pipe"); }, tcp() { return write("tcp"); }, udp() { return write("udp"); }, tty() { return write("tty"); }, statwatcher() { return write("statwatcher"); }, securecontext() { return write("securecontext"); }, connection() { return write("connection"); }, zlib() { return write("zlib"); }, context() { return write("context"); }, nodescript() { return write("nodescript"); }, httpparser() { return write("httpparser"); }, dataview() { return write("dataview"); }, signal() { return write("signal"); }, fsevent() { return write("fsevent"); }, tlswrap() { return write("tlswrap"); } }; } const nativeFunc = "[native code] }"; const nativeFuncLength = nativeFunc.length; function isNativeFunction(f) { if (typeof f !== "function") { return false; } return Function.prototype.toString.call(f).slice(-nativeFuncLength) === nativeFunc; } function hasProp(obj, prop) { try { return prop in obj; } catch { return false; } } var __defProp$2 = Object.defineProperty; var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$2 = (obj, key, value) => { __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; class H3Error extends Error { constructor(message, opts = {}) { super(message, opts); __publicField$2(this, "statusCode", 500); __publicField$2(this, "fatal", false); __publicField$2(this, "unhandled", false); __publicField$2(this, "statusMessage"); __publicField$2(this, "data"); __publicField$2(this, "cause"); if (opts.cause && !this.cause) { this.cause = opts.cause; } } toJSON() { const obj = { message: this.message, statusCode: sanitizeStatusCode(this.statusCode, 500) }; if (this.statusMessage) { obj.statusMessage = sanitizeStatusMessage(this.statusMessage); } if (this.data !== void 0) { obj.data = this.data; } return obj; } } __publicField$2(H3Error, "__h3_error__", true); const DISALLOWED_STATUS_CHARS = /[^\u0009\u0020-\u007E]/g; function sanitizeStatusMessage(statusMessage = "") { return statusMessage.replace(DISALLOWED_STATUS_CHARS, ""); } function sanitizeStatusCode(statusCode, defaultStatusCode = 200) { if (!statusCode) { return defaultStatusCode; } if (typeof statusCode === "string") { statusCode = Number.parseInt(statusCode, 10); } if (statusCode < 100 || statusCode > 999) { return defaultStatusCode; } return statusCode; } function setCookie$1(event, name, value, serializeOptions) { serializeOptions = { path: "/", ...serializeOptions }; const cookieStr = serialize(name, value, serializeOptions); let setCookies = event.node.res.getHeader("set-cookie"); if (!Array.isArray(setCookies)) { setCookies = [setCookies]; } const _optionsHash = objectHash(serializeOptions); setCookies = setCookies.filter((cookieValue) => { return cookieValue && _optionsHash !== objectHash(parse(cookieValue)); }); event.node.res.setHeader("set-cookie", [...setCookies, cookieStr]); } function splitCookiesString(cookiesString) { if (Array.isArray(cookiesString)) { return cookiesString.flatMap((c) => splitCookiesString(c)); } if (typeof cookiesString !== "string") { return []; } const cookiesStrings = []; let pos = 0; let start; let ch; let lastComma; let nextStart; let cookiesSeparatorFound; const skipWhitespace = () => { while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) { pos += 1; } return pos < cookiesString.length; }; const notSpecialChar = () => { ch = cookiesString.charAt(pos); return ch !== "=" && ch !== ";" && ch !== ","; }; while (pos < cookiesString.length) { start = pos; cookiesSeparatorFound = false; while (skipWhitespace()) { ch = cookiesString.charAt(pos); if (ch === ",") { lastComma = pos; pos += 1; skipWhitespace(); nextStart = pos; while (pos < cookiesString.length && notSpecialChar()) { pos += 1; } if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") { cookiesSeparatorFound = true; pos = nextStart; cookiesStrings.push(cookiesString.slice(start, lastComma)); start = pos; } else { pos = lastComma + 1; } } else { pos += 1; } } if (!cookiesSeparatorFound || pos >= cookiesString.length) { cookiesStrings.push(cookiesString.slice(start)); } } return cookiesStrings; } typeof setImmediate === "undefined" ? (fn) => fn() : setImmediate; function sendStream(event, stream) { if (!stream || typeof stream !== "object") { throw new Error("[h3] Invalid stream provided."); } event.node.res._data = stream; if (!event.node.res.socket) { event._handled = true; return Promise.resolve(); } if (hasProp(stream, "pipeTo") && typeof stream.pipeTo === "function") { return stream.pipeTo( new WritableStream({ write(chunk) { event.node.res.write(chunk); } }) ).then(() => { event.node.res.end(); }); } if (hasProp(stream, "pipe") && typeof stream.pipe === "function") { return new Promise((resolve, reject) => { stream.pipe(event.node.res); if (stream.on) { stream.on("end", () => { event.node.res.end(); resolve(); }); stream.on("error", (error) => { reject(error); }); } event.node.res.on("close", () => { if (stream.abort) { stream.abort(); } }); }); } throw new Error("[h3] Invalid or incompatible stream provided."); } function sendWebResponse(event, response) { for (const [key, value] of response.headers) { if (key === "set-cookie") { event.node.res.appendHeader(key, splitCookiesString(value)); } else { event.node.res.setHeader(key, value); } } if (response.status) { event.node.res.statusCode = sanitizeStatusCode( response.status, event.node.res.statusCode ); } if (response.statusText) { event.node.res.statusMessage = sanitizeStatusMessage(response.statusText); } if (response.redirected) { event.node.res.setHeader("location", response.url); } if (!response.body) { event.node.res.end(); return; } return sendStream(event, response.body); } var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; class H3Event { constructor(req, res) { __publicField(this, "__is_event__", true); // Context __publicField(this, "node"); // Node __publicField(this, "web"); // Web __publicField(this, "context", {}); // Shared // Request __publicField(this, "_method"); __publicField(this, "_path"); __publicField(this, "_headers"); __publicField(this, "_requestBody"); // Response __publicField(this, "_handled", false); // Hooks __publicField(this, "_onBeforeResponseCalled"); __publicField(this, "_onAfterResponseCalled"); this.node = { req, res }; } // --- Request --- get method() { if (!this._method) { this._method = (this.node.req.method || "GET").toUpperCase(); } return this._method; } get path() { return this._path || this.node.req.url || "/"; } get headers() { if (!this._headers) { this._headers = _normalizeNodeHeaders(this.node.req.headers); } return this._headers; } // --- Respoonse --- get handled() { return this._handled || this.node.res.writableEnded || this.node.res.headersSent; } respondWith(response) { return Promise.resolve(response).then( (_response) => sendWebResponse(this, _response) ); } // --- Utils --- toString() { return `[${this.method}] ${this.path}`; } toJSON() { return this.toString(); } // --- Deprecated --- /** @deprecated Please use `event.node.req` instead. */ get req() { return this.node.req; } /** @deprecated Please use `event.node.res` instead. */ get res() { return this.node.res; } } function _normalizeNodeHeaders(nodeHeaders) { const headers = new Headers(); for (const [name, value] of Object.entries(nodeHeaders)) { if (Array.isArray(value)) { for (const item of value) { headers.append(name, item); } } else if (value) { headers.set(name, value); } } return headers; } const eventStorage = new AsyncLocalStorage(); function getEvent() { const event = eventStorage.getStore(); if (!event) { throw new Error( `No HTTPEvent found in AsyncLocalStorage. Make sure you are using the function within the server runtime.` ); } return event; } const HTTPEventSymbol = Symbol("$HTTPEvent"); function isEvent(obj) { return typeof obj === "object" && (obj instanceof H3Event || (obj == null ? void 0 : obj[HTTPEventSymbol]) instanceof H3Event || (obj == null ? void 0 : obj.__is_event__) === true); } function createWrapperFunction(h3Function) { return function(...args) { const event = args[0]; if (!isEvent(event)) { args.unshift(getEvent()); } else { args[0] = event instanceof H3Event || event.__is_event__ ? event : event[HTTPEventSymbol]; } return h3Function(...args); }; } const setCookie = createWrapperFunction(setCookie$1); export { H3Error, H3Event, HTTPEventSymbol, getEvent, isEvent, sanitizeStatusCode, sanitizeStatusMessage, setCookie, splitCookiesString };