UNPKG

@buildappolis/env-manager

Version:

Enterprise-grade environment variable management system with encryption, snapshots, and validation

1,650 lines (1,568 loc) 244 kB
import { Http2ServerResponse } from 'node:http2'; import { R as ROUTE_TYPE_HEADER, h as REROUTE_DIRECTIVE_HEADER, i as bold, j as red, y as yellow, k as dim, l as blue, n as decryptString, o as createSlotValueFromString, d as renderComponent, r as renderTemplate, D as DEFAULT_404_COMPONENT, p as renderSlotToString, q as renderJSX, t as chunkToString, u as isRenderInstruction, v as originPathnameSymbol, A as ASTRO_VERSION, w as clientLocalsSymbol, x as clientAddressSymbol, z as responseSentSymbol$1, B as renderPage, C as REWRITE_DIRECTIVE_HEADER_KEY, E as REWRITE_DIRECTIVE_HEADER_VALUE, F as renderEndpoint, G as REROUTABLE_STATUS_CODES, H as getDefaultExportFromCjs } from './astro/server_DE_7F_eO.mjs'; import { q as appendForwardSlash$1, s as joinPaths, A as AstroError, t as i18nNoLocaleFoundInPath, R as ResponseSentError, u as MiddlewareNoDataOrNextCalled, v as MiddlewareNotAResponse, G as GetStaticPathsRequired, w as InvalidGetStaticPathsReturn, x as InvalidGetStaticPathsEntry, y as GetStaticPathsExpectedParams, z as GetStaticPathsInvalidRouteParam, B as trimSlashes, P as PageNumberParamNotFound, C as NoMatchingStaticPathFound, H as PrerenderDynamicEndpointPathCollide, J as ReservedSlotName, K as removeTrailingForwardSlash, L as RewriteWithBodyUsed, Q as LocalsNotAnObject, S as PrerenderClientAddressNotAvailable, T as ClientAddressNotAvailable, U as StaticClientAddressNotAvailable, V as AstroResponseHeadersReassigned, W as fileExtension, X as slash, Y as prependForwardSlash$1 } from './astro/assets-service_DpLAZY03.mjs'; import { g as getActionQueryString, d as deserializeActionResult, e as ensure404Route, D as DEFAULT_404_ROUTE, a as default404Instance, N as NOOP_MIDDLEWARE_FN } from './astro-designed-error-pages_DtTvViuk.mjs'; import 'clsx'; import { AsyncLocalStorage } from 'node:async_hooks'; import fs$3 from 'node:fs'; import http from 'node:http'; import https from 'node:https'; import os from 'node:os'; import path$2 from 'node:path'; import url from 'node:url'; import path$1 from 'path'; import require$$0$1 from 'tty'; import require$$1 from 'util'; import fs$2 from 'fs'; import require$$4 from 'net'; import require$$0$2 from 'events'; import require$$2$1 from 'stream'; import require$$3 from 'zlib'; import crypto$2 from 'crypto'; import buffer from 'node:buffer'; import crypto$1 from 'node:crypto'; function shouldAppendForwardSlash(trailingSlash, buildFormat) { switch (trailingSlash) { case "always": return true; case "never": return false; case "ignore": { switch (buildFormat) { case "directory": return true; case "preserve": case "file": return false; } } } } function createI18nMiddleware(i18n, base, trailingSlash, format) { if (!i18n) return (_, next) => next(); const payload = { ...i18n, trailingSlash, base, format}; const _redirectToDefaultLocale = redirectToDefaultLocale(payload); const _noFoundForNonLocaleRoute = notFound(payload); const _requestHasLocale = requestHasLocale(payload.locales); const _redirectToFallback = redirectToFallback(payload); const prefixAlways = (context) => { const url = context.url; if (url.pathname === base + "/" || url.pathname === base) { return _redirectToDefaultLocale(context); } else if (!_requestHasLocale(context)) { return _noFoundForNonLocaleRoute(context); } return void 0; }; const prefixOtherLocales = (context, response) => { let pathnameContainsDefaultLocale = false; const url = context.url; for (const segment of url.pathname.split("/")) { if (normalizeTheLocale(segment) === normalizeTheLocale(i18n.defaultLocale)) { pathnameContainsDefaultLocale = true; break; } } if (pathnameContainsDefaultLocale) { const newLocation = url.pathname.replace(`/${i18n.defaultLocale}`, ""); response.headers.set("Location", newLocation); return _noFoundForNonLocaleRoute(context); } return void 0; }; return async (context, next) => { const response = await next(); const type = response.headers.get(ROUTE_TYPE_HEADER); const isReroute = response.headers.get(REROUTE_DIRECTIVE_HEADER); if (isReroute === "no" && typeof i18n.fallback === "undefined") { return response; } if (type !== "page" && type !== "fallback") { return response; } if (requestIs404Or500(context.request, base)) { return response; } const { currentLocale } = context; switch (i18n.strategy) { case "manual": { return response; } case "domains-prefix-other-locales": { if (localeHasntDomain(i18n, currentLocale)) { const result = prefixOtherLocales(context, response); if (result) { return result; } } break; } case "pathname-prefix-other-locales": { const result = prefixOtherLocales(context, response); if (result) { return result; } break; } case "domains-prefix-always-no-redirect": { if (localeHasntDomain(i18n, currentLocale)) { const result = _noFoundForNonLocaleRoute(context, response); if (result) { return result; } } break; } case "pathname-prefix-always-no-redirect": { const result = _noFoundForNonLocaleRoute(context, response); if (result) { return result; } break; } case "pathname-prefix-always": { const result = prefixAlways(context); if (result) { return result; } break; } case "domains-prefix-always": { if (localeHasntDomain(i18n, currentLocale)) { const result = prefixAlways(context); if (result) { return result; } } break; } } return _redirectToFallback(context, response); }; } function localeHasntDomain(i18n, currentLocale) { for (const domainLocale of Object.values(i18n.domainLookupTable)) { if (domainLocale === currentLocale) { return false; } } return true; } function requestHasLocale(locales) { return function(context) { return pathHasLocale(context.url.pathname, locales); }; } function requestIs404Or500(request, base = "") { const url = new URL(request.url); return url.pathname.startsWith(`${base}/404`) || url.pathname.startsWith(`${base}/500`); } function pathHasLocale(path, locales) { const segments = path.split("/"); for (const segment of segments) { for (const locale of locales) { if (typeof locale === "string") { if (normalizeTheLocale(segment) === normalizeTheLocale(locale)) { return true; } } else if (segment === locale.path) { return true; } } } return false; } function getPathByLocale(locale, locales) { for (const loopLocale of locales) { if (typeof loopLocale === "string") { if (loopLocale === locale) { return loopLocale; } } else { for (const code of loopLocale.codes) { if (code === locale) { return loopLocale.path; } } } } throw new AstroError(i18nNoLocaleFoundInPath); } function normalizeTheLocale(locale) { return locale.replaceAll("_", "-").toLowerCase(); } function toCodes(locales) { return locales.map((loopLocale) => { if (typeof loopLocale === "string") { return loopLocale; } else { return loopLocale.codes[0]; } }); } function redirectToDefaultLocale({ trailingSlash, format, base, defaultLocale }) { return function(context, statusCode) { if (shouldAppendForwardSlash(trailingSlash, format)) { return context.redirect(`${appendForwardSlash$1(joinPaths(base, defaultLocale))}`, statusCode); } else { return context.redirect(`${joinPaths(base, defaultLocale)}`, statusCode); } }; } function notFound({ base, locales }) { return function(context, response) { if (response?.headers.get(REROUTE_DIRECTIVE_HEADER) === "no") return response; const url = context.url; const isRoot = url.pathname === base + "/" || url.pathname === base; if (!(isRoot || pathHasLocale(url.pathname, locales))) { if (response) { response.headers.set(REROUTE_DIRECTIVE_HEADER, "no"); return new Response(response.body, { status: 404, headers: response.headers }); } else { return new Response(null, { status: 404, headers: { [REROUTE_DIRECTIVE_HEADER]: "no" } }); } } return void 0; }; } function redirectToFallback({ fallback, locales, defaultLocale, strategy, base, fallbackType }) { return async function(context, response) { if (response.status >= 300 && fallback) { const fallbackKeys = fallback ? Object.keys(fallback) : []; const segments = context.url.pathname.split("/"); const urlLocale = segments.find((segment) => { for (const locale of locales) { if (typeof locale === "string") { if (locale === segment) { return true; } } else if (locale.path === segment) { return true; } } return false; }); if (urlLocale && fallbackKeys.includes(urlLocale)) { const fallbackLocale = fallback[urlLocale]; const pathFallbackLocale = getPathByLocale(fallbackLocale, locales); let newPathname; if (pathFallbackLocale === defaultLocale && strategy === "pathname-prefix-other-locales") { if (context.url.pathname.includes(`${base}`)) { newPathname = context.url.pathname.replace(`/${urlLocale}`, ``); } else { newPathname = context.url.pathname.replace(`/${urlLocale}`, `/`); } } else { newPathname = context.url.pathname.replace(`/${urlLocale}`, `/${pathFallbackLocale}`); } if (fallbackType === "rewrite") { return await context.rewrite(newPathname); } else { return context.redirect(newPathname); } } } return response; }; } /*! * cookie * Copyright(c) 2012-2014 Roman Shtylman * Copyright(c) 2015 Douglas Christopher Wilson * MIT Licensed */ /** * Module exports. * @public */ var parse_1 = parse$1; var serialize_1 = serialize; /** * Module variables. * @private */ var __toString = Object.prototype.toString; var __hasOwnProperty = Object.prototype.hasOwnProperty; /** * RegExp to match cookie-name in RFC 6265 sec 4.1.1 * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2 * which has been replaced by the token definition in RFC 7230 appendix B. * * cookie-name = token * token = 1*tchar * tchar = "!" / "#" / "$" / "%" / "&" / "'" / * "*" / "+" / "-" / "." / "^" / "_" / * "`" / "|" / "~" / DIGIT / ALPHA */ var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/; /** * RegExp to match cookie-value in RFC 6265 sec 4.1.1 * * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E * ; US-ASCII characters excluding CTLs, * ; whitespace DQUOTE, comma, semicolon, * ; and backslash */ var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/; /** * RegExp to match domain-value in RFC 6265 sec 4.1.1 * * domain-value = <subdomain> * ; defined in [RFC1034], Section 3.5, as * ; enhanced by [RFC1123], Section 2.1 * <subdomain> = <label> | <subdomain> "." <label> * <label> = <let-dig> [ [ <ldh-str> ] <let-dig> ] * Labels must be 63 characters or less. * 'let-dig' not 'letter' in the first char, per RFC1123 * <ldh-str> = <let-dig-hyp> | <let-dig-hyp> <ldh-str> * <let-dig-hyp> = <let-dig> | "-" * <let-dig> = <letter> | <digit> * <letter> = any one of the 52 alphabetic characters A through Z in * upper case and a through z in lower case * <digit> = any one of the ten digits 0 through 9 * * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173 * * > (Note that a leading %x2E ("."), if present, is ignored even though that * character is not permitted, but a trailing %x2E ("."), if present, will * cause the user agent to ignore the attribute.) */ var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i; /** * RegExp to match path-value in RFC 6265 sec 4.1.1 * * path-value = <any CHAR except CTLs or ";"> * CHAR = %x01-7F * ; defined in RFC 5234 appendix B.1 */ var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/; /** * Parse a cookie header. * * Parse the given cookie header string into an object * The object has the various cookies as keys(names) => values * * @param {string} str * @param {object} [opt] * @return {object} * @public */ function parse$1(str, opt) { if (typeof str !== 'string') { throw new TypeError('argument str must be a string'); } var obj = {}; var len = str.length; // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='. if (len < 2) return obj; var dec = (opt && opt.decode) || decode$1; var index = 0; var eqIdx = 0; var endIdx = 0; do { eqIdx = str.indexOf('=', index); if (eqIdx === -1) break; // No more cookie pairs. endIdx = str.indexOf(';', index); if (endIdx === -1) { endIdx = len; } else if (eqIdx > endIdx) { // backtrack on prior semicolon index = str.lastIndexOf(';', eqIdx - 1) + 1; continue; } var keyStartIdx = startIndex(str, index, eqIdx); var keyEndIdx = endIndex(str, eqIdx, keyStartIdx); var key = str.slice(keyStartIdx, keyEndIdx); // only assign once if (!__hasOwnProperty.call(obj, key)) { var valStartIdx = startIndex(str, eqIdx + 1, endIdx); var valEndIdx = endIndex(str, endIdx, valStartIdx); if (str.charCodeAt(valStartIdx) === 0x22 /* " */ && str.charCodeAt(valEndIdx - 1) === 0x22 /* " */) { valStartIdx++; valEndIdx--; } var val = str.slice(valStartIdx, valEndIdx); obj[key] = tryDecode(val, dec); } index = endIdx + 1; } while (index < len); return obj; } function startIndex(str, index, max) { do { var code = str.charCodeAt(index); if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index; } while (++index < max); return max; } function endIndex(str, index, min) { while (index > min) { var code = str.charCodeAt(--index); if (code !== 0x20 /* */ && code !== 0x09 /* \t */) return index + 1; } return min; } /** * Serialize data into a cookie header. * * Serialize a name value pair into a cookie string suitable for * http headers. An optional options object specifies cookie parameters. * * serialize('foo', 'bar', { httpOnly: true }) * => "foo=bar; httpOnly" * * @param {string} name * @param {string} val * @param {object} [opt] * @return {string} * @public */ function serialize(name, val, opt) { var enc = (opt && opt.encode) || encodeURIComponent; if (typeof enc !== 'function') { throw new TypeError('option encode is invalid'); } if (!cookieNameRegExp.test(name)) { throw new TypeError('argument name is invalid'); } var value = enc(val); if (!cookieValueRegExp.test(value)) { throw new TypeError('argument val is invalid'); } var str = name + '=' + value; if (!opt) return str; if (null != opt.maxAge) { var maxAge = Math.floor(opt.maxAge); if (!isFinite(maxAge)) { throw new TypeError('option maxAge is invalid') } str += '; Max-Age=' + maxAge; } if (opt.domain) { if (!domainValueRegExp.test(opt.domain)) { throw new TypeError('option domain is invalid'); } str += '; Domain=' + opt.domain; } if (opt.path) { if (!pathValueRegExp.test(opt.path)) { throw new TypeError('option path is invalid'); } str += '; Path=' + opt.path; } if (opt.expires) { var expires = opt.expires; if (!isDate(expires) || isNaN(expires.valueOf())) { throw new TypeError('option expires is invalid'); } str += '; Expires=' + expires.toUTCString(); } if (opt.httpOnly) { str += '; HttpOnly'; } if (opt.secure) { str += '; Secure'; } if (opt.partitioned) { str += '; Partitioned'; } if (opt.priority) { var 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) { var 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'); } } return str; } /** * URL-decode string value. Optimized to skip native call when no %. * * @param {string} str * @returns {string} */ function decode$1 (str) { return str.indexOf('%') !== -1 ? decodeURIComponent(str) : str } /** * Determine if value is a Date. * * @param {*} val * @private */ function isDate (val) { return __toString.call(val) === '[object Date]'; } /** * Try decoding a string using a decoding function. * * @param {string} str * @param {function} decode * @private */ function tryDecode(str, decode) { try { return decode(str); } catch (e) { return str; } } const DELETED_EXPIRATION = /* @__PURE__ */ new Date(0); const DELETED_VALUE = "deleted"; const responseSentSymbol = Symbol.for("astro.responseSent"); class AstroCookie { constructor(value) { this.value = value; } json() { if (this.value === void 0) { throw new Error(`Cannot convert undefined to an object.`); } return JSON.parse(this.value); } number() { return Number(this.value); } boolean() { if (this.value === "false") return false; if (this.value === "0") return false; return Boolean(this.value); } } class AstroCookies { #request; #requestValues; #outgoing; #consumed; constructor(request) { this.#request = request; this.#requestValues = null; this.#outgoing = null; this.#consumed = false; } /** * Astro.cookies.delete(key) is used to delete a cookie. Using this method will result * in a Set-Cookie header added to the response. * @param key The cookie to delete * @param options Options related to this deletion, such as the path of the cookie. */ delete(key, options) { const { // @ts-expect-error maxAge: _ignoredMaxAge, // @ts-expect-error expires: _ignoredExpires, ...sanitizedOptions } = options || {}; const serializeOptions = { expires: DELETED_EXPIRATION, ...sanitizedOptions }; this.#ensureOutgoingMap().set(key, [ DELETED_VALUE, serialize_1(key, DELETED_VALUE, serializeOptions), false ]); } /** * Astro.cookies.get(key) is used to get a cookie value. The cookie value is read from the * request. If you have set a cookie via Astro.cookies.set(key, value), the value will be taken * from that set call, overriding any values already part of the request. * @param key The cookie to get. * @returns An object containing the cookie value as well as convenience methods for converting its value. */ get(key, options = void 0) { if (this.#outgoing?.has(key)) { let [serializedValue, , isSetValue] = this.#outgoing.get(key); if (isSetValue) { return new AstroCookie(serializedValue); } else { return void 0; } } const values = this.#ensureParsed(options); if (key in values) { const value = values[key]; return new AstroCookie(value); } } /** * Astro.cookies.has(key) returns a boolean indicating whether this cookie is either * part of the initial request or set via Astro.cookies.set(key) * @param key The cookie to check for. * @returns */ has(key, options = void 0) { if (this.#outgoing?.has(key)) { let [, , isSetValue] = this.#outgoing.get(key); return isSetValue; } const values = this.#ensureParsed(options); return !!values[key]; } /** * Astro.cookies.set(key, value) is used to set a cookie's value. If provided * an object it will be stringified via JSON.stringify(value). Additionally you * can provide options customizing how this cookie will be set, such as setting httpOnly * in order to prevent the cookie from being read in client-side JavaScript. * @param key The name of the cookie to set. * @param value A value, either a string or other primitive or an object. * @param options Options for the cookie, such as the path and security settings. */ set(key, value, options) { if (this.#consumed) { const warning = new Error( "Astro.cookies.set() was called after the cookies had already been sent to the browser.\nThis may have happened if this method was called in an imported component.\nPlease make sure that Astro.cookies.set() is only called in the frontmatter of the main page." ); warning.name = "Warning"; console.warn(warning); } let serializedValue; if (typeof value === "string") { serializedValue = value; } else { let toStringValue = value.toString(); if (toStringValue === Object.prototype.toString.call(value)) { serializedValue = JSON.stringify(value); } else { serializedValue = toStringValue; } } const serializeOptions = {}; if (options) { Object.assign(serializeOptions, options); } this.#ensureOutgoingMap().set(key, [ serializedValue, serialize_1(key, serializedValue, serializeOptions), true ]); if (this.#request[responseSentSymbol]) { throw new AstroError({ ...ResponseSentError }); } } /** * Merges a new AstroCookies instance into the current instance. Any new cookies * will be added to the current instance, overwriting any existing cookies with the same name. */ merge(cookies) { const outgoing = cookies.#outgoing; if (outgoing) { for (const [key, value] of outgoing) { this.#ensureOutgoingMap().set(key, value); } } } /** * Astro.cookies.header() returns an iterator for the cookies that have previously * been set by either Astro.cookies.set() or Astro.cookies.delete(). * This method is primarily used by adapters to set the header on outgoing responses. * @returns */ *headers() { if (this.#outgoing == null) return; for (const [, value] of this.#outgoing) { yield value[1]; } } /** * Behaves the same as AstroCookies.prototype.headers(), * but allows a warning when cookies are set after the instance is consumed. */ static consume(cookies) { cookies.#consumed = true; return cookies.headers(); } #ensureParsed(options = void 0) { if (!this.#requestValues) { this.#parse(options); } if (!this.#requestValues) { this.#requestValues = {}; } return this.#requestValues; } #ensureOutgoingMap() { if (!this.#outgoing) { this.#outgoing = /* @__PURE__ */ new Map(); } return this.#outgoing; } #parse(options = void 0) { const raw = this.#request.headers.get("cookie"); if (!raw) { return; } this.#requestValues = parse_1(raw, options); } } const astroCookiesSymbol = Symbol.for("astro.cookies"); function attachCookiesToResponse(response, cookies) { Reflect.set(response, astroCookiesSymbol, cookies); } function getCookiesFromResponse(response) { let cookies = Reflect.get(response, astroCookiesSymbol); if (cookies != null) { return cookies; } else { return void 0; } } function* getSetCookiesFromResponse(response) { const cookies = getCookiesFromResponse(response); if (!cookies) { return []; } for (const headerValue of AstroCookies.consume(cookies)) { yield headerValue; } return []; } const dateTimeFormat = new Intl.DateTimeFormat([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false }); const levels = { debug: 20, info: 30, warn: 40, error: 50, silent: 90 }; function log$1(opts, level, label, message, newLine = true) { const logLevel = opts.level; const dest = opts.dest; const event = { label, level, message, newLine }; if (!isLogLevelEnabled(logLevel, level)) { return; } dest.write(event); } function isLogLevelEnabled(configuredLogLevel, level) { return levels[configuredLogLevel] <= levels[level]; } function info(opts, label, message, newLine = true) { return log$1(opts, "info", label, message, newLine); } function warn(opts, label, message, newLine = true) { return log$1(opts, "warn", label, message, newLine); } function error(opts, label, message, newLine = true) { return log$1(opts, "error", label, message, newLine); } function debug$2(...args) { if ("_astroGlobalDebug" in globalThis) { globalThis._astroGlobalDebug(...args); } } function getEventPrefix({ level, label }) { const timestamp = `${dateTimeFormat.format(/* @__PURE__ */ new Date())}`; const prefix = []; if (level === "error" || level === "warn") { prefix.push(bold(timestamp)); prefix.push(`[${level.toUpperCase()}]`); } else { prefix.push(timestamp); } if (label) { prefix.push(`[${label}]`); } if (level === "error") { return red(prefix.join(" ")); } if (level === "warn") { return yellow(prefix.join(" ")); } if (prefix.length === 1) { return dim(prefix[0]); } return dim(prefix[0]) + " " + blue(prefix.splice(1).join(" ")); } class Logger { options; constructor(options) { this.options = options; } info(label, message, newLine = true) { info(this.options, label, message, newLine); } warn(label, message, newLine = true) { warn(this.options, label, message, newLine); } error(label, message, newLine = true) { error(this.options, label, message, newLine); } debug(label, ...messages) { debug$2(label, ...messages); } level() { return this.options.level; } forkIntegrationLogger(label) { return new AstroIntegrationLogger(this.options, label); } } class AstroIntegrationLogger { options; label; constructor(logging, label) { this.options = logging; this.label = label; } /** * Creates a new logger instance with a new label, but the same log options. */ fork(label) { return new AstroIntegrationLogger(this.options, label); } info(message) { info(this.options, this.label, message); } warn(message) { warn(this.options, this.label, message); } error(message) { error(this.options, this.label, message); } debug(message) { debug$2(this.label, message); } } const consoleLogDestination = { write(event) { let dest = console.error; if (levels[event.level] < levels["error"]) { dest = console.log; } if (event.label === "SKIP_FORMAT") { dest(event.message); } else { dest(getEventPrefix(event) + " " + event.message); } return true; } }; const ACTION_API_CONTEXT_SYMBOL = Symbol.for("astro.actionAPIContext"); function hasActionPayload(locals) { return "_actionPayload" in locals; } function createGetActionResult(locals) { return (actionFn) => { if (!hasActionPayload(locals) || actionFn.toString() !== getActionQueryString(locals._actionPayload.actionName)) { return void 0; } return deserializeActionResult(locals._actionPayload.actionResult); }; } function createCallAction(context) { return (baseAction, input) => { Reflect.set(context, ACTION_API_CONTEXT_SYMBOL, true); const action = baseAction.bind(context); return action(input); }; } function parseLocale(header) { if (header === "*") { return [{ locale: header, qualityValue: void 0 }]; } const result = []; const localeValues = header.split(",").map((str) => str.trim()); for (const localeValue of localeValues) { const split = localeValue.split(";").map((str) => str.trim()); const localeName = split[0]; const qualityValue = split[1]; if (!split) { continue; } if (qualityValue && qualityValue.startsWith("q=")) { const qualityValueAsFloat = Number.parseFloat(qualityValue.slice("q=".length)); if (Number.isNaN(qualityValueAsFloat) || qualityValueAsFloat > 1) { result.push({ locale: localeName, qualityValue: void 0 }); } else { result.push({ locale: localeName, qualityValue: qualityValueAsFloat }); } } else { result.push({ locale: localeName, qualityValue: void 0 }); } } return result; } function sortAndFilterLocales(browserLocaleList, locales) { const normalizedLocales = toCodes(locales).map(normalizeTheLocale); return browserLocaleList.filter((browserLocale) => { if (browserLocale.locale !== "*") { return normalizedLocales.includes(normalizeTheLocale(browserLocale.locale)); } return true; }).sort((a, b) => { if (a.qualityValue && b.qualityValue) { return Math.sign(b.qualityValue - a.qualityValue); } return 0; }); } function computePreferredLocale(request, locales) { const acceptHeader = request.headers.get("Accept-Language"); let result = void 0; if (acceptHeader) { const browserLocaleList = sortAndFilterLocales(parseLocale(acceptHeader), locales); const firstResult = browserLocaleList.at(0); if (firstResult && firstResult.locale !== "*") { for (const currentLocale of locales) { if (typeof currentLocale === "string") { if (normalizeTheLocale(currentLocale) === normalizeTheLocale(firstResult.locale)) { result = currentLocale; } } else { for (const currentCode of currentLocale.codes) { if (normalizeTheLocale(currentCode) === normalizeTheLocale(firstResult.locale)) { result = currentLocale.path; } } } } } } return result; } function computePreferredLocaleList(request, locales) { const acceptHeader = request.headers.get("Accept-Language"); let result = []; if (acceptHeader) { const browserLocaleList = sortAndFilterLocales(parseLocale(acceptHeader), locales); if (browserLocaleList.length === 1 && browserLocaleList.at(0).locale === "*") { return locales.map((locale) => { if (typeof locale === "string") { return locale; } else { return locale.codes.at(0); } }); } else if (browserLocaleList.length > 0) { for (const browserLocale of browserLocaleList) { for (const loopLocale of locales) { if (typeof loopLocale === "string") { if (normalizeTheLocale(loopLocale) === normalizeTheLocale(browserLocale.locale)) { result.push(loopLocale); } } else { for (const code of loopLocale.codes) { if (code === browserLocale.locale) { result.push(loopLocale.path); } } } } } } } return result; } function computeCurrentLocale(pathname, locales, defaultLocale) { for (const segment of pathname.split("/")) { for (const locale of locales) { if (typeof locale === "string") { if (!segment.includes(locale)) continue; if (normalizeTheLocale(locale) === normalizeTheLocale(segment)) { return locale; } } else { if (locale.path === segment) { return locale.codes.at(0); } else { for (const code of locale.codes) { if (normalizeTheLocale(code) === normalizeTheLocale(segment)) { return code; } } } } } } for (const locale of locales) { if (typeof locale === "string") { if (locale === defaultLocale) { return locale; } } else { if (locale.path === defaultLocale) { return locale.codes.at(0); } } } } async function callMiddleware(onRequest, apiContext, responseFunction) { let nextCalled = false; let responseFunctionPromise = void 0; const next = async (payload) => { nextCalled = true; responseFunctionPromise = responseFunction(apiContext, payload); return responseFunctionPromise; }; let middlewarePromise = onRequest(apiContext, next); return await Promise.resolve(middlewarePromise).then(async (value) => { if (nextCalled) { if (typeof value !== "undefined") { if (value instanceof Response === false) { throw new AstroError(MiddlewareNotAResponse); } return value; } else { if (responseFunctionPromise) { return responseFunctionPromise; } else { throw new AstroError(MiddlewareNotAResponse); } } } else if (typeof value === "undefined") { throw new AstroError(MiddlewareNoDataOrNextCalled); } else if (value instanceof Response === false) { throw new AstroError(MiddlewareNotAResponse); } else { return value; } }); } const FORM_CONTENT_TYPES = [ "application/x-www-form-urlencoded", "multipart/form-data", "text/plain" ]; function createOriginCheckMiddleware() { return defineMiddleware((context, next) => { const { request, url } = context; if (request.method === "GET") { return next(); } const sameOrigin = (request.method === "POST" || request.method === "PUT" || request.method === "PATCH" || request.method === "DELETE") && request.headers.get("origin") === url.origin; const hasContentType = request.headers.has("content-type"); if (hasContentType) { const formLikeHeader = hasFormLikeHeader(request.headers.get("content-type")); if (formLikeHeader && !sameOrigin) { return new Response(`Cross-site ${request.method} form submissions are forbidden`, { status: 403 }); } } else { if (!sameOrigin) { return new Response(`Cross-site ${request.method} form submissions are forbidden`, { status: 403 }); } } return next(); }); } function hasFormLikeHeader(contentType) { if (contentType) { for (const FORM_CONTENT_TYPE of FORM_CONTENT_TYPES) { if (contentType.toLowerCase().includes(FORM_CONTENT_TYPE)) { return true; } } } return false; } const VALID_PARAM_TYPES = ["string", "number", "undefined"]; function validateGetStaticPathsParameter([key, value], route) { if (!VALID_PARAM_TYPES.includes(typeof value)) { throw new AstroError({ ...GetStaticPathsInvalidRouteParam, message: GetStaticPathsInvalidRouteParam.message(key, value, typeof value), location: { file: route } }); } } function validateDynamicRouteModule(mod, { ssr, route }) { if ((!ssr || route.prerender) && !mod.getStaticPaths) { throw new AstroError({ ...GetStaticPathsRequired, location: { file: route.component } }); } } function validateGetStaticPathsResult(result, logger, route) { if (!Array.isArray(result)) { throw new AstroError({ ...InvalidGetStaticPathsReturn, message: InvalidGetStaticPathsReturn.message(typeof result), location: { file: route.component } }); } result.forEach((pathObject) => { if (typeof pathObject === "object" && Array.isArray(pathObject) || pathObject === null) { throw new AstroError({ ...InvalidGetStaticPathsEntry, message: InvalidGetStaticPathsEntry.message( Array.isArray(pathObject) ? "array" : typeof pathObject ) }); } if (pathObject.params === void 0 || pathObject.params === null || pathObject.params && Object.keys(pathObject.params).length === 0) { throw new AstroError({ ...GetStaticPathsExpectedParams, location: { file: route.component } }); } for (const [key, val] of Object.entries(pathObject.params)) { if (!(typeof val === "undefined" || typeof val === "string" || typeof val === "number")) { logger.warn( "router", `getStaticPaths() returned an invalid path param: "${key}". A string, number or undefined value was expected, but got \`${JSON.stringify( val )}\`.` ); } if (typeof val === "string" && val === "") { logger.warn( "router", `getStaticPaths() returned an invalid path param: "${key}". \`undefined\` expected for an optional param, but got empty string.` ); } } }); } function stringifyParams(params, route) { const validatedParams = Object.entries(params).reduce((acc, next) => { validateGetStaticPathsParameter(next, route.component); const [key, value] = next; if (value !== void 0) { acc[key] = typeof value === "string" ? trimSlashes(value) : value.toString(); } return acc; }, {}); return route.generate(validatedParams); } function generatePaginateFunction(routeMatch) { return function paginateUtility(data, args = {}) { let { pageSize: _pageSize, params: _params, props: _props } = args; const pageSize = _pageSize || 10; const paramName = "page"; const additionalParams = _params || {}; const additionalProps = _props || {}; let includesFirstPageNumber; if (routeMatch.params.includes(`...${paramName}`)) { includesFirstPageNumber = false; } else if (routeMatch.params.includes(`${paramName}`)) { includesFirstPageNumber = true; } else { throw new AstroError({ ...PageNumberParamNotFound, message: PageNumberParamNotFound.message(paramName) }); } const lastPage = Math.max(1, Math.ceil(data.length / pageSize)); const result = [...Array(lastPage).keys()].map((num) => { const pageNum = num + 1; const start = pageSize === Infinity ? 0 : (pageNum - 1) * pageSize; const end = Math.min(start + pageSize, data.length); const params = { ...additionalParams, [paramName]: includesFirstPageNumber || pageNum > 1 ? String(pageNum) : void 0 }; const current = correctIndexRoute(routeMatch.generate({ ...params })); const next = pageNum === lastPage ? void 0 : correctIndexRoute(routeMatch.generate({ ...params, page: String(pageNum + 1) })); const prev = pageNum === 1 ? void 0 : correctIndexRoute( routeMatch.generate({ ...params, page: !includesFirstPageNumber && pageNum - 1 === 1 ? void 0 : String(pageNum - 1) }) ); const first = pageNum === 1 ? void 0 : correctIndexRoute( routeMatch.generate({ ...params, page: includesFirstPageNumber ? "1" : void 0 }) ); const last = pageNum === lastPage ? void 0 : correctIndexRoute(routeMatch.generate({ ...params, page: String(lastPage) })); return { params, props: { ...additionalProps, page: { data: data.slice(start, end), start, end: end - 1, size: pageSize, total: data.length, currentPage: pageNum, lastPage, url: { current, next, prev, first, last } } } }; }); return result; }; } function correctIndexRoute(route) { if (route === "") { return "/"; } return route; } async function callGetStaticPaths({ mod, route, routeCache, logger, ssr }) { const cached = routeCache.get(route); if (!mod) { throw new Error("This is an error caused by Astro and not your code. Please file an issue."); } if (cached?.staticPaths) { return cached.staticPaths; } validateDynamicRouteModule(mod, { ssr, route }); if (ssr && !route.prerender) { const entry = Object.assign([], { keyed: /* @__PURE__ */ new Map() }); routeCache.set(route, { ...cached, staticPaths: entry }); return entry; } let staticPaths = []; if (!mod.getStaticPaths) { throw new Error("Unexpected Error."); } staticPaths = await mod.getStaticPaths({ // Q: Why the cast? // A: So users downstream can have nicer typings, we have to make some sacrifice in our internal typings, which necessitate a cast here paginate: generatePaginateFunction(route) }); validateGetStaticPathsResult(staticPaths, logger, route); const keyedStaticPaths = staticPaths; keyedStaticPaths.keyed = /* @__PURE__ */ new Map(); for (const sp of keyedStaticPaths) { const paramsKey = stringifyParams(sp.params, route); keyedStaticPaths.keyed.set(paramsKey, sp); } routeCache.set(route, { ...cached, staticPaths: keyedStaticPaths }); return keyedStaticPaths; } class RouteCache { logger; cache = {}; mode; constructor(logger, mode = "production") { this.logger = logger; this.mode = mode; } /** Clear the cache. */ clearAll() { this.cache = {}; } set(route, entry) { const key = this.key(route); if (this.mode === "production" && this.cache[key]?.staticPaths) { this.logger.warn(null, `Internal Warning: route cache overwritten. (${key})`); } this.cache[key] = entry; } get(route) { return this.cache[this.key(route)]; } key(route) { return `${route.route}_${route.component}`; } } function findPathItemByKey(staticPaths, params, route, logger) { const paramsKey = stringifyParams(params, route); const matchedStaticPath = staticPaths.keyed.get(paramsKey); if (matchedStaticPath) { return matchedStaticPath; } logger.debug("router", `findPathItemByKey() - Unexpected cache miss looking for ${paramsKey}`); } function getPattern(segments, base, addTrailingSlash) { const pathname = segments.map((segment) => { if (segment.length === 1 && segment[0].spread) { return "(?:\\/(.*?))?"; } else { return "\\/" + segment.map((part) => { if (part.spread) { return "(.*?)"; } else if (part.dynamic) { return "([^/]+?)"; } else { return part.content.normalize().replace(/\?/g, "%3F").replace(/#/g, "%23").replace(/%5B/g, "[").replace(/%5D/g, "]").replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } }).join(""); } }).join(""); const trailing = addTrailingSlash && segments.length ? getTrailingSlashPattern(addTrailingSlash) : "$"; let initial = "\\/"; if (addTrailingSlash === "never" && base !== "/") { initial = ""; } return new RegExp(`^${pathname || initial}${trailing}`); } function getTrailingSlashPattern(addTrailingSlash) { if (addTrailingSlash === "always") { return "\\/$"; } if (addTrailingSlash === "never") { return "$"; } return "\\/?$"; } const SERVER_ISLAND_ROUTE = "/_server-islands/[name]"; const SERVER_ISLAND_COMPONENT = "_server-islands.astro"; function getServerIslandRouteData(config) { const segments = [ [{ content: "_server-islands", dynamic: false, spread: false }], [{ content: "name", dynamic: true, spread: false }] ]; const route = { type: "page", component: SERVER_ISLAND_COMPONENT, generate: () => "", params: ["name"], segments, pattern: getPattern(segments, config.base, config.trailingSlash), prerender: false, isIndex: false, fallbackRoutes: [], route: SERVER_ISLAND_ROUTE }; return route; } function ensureServerIslandRoute(config, routeManifest) { if (routeManifest.routes.some((route) => route.route === "/_server-islands/[name]")) { return; } routeManifest.routes.unshift(getServerIslandRouteData(config)); } function createEndpoint(manifest) { const page = async (result) => { const params = result.params; const request = result.request; const raw = await request.text(); const data = JSON.parse(raw); if (!params.name) { return new Response(null, { status: 400, statusText: "Bad request" }); } const componentId = params.name; const imp = manifest.serverIslandMap?.get(componentId); if (!imp) { return new Response(null, { status: 404, statusText: "Not found" }); } const key = await manifest.key; const encryptedProps = data.encryptedProps; const propString = await decryptString(key, encryptedProps); const props = JSON.parse(propString); const componentModule = await imp(); const Component = componentModule[data.componentExport]; const slots = {}; for (const prop in data.slots) { slots[prop] = createSlotValueFromString(data.slots[prop]); } return renderTemplate`${renderComponent(result, "Component", Component, props, slots)}`; }; page.isAstroComponentFactory = true; const instance = { default: page, partial: true }; return instance; } function injectDefaultRoutes(ssrManifest, routeManifest) { ensure404Route(routeManifest); ensureServerIslandRoute(ssrManifest, routeManifest); return routeManifest; } function createDefaultRoutes(manifest) { const root = new URL(manifest.hrefRoot); return [ { instance: default404Instance, matchesComponent: (filePath) => filePath.href === new URL(DEFAULT_404_COMPONENT, root).href, route: DEFAULT_404_ROUTE.route, component: DEFAULT_404_COMPONENT }, { instance: createEndpoint(manifest), matchesComponent: (filePath) => filePath.href === new URL(SERVER_ISLAND_COMPONENT, root).href, route: SERVER_ISLAND_ROUTE, component: SERVER_ISLAND_COMPONENT } ]; } class Pipeline { constructor(logger, manifest, mode, renderers, resolve, serverLike, streaming, adapterName = manifest.adapterName, clientDirectives = manifest.clientDirectives, inlinedScripts = manifest.inlinedScripts, compressHTML = manifest.compressHTML, i18n = manifest.i18n, middleware = manifest.middleware, routeCache = new RouteCache(logger, mode), site = manifest.site ? new URL(manifest.site) : void 0, defaultRoutes = createDefaultRoutes(manifest)) { this.logger = logger; this.manifest = manifest; this.mode = mode; this.renderers = renderers; this.resolve = resolve; this.serverLike = serverLike; this.streaming = streaming; this.adapterName = adapterName; this.clientDirectives = clientDirectives; this.inlinedScripts = inlinedScripts; this.compressHTML = compressHTML; this.i18n = i18n; this.middleware = middleware; this.routeCache = routeCache; this.site = site; this.defaultRoutes = defaultRoutes; this.internalMiddleware = []; if (i18n?.strategy !== "manual") { this.internalMiddleware.push( createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat) ); } } internalMiddleware; resolvedMiddleware = void 0; /** * Resolves the middleware from the manifest, and returns the `onRequest` function. If `onRequest` isn't there, * it returns a no-op function */ async getMiddleware() { if (this.resolvedMiddleware) { return this.resolvedMiddleware; } else if (this.middleware) { const middlewareInstance = await this.middleware(); const onRequest = middlewareInstance.onRequest ?? NOOP_MIDDLEWARE_FN; if (this.manifest.checkOrigin) { this.resolvedMiddleware = sequence(createOriginCheckMiddleware(), onRequest); } else { this.resolvedMiddleware = onRequest; } return this.resolvedMiddleware; } else { this.resolvedMiddleware = NOOP_MIDDLEWARE_FN; return this.resolvedMiddleware; } } } function routeIsRedirect(route) { return route?.type === "redirect"; } function routeIsFallback(route) { return route?.type === "fallback"; } const RedirectComponentInstance = { default() { return new Response(null, { status: 301 }); } }; const RedirectSinglePageBuiltModule = { page: () => Promise.resolve(RedirectComponentInstance), onRequest: (_, next) => next(), renderers: [] }; async function renderRedirect(renderContext) { const { request: { method }, routeData } = renderContext; const { redirect, redirectRoute } = routeData; const status = redirectRoute && typeof redirect === "object" ? redirect.status : method === "GET" ? 301 : 308; const headers = { location: encodeURI(redirectRouteGenerate(renderContext)) }; return new Response(null, { status, headers }); } function redirectRouteGenerate(renderContext) { const { params, routeData: { redirect, redirectRoute } } = renderContext; if (typeof redirectRoute !== "undefined") { return redirectRoute?.generate(params) || redirectRoute?.pathname || "/"; } else if (typeof redirect === "string") { let target = redirect; for (const param of Object.keys(params)) { cons