@isikk/core 0.3.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/configError-BtEWY-oE.d.ts +79 -0
- package/dist/hooks/index.cjs +18 -10
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +18 -10
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +7 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/next/config/browser.d.ts +6 -4
- package/dist/next/config/browser.js +63 -6
- package/dist/next/config/browser.js.map +1 -1
- package/dist/next/config/index.d.ts +7 -13
- package/dist/next/config/index.js +66 -9
- package/dist/next/config/index.js.map +1 -1
- package/dist/next/middleware/index.cjs.map +1 -1
- package/dist/next/middleware/index.js.map +1 -1
- package/dist/node/index.cjs +4 -3
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.js +4 -3
- package/dist/node/index.js.map +1 -1
- package/package.json +6 -2
- package/dist/shared-By0kkXDs.d.ts +0 -31
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/index.ts","../src/arrays/index.ts","../src/functions/index.ts","../src/objects/index.ts","../src/strings/index.ts","../src/dates/_format.ts","../src/dates/index.ts","../src/files/index.ts","../src/cookies/index.ts","../src/console/index.ts","../src/colors/index.ts"],"sourcesContent":["export const getKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>\n\nexport type RecursivePartial<T> = { [P in keyof T]?: RecursivePartial<T[P]> }\n\nexport type RecursiveRecord = {\n [key: string]: string | number | boolean | RecursiveRecord | Array<RecursiveRecord>\n}\n\nexport function forcedType<T>(obj: unknown): T {\n return obj as unknown as T\n}\n","export function notNone<T>(value: T | null | undefined): value is T {\n return value !== null && value !== undefined\n}\n\nfunction combinationsOfSize<T>(items: T[], size: number): T[][] {\n if (size === 0) {\n return [[]]\n }\n if (size > items.length) {\n return []\n }\n const [first, ...rest] = items\n const withFirst = combinationsOfSize(rest, size - 1).map((combination) => [first, ...combination])\n const withoutFirst = combinationsOfSize(rest, size)\n return [...withFirst, ...withoutFirst]\n}\n\nexport function allCombinations<T>(options: T[]): T[][] {\n const result: T[][] = []\n for (let size = 1; size <= options.length; size++) {\n result.push(...combinationsOfSize(options, size))\n }\n return result\n}\n","export function withAttributes<Fn extends (...args: never[]) => unknown, Attrs extends Record<string, unknown>>(\n fn: Fn,\n attributes: Attrs\n): Fn & Attrs {\n for (const key of Object.keys(attributes)) {\n // Object.defineProperty (unlike a plain `fn[key] = value` assignment) always creates/\n // overwrites an own property, even when key is \"__proto__\" - a plain assignment would instead\n // be intercepted by Object.prototype's special __proto__ accessor and reassign fn's own\n // prototype instead of setting a property on it.\n Object.defineProperty(fn, key, {\n value: attributes[key],\n writable: true,\n configurable: true,\n enumerable: true,\n })\n }\n return fn as Fn & Attrs\n}\n\nexport function makeCallable<T, R>(originalCallable: (arg: T) => R) {\n return (data: T) => () => originalCallable(data)\n}\n\nexport function getLazyValue<T>(input: T | (() => T)): T {\n if (typeof input === 'function') {\n return (input as () => T)()\n }\n return input\n}\n\nexport async function getLazyValueAsync<T>(input: T | (() => Promise<T>) | (() => T)): Promise<T> {\n if (typeof input === 'function') {\n const result = (input as () => Promise<T>)()\n if (result instanceof Promise) {\n return await result\n }\n return result as unknown as T\n }\n return input\n}\n\nexport function suppress<T, ERT>(\n exceptions: Array<new (message?: string) => Error>,\n fn: () => T,\n onError?: (error: unknown) => ERT\n): T | ERT | undefined {\n try {\n return fn()\n } catch (error) {\n if (exceptions.some((exception) => error instanceof exception)) {\n return onError ? onError(error) : undefined\n }\n throw error\n }\n}\n\nexport function preventDefault<E extends Event, R>(callable: (event: E) => R): (event: E) => Promise<Awaited<R>> {\n return async function (event: E): Promise<Awaited<R>> {\n event.preventDefault()\n return await callable(event)\n }\n}\n\nexport function isPathMatched(pathname: string, pattern: RegExp, exemptPatterns: RegExp[] = []): boolean {\n if (exemptPatterns.some((exempt) => exempt.test(pathname))) {\n return false\n }\n return pattern.test(pathname)\n}\n\nexport function raises(error: Error): (...args: unknown[]) => never {\n return () => {\n throw error\n }\n}\n\nexport function cloned<Fn extends (...args: never[]) => unknown>(fn: Fn): Fn {\n return ((...args: Parameters<Fn>) => fn(...args)) as Fn\n}\n\nexport function enabledIf<R>(condition: boolean | (() => boolean), options: { ifNotEnabledReturnValue: R }) {\n const enabled = typeof condition === 'function' ? condition() : condition\n\n return function <Fn extends (...args: never[]) => R>(fn: Fn): Fn {\n if (!enabled) {\n return cloned((() => options.ifNotEnabledReturnValue) as Fn)\n }\n return cloned(fn)\n }\n}\n\nexport function transformExceptions<E extends Error>(\n exceptionTypes: Array<new (...args: never[]) => E>,\n transform: (error: E) => Error,\n options: { keepOriginal?: boolean } = {}\n) {\n const { keepOriginal = true } = options\n\n return function <Fn extends (...args: never[]) => unknown>(fn: Fn): Fn {\n return ((...args: Parameters<Fn>) => {\n try {\n return fn(...args)\n } catch (error) {\n if (!exceptionTypes.some((ExceptionType) => error instanceof ExceptionType)) {\n throw error\n }\n const newError = transform(error as E)\n if (keepOriginal) {\n newError.cause = error\n }\n throw newError\n }\n }) as Fn\n }\n}\n","export function checkRequiredKeys<T extends Record<string, unknown>, C extends Record<string, Array<keyof T>>>(\n obj: T,\n conditions: C\n): keyof C {\n const matchingConditions = Object.entries(conditions).filter(\n ([, keys]) =>\n keys.every((key) => obj[key] !== undefined) &&\n Object.keys(obj).every((key) => keys.includes(key as keyof T) || obj[key] === undefined)\n )\n\n if (matchingConditions.length !== 1) {\n throw new Error(`Object keys do not match exactly one required condition. ${JSON.stringify(conditions)}`)\n }\n\n return matchingConditions[0][0] as keyof C\n}\n\nexport function requireExclusiveKeys<T extends Record<string, unknown>, C extends Record<string, Array<keyof T>>>(\n conditions: C,\n options: { allowEmpty?: boolean } = {}\n) {\n const conditionEntries = Object.entries(conditions) as Array<[string, Array<keyof T>]>\n if (conditionEntries.length === 0) {\n throw new Error('At least one condition must be provided.')\n }\n const { allowEmpty = false } = options\n const governedKeys = new Set(conditionEntries.flatMap(([, keys]) => keys))\n\n return function <Fn extends (arg: T) => unknown>(fn: Fn): Fn {\n return ((arg: T) => {\n // Only keys that are actually governed by a condition are considered - unlike\n // checkRequiredKeys, any other key on `arg` is fully unconstrained and ignored here\n // regardless of its value, since this is meant to validate one options object that may\n // legitimately carry other, unrelated fields alongside the mutually-exclusive ones.\n const provided = new Set(\n Object.keys(arg).filter((key) => governedKeys.has(key as keyof T) && arg[key] !== undefined)\n )\n\n if (allowEmpty && provided.size === 0) {\n return fn(arg)\n }\n\n const matches = conditionEntries.filter(\n ([, keys]) => keys.length === provided.size && keys.every((key) => provided.has(key as string))\n )\n if (matches.length !== 1) {\n throw new Error(`Object keys do not match exactly one required condition. ${JSON.stringify(conditions)}`)\n }\n return fn(arg)\n }) as Fn\n }\n}\n\nexport function setKeyValueToObjectIfValue(key: string, value: unknown, object: Record<string, unknown>) {\n if (value) {\n // Object.defineProperty (unlike a plain `object[key] = value` assignment) always creates/\n // overwrites an own property, even when key is \"__proto__\" - a plain assignment would instead\n // be intercepted by Object.prototype's special __proto__ accessor and reassign this object's\n // prototype instead of setting a property on it.\n Object.defineProperty(object, key, { value, writable: true, configurable: true, enumerable: true })\n }\n}\n","export function slugify(value: string, allowUnicode: boolean = false): string {\n if (allowUnicode) {\n value = value.normalize('NFKC').replace(/[^\\p{L}\\p{N}_\\s-]/gu, '')\n } else {\n value = value\n .normalize('NFKD')\n // eslint-disable-next-line no-control-regex\n .replace(/[^\\x00-\\x7F]/g, '')\n .replace(/[\\r\\n]+/g, ' ')\n .trim()\n .replace(/[^\\w\\s-]/g, '')\n }\n\n value = value.toLowerCase()\n\n return value.replace(/[-\\s]+/g, '-').replace(/^[-_]+|[-_]+$/g, '')\n}\n","import { format } from 'date-fns'\n\nexport function formatDate(date: Date, pattern: string): string {\n return format(date, pattern)\n}\n","import { formatDate } from './_format'\n\nexport const LONG_DATE_FORMAT = \"EEEE, MMMM dd, yyyy 'at' hh:mm a\"\nexport const SHORT_DATE_FORMAT = 'dd.MM.yyyy'\nexport const SHORT_DATETIME_FORMAT = 'dd.MM.yyyy HH:mm a'\n\nexport function formattedDate(pattern: string, date: Date = new Date()): string {\n return formatDate(date, pattern)\n}\n\nexport function longFormattedDate(date: Date = new Date()): string {\n return formattedDate(LONG_DATE_FORMAT, date)\n}\n\nexport function shortFormattedDate(date: Date = new Date()): string {\n return formattedDate(SHORT_DATE_FORMAT, date)\n}\n\nexport function shortFormattedDateTime(date: Date = new Date()): string {\n return formattedDate(SHORT_DATETIME_FORMAT, date)\n}\n\nexport function optionalDate(date?: string): Date | undefined {\n return date ? new Date(date) : undefined\n}\n","type MimeType = 'image/png' | 'image/jpeg' | 'image/webp'\n\nexport function guessImageMimeType(filename: string): MimeType {\n const withoutQueryOrHash = filename.split(/[?#]/)[0]\n const extension = withoutQueryOrHash.split('.').pop()?.toLowerCase()\n switch (extension) {\n case 'png':\n return 'image/png'\n case 'jfif':\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg'\n case 'webp':\n return 'image/webp'\n default:\n return 'image/png'\n }\n}\n\nexport function isImageMimeType(mimeType: string): mimeType is MimeType {\n return mimeType === 'image/png' || mimeType === 'image/jpeg' || mimeType === 'image/webp'\n}\n\nexport function escapeName(name: string): string {\n return name.replace(/[^a-zA-Z0-9-_.]/g, '_')\n}\n\nexport function safeFileName(filename: string, maxLength: number = 255): string {\n if (filename.length <= maxLength) return filename\n\n const dotIndex = filename.lastIndexOf('.')\n const hasExtension = dotIndex > 0\n const extension = escapeName(hasExtension ? filename.slice(dotIndex) : '')\n const name = escapeName(hasExtension ? filename.slice(0, dotIndex) : filename)\n\n return name.slice(0, Math.max(0, maxLength - extension.length)) + extension\n}\n\nexport async function downloadAndFormatImage(\n src: string,\n name: string = 'image.png',\n mimeType: MimeType = guessImageMimeType(name),\n quality: number = 1\n): Promise<void> {\n name = safeFileName(name)\n try {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n\n await new Promise((resolve, reject) => {\n img.onload = resolve\n img.onerror = reject\n img.src = src\n })\n\n const canvas = document.createElement('canvas')\n canvas.width = img.width\n canvas.height = img.height\n const ctx = canvas.getContext('2d')\n\n if (!ctx) {\n throw new Error('Could not get canvas context')\n }\n\n ctx.drawImage(img, 0, 0)\n\n const blob = await new Promise<Blob | null>((resolve) => {\n canvas.toBlob(resolve, mimeType, quality)\n })\n\n if (!blob) {\n throw new Error('Could not generate blob')\n }\n\n const link = document.createElement('a')\n const downloadUrl = URL.createObjectURL(blob)\n try {\n link.href = downloadUrl\n link.download = name\n document.body.appendChild(link)\n link.click()\n } finally {\n document.body.removeChild(link)\n URL.revokeObjectURL(downloadUrl)\n }\n } catch (error) {\n console.error('Failed to download image:', error)\n }\n}\n\nexport async function fileToBase64Native(file: File): Promise<string> {\n const result = await new Promise<string | ArrayBuffer | null>((resolve, reject) => {\n const reader = new FileReader()\n reader.readAsDataURL(file)\n reader.onload = () => resolve(reader.result)\n reader.onerror = (error) => reject(error)\n })\n\n if (typeof result === 'string') {\n return result\n } else {\n throw new Error('Failed to read file as Data URL')\n }\n}\n\nexport async function fileToBase64(file: File, quality: number = 1): Promise<string> {\n if (isImageMimeType(file.type)) {\n const img = new Image()\n const url = URL.createObjectURL(file)\n try {\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve()\n img.onerror = () => reject(new Error('Failed to load image for metadata removal'))\n img.src = url\n })\n\n const canvas = document.createElement('canvas')\n canvas.width = img.width\n canvas.height = img.height\n\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n throw new Error('Failed to get canvas context')\n }\n ctx.drawImage(img, 0, 0)\n\n const cleanDataUrl = canvas.toDataURL(file.type, quality)\n if (cleanDataUrl === 'data:,') {\n return await fileToBase64Native(file)\n }\n\n return cleanDataUrl\n } finally {\n URL.revokeObjectURL(url)\n }\n } else {\n return await fileToBase64Native(file)\n }\n}\n","export function getCookie(name: string): string | undefined {\n for (const pair of document.cookie.split('; ')) {\n const separatorIndex = pair.indexOf('=')\n if (separatorIndex === -1) {\n continue\n }\n if (pair.slice(0, separatorIndex) === name) {\n return pair.slice(separatorIndex + 1)\n }\n }\n return undefined\n}\n\nexport interface SetCookieOptions {\n /** Days until the cookie expires. Omit for a session cookie (cleared when the browser closes). */\n days?: number\n path?: string\n}\n\nexport function setCookie(name: string, value: string, options: SetCookieOptions = {}): void {\n const { days, path = '/' } = options\n const expires = days === undefined ? '' : `; expires=${new Date(Date.now() + days * 86_400_000).toUTCString()}`\n document.cookie = `${name}=${value}${expires}; path=${path}`\n}\n\nexport function removeCookie(name: string, path: string = '/'): void {\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}`\n}\n","type ConsoleMethod = (...args: unknown[]) => void\ntype WindowLike = Window & typeof globalThis\n\nconst patchedWindows = new WeakMap<WindowLike, Set<string>>()\n\nexport function createConsoleDebugSwitch(targetWindow: WindowLike, options: { namespace: string }): void {\n if (!targetWindow) {\n return\n }\n\n const { namespace } = options\n\n let enabledNamespaces = patchedWindows.get(targetWindow)\n if (!enabledNamespaces) {\n enabledNamespaces = new Set<string>()\n patchedWindows.set(targetWindow, enabledNamespaces)\n\n const original = {\n log: targetWindow.console.log.bind(targetWindow.console),\n info: targetWindow.console.info.bind(targetWindow.console),\n warn: targetWindow.console.warn.bind(targetWindow.console),\n error: targetWindow.console.error.bind(targetWindow.console),\n }\n\n const conditional =\n (method: ConsoleMethod): ConsoleMethod =>\n (...args) => {\n if (enabledNamespaces!.size > 0) {\n method(...args)\n }\n }\n\n targetWindow.console.log = conditional(original.log)\n targetWindow.console.info = conditional(original.info)\n targetWindow.console.warn = conditional(original.warn)\n targetWindow.console.error = conditional(original.error)\n }\n\n type Namespace = { debug: (enabled: boolean) => void }\n const globals = targetWindow as unknown as Record<string, Namespace | undefined>\n const existing = Object.prototype.hasOwnProperty.call(globals, namespace)\n ? (Object.getOwnPropertyDescriptor(globals, namespace)?.value as Namespace | undefined)\n : undefined\n const target = existing ?? ({} as Namespace)\n target.debug = (flag: boolean) => {\n if (flag) {\n enabledNamespaces!.add(namespace)\n } else {\n enabledNamespaces!.delete(namespace)\n }\n }\n // Object.defineProperty (unlike a plain `globals[namespace] = target` assignment) always\n // creates/overwrites an own property, even when namespace is a name like \"__proto__\" that\n // would otherwise be intercepted by Object.prototype's special __proto__ accessor and\n // pollute the shared prototype instead of setting a property on this specific object.\n Object.defineProperty(globals, namespace, { value: target, writable: true, configurable: true, enumerable: true })\n}\n","export type TailwindShade = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950\n\nexport type TailwindColorScale = Record<TailwindShade, string>\n\ninterface Rgb {\n r: number\n g: number\n b: number\n}\n\nconst HEX_PATTERN = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i\n\nfunction hexToRgb(hex: string): Rgb {\n const match = HEX_PATTERN.exec(hex.trim())\n if (!match) {\n throw new Error(`Invalid hex color: \"${hex}\"`)\n }\n\n const digits = match[1]\n const normalized =\n digits.length === 3\n ? digits\n .split('')\n .map((char) => char + char)\n .join('')\n : digits\n\n return {\n r: parseInt(normalized.slice(0, 2), 16),\n g: parseInt(normalized.slice(2, 4), 16),\n b: parseInt(normalized.slice(4, 6), 16),\n }\n}\n\nfunction rgbToHex({ r, g, b }: Rgb): string {\n return `#${[r, g, b].map((channel) => Math.round(channel).toString(16).padStart(2, '0')).join('')}`\n}\n\nfunction mixRgb(base: Rgb, target: Rgb, weight: number): Rgb {\n return {\n r: base.r + (target.r - base.r) * weight,\n g: base.g + (target.g - base.g) * weight,\n b: base.b + (target.b - base.b) * weight,\n }\n}\n\nconst WHITE: Rgb = { r: 255, g: 255, b: 255 }\nconst BLACK: Rgb = { r: 0, g: 0, b: 0 }\n\n// Weight of white/black mixed into the base color at each shade, tuned so 500 is the input\n// color unchanged and the rest approximate the spread of Tailwind's own default palettes.\nconst TINT_WEIGHTS: Record<50 | 100 | 200 | 300 | 400, number> = { 50: 0.95, 100: 0.9, 200: 0.75, 300: 0.6, 400: 0.3 }\nconst SHADE_WEIGHTS: Record<600 | 700 | 800 | 900 | 950, number> = {\n 600: 0.15,\n 700: 0.3,\n 800: 0.45,\n 900: 0.6,\n 950: 0.8,\n}\n\n/**\n * Generates a Tailwind-style 50-950 color scale from a single base hex color, treated as the 500 shade.\n */\nexport function generateTailwindColorScale(baseColor: string): TailwindColorScale {\n const base = hexToRgb(baseColor)\n\n return {\n 50: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[50])),\n 100: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[100])),\n 200: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[200])),\n 300: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[300])),\n 400: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[400])),\n 500: rgbToHex(base),\n 600: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[600])),\n 700: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[700])),\n 800: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[800])),\n 900: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[900])),\n 950: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[950])),\n }\n}\n\n/**\n * Like {@link generateTailwindColorScale}, but prefixes each shade with `name` (e.g. `primary500`)\n * so multiple scales can be spread into one flat palette object.\n */\nexport function generateNamedTailwindColorScale<T extends string>(\n baseColor: string,\n name: T\n): Record<`${T}${TailwindShade}`, string> {\n const scale = generateTailwindColorScale(baseColor)\n\n return Object.fromEntries(Object.entries(scale).map(([shade, hex]) => [`${name}${shade}`, hex])) as Record<\n `${T}${TailwindShade}`,\n string\n >\n}\n\nfunction rgbToHsl({ r, g, b }: Rgb): { h: number; s: number; l: number } {\n const rN = r / 255\n const gN = g / 255\n const bN = b / 255\n\n const max = Math.max(rN, gN, bN)\n const min = Math.min(rN, gN, bN)\n const l = (max + min) / 2\n\n if (max === min) {\n return { h: 0, s: 0, l: l * 100 }\n }\n\n const delta = max - min\n const s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min)\n\n let h: number\n if (max === rN) {\n h = ((gN - bN) / delta + (gN < bN ? 6 : 0)) * 60\n } else if (max === gN) {\n h = ((bN - rN) / delta + 2) * 60\n } else {\n h = ((rN - gN) / delta + 4) * 60\n }\n\n return { h, s: s * 100, l: l * 100 }\n}\n\n/**\n * Formats a hex color as the \"H S% L%\" triplet shadcn/Tailwind CSS variable themes expect,\n * e.g. for `--primary: 240 5.9% 10%;` consumed as `hsl(var(--primary))`.\n */\nexport function hexToHslTriplet(hex: string, precision: number = 1): string {\n const { h, s, l } = rgbToHsl(hexToRgb(hex))\n const round = (value: number) => Number(value.toFixed(precision))\n\n return `${round(h)} ${round(s)}% ${round(l)}%`\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types/index.ts","../src/arrays/index.ts","../src/functions/index.ts","../src/objects/index.ts","../src/strings/index.ts","../src/dates/_format.ts","../src/dates/index.ts","../src/files/index.ts","../src/cookies/index.ts","../src/console/index.ts","../src/colors/index.ts"],"sourcesContent":["export const getKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>\n\nexport type RecursivePartial<T> = { [P in keyof T]?: RecursivePartial<T[P]> }\n\nexport type RecursiveRecord = {\n [key: string]: string | number | boolean | RecursiveRecord | Array<RecursiveRecord>\n}\n\nexport function forcedType<T>(obj: unknown): T {\n return obj as unknown as T\n}\n","export function notNone<T>(value: T | null | undefined): value is T {\n return value !== null && value !== undefined\n}\n\nfunction combinationsOfSize<T>(items: T[], size: number): T[][] {\n if (size === 0) {\n return [[]]\n }\n if (size > items.length) {\n return []\n }\n const [first, ...rest] = items\n const withFirst = combinationsOfSize(rest, size - 1).map((combination) => [first, ...combination])\n const withoutFirst = combinationsOfSize(rest, size)\n return [...withFirst, ...withoutFirst]\n}\n\nexport function allCombinations<T>(options: T[]): T[][] {\n const result: T[][] = []\n for (let size = 1; size <= options.length; size++) {\n result.push(...combinationsOfSize(options, size))\n }\n return result\n}\n","export function withAttributes<Fn extends (...args: never[]) => unknown, Attrs extends Record<string, unknown>>(\n fn: Fn,\n attributes: Attrs\n): Fn & Attrs {\n for (const key of Object.keys(attributes)) {\n // Object.defineProperty (unlike a plain `fn[key] = value` assignment) always creates/\n // overwrites an own property, even when key is \"__proto__\" - a plain assignment would instead\n // be intercepted by Object.prototype's special __proto__ accessor and reassign fn's own\n // prototype instead of setting a property on it.\n Object.defineProperty(fn, key, {\n value: attributes[key],\n writable: true,\n configurable: true,\n enumerable: true,\n })\n }\n return fn as Fn & Attrs\n}\n\nexport function makeCallable<T, R>(originalCallable: (arg: T) => R) {\n return (data: T) => () => originalCallable(data)\n}\n\nexport function getLazyValue<T>(input: T | (() => T)): T {\n if (typeof input === 'function') {\n return (input as () => T)()\n }\n return input\n}\n\nexport async function getLazyValueAsync<T>(input: T | (() => Promise<T>) | (() => T)): Promise<T> {\n if (typeof input === 'function') {\n const result = (input as () => Promise<T>)()\n // Stryker disable next-line ConditionalExpression,BlockStatement: equivalent mutant. An async\n // function auto-adopts a returned thenable through the same resolution algorithm `await`\n // uses, so `return result` here resolves to the same value as `return await result` - the\n // only difference is an extra microtask tick, which isn't part of this function's contract.\n if (result instanceof Promise) {\n return await result\n }\n return result as unknown as T\n }\n return input\n}\n\nexport function suppress<T, ERT>(\n exceptions: Array<new (message?: string) => Error>,\n fn: () => T,\n onError?: (error: unknown) => ERT\n): T | ERT | undefined {\n try {\n return fn()\n } catch (error) {\n if (exceptions.some((exception) => error instanceof exception)) {\n return onError ? onError(error) : undefined\n }\n throw error\n }\n}\n\nexport function preventDefault<E extends Event, R>(callable: (event: E) => R): (event: E) => Promise<Awaited<R>> {\n return async function (event: E): Promise<Awaited<R>> {\n event.preventDefault()\n return await callable(event)\n }\n}\n\nexport function isPathMatched(pathname: string, pattern: RegExp, exemptPatterns: RegExp[] = []): boolean {\n if (exemptPatterns.some((exempt) => exempt.test(pathname))) {\n return false\n }\n return pattern.test(pathname)\n}\n\nexport function raises(error: Error): (...args: unknown[]) => never {\n return () => {\n throw error\n }\n}\n\nexport function cloned<Fn extends (...args: never[]) => unknown>(fn: Fn): Fn {\n return ((...args: Parameters<Fn>) => fn(...args)) as Fn\n}\n\nexport function enabledIf<R>(condition: boolean | (() => boolean), options: { ifNotEnabledReturnValue: R }) {\n const enabled = typeof condition === 'function' ? condition() : condition\n\n return function <Fn extends (...args: never[]) => R>(fn: Fn): Fn {\n if (!enabled) {\n return cloned((() => options.ifNotEnabledReturnValue) as Fn)\n }\n return cloned(fn)\n }\n}\n\nexport function transformExceptions<E extends Error>(\n exceptionTypes: Array<new (...args: never[]) => E>,\n transform: (error: E) => Error,\n options: { keepOriginal?: boolean } = {}\n) {\n const { keepOriginal = true } = options\n\n return function <Fn extends (...args: never[]) => unknown>(fn: Fn): Fn {\n return ((...args: Parameters<Fn>) => {\n try {\n return fn(...args)\n } catch (error) {\n if (!exceptionTypes.some((ExceptionType) => error instanceof ExceptionType)) {\n throw error\n }\n const newError = transform(error as E)\n if (keepOriginal) {\n newError.cause = error\n }\n throw newError\n }\n }) as Fn\n }\n}\n","export function checkRequiredKeys<T extends Record<string, unknown>, C extends Record<string, Array<keyof T>>>(\n obj: T,\n conditions: C\n): keyof C {\n const matchingConditions = Object.entries(conditions).filter(\n ([, keys]) =>\n keys.every((key) => obj[key] !== undefined) &&\n Object.keys(obj).every((key) => keys.includes(key as keyof T) || obj[key] === undefined)\n )\n\n if (matchingConditions.length !== 1) {\n throw new Error(`Object keys do not match exactly one required condition. ${JSON.stringify(conditions)}`)\n }\n\n return matchingConditions[0][0] as keyof C\n}\n\nexport function requireExclusiveKeys<T extends Record<string, unknown>, C extends Record<string, Array<keyof T>>>(\n conditions: C,\n options: { allowEmpty?: boolean } = {}\n) {\n const conditionEntries = Object.entries(conditions) as Array<[string, Array<keyof T>]>\n if (conditionEntries.length === 0) {\n throw new Error('At least one condition must be provided.')\n }\n const { allowEmpty = false } = options\n const governedKeys = new Set(conditionEntries.flatMap(([, keys]) => keys))\n\n return function <Fn extends (arg: T) => unknown>(fn: Fn): Fn {\n return ((arg: T) => {\n // Only keys that are actually governed by a condition are considered - unlike\n // checkRequiredKeys, any other key on `arg` is fully unconstrained and ignored here\n // regardless of its value, since this is meant to validate one options object that may\n // legitimately carry other, unrelated fields alongside the mutually-exclusive ones.\n const provided = new Set(\n Object.keys(arg).filter((key) => governedKeys.has(key as keyof T) && arg[key] !== undefined)\n )\n\n if (allowEmpty && provided.size === 0) {\n return fn(arg)\n }\n\n const matches = conditionEntries.filter(\n ([, keys]) => keys.length === provided.size && keys.every((key) => provided.has(key as string))\n )\n if (matches.length !== 1) {\n throw new Error(`Object keys do not match exactly one required condition. ${JSON.stringify(conditions)}`)\n }\n return fn(arg)\n }) as Fn\n }\n}\n\nexport function setKeyValueToObjectIfValue(key: string, value: unknown, object: Record<string, unknown>) {\n if (value) {\n // Object.defineProperty (unlike a plain `object[key] = value` assignment) always creates/\n // overwrites an own property, even when key is \"__proto__\" - a plain assignment would instead\n // be intercepted by Object.prototype's special __proto__ accessor and reassign this object's\n // prototype instead of setting a property on it.\n Object.defineProperty(object, key, { value, writable: true, configurable: true, enumerable: true })\n }\n}\n","export function slugify(value: string, allowUnicode: boolean = false): string {\n if (allowUnicode) {\n value = value.normalize('NFKC').replace(/[^\\p{L}\\p{N}_\\s-]/gu, '')\n } else {\n value = value.normalize('NFKD')\n // eslint-disable-next-line no-control-regex\n value = value.replace(/[^\\x00-\\x7F]/g, '')\n // Stryker disable next-line Regex: equivalent mutant. The `+` quantifier is redundant with\n // the `[-\\s]+` -> '-' collapse below, which flattens a run of replaced newlines to a single\n // dash regardless of how many spaces this leaves - kept for clarity/intent, not correctness.\n value = value.replace(/[\\r\\n]+/g, ' ')\n // Stryker disable next-line MethodExpression: equivalent mutant. Redundant with the collapse\n // + trim below, which strips any whitespace this would have removed once it's converted to\n // leading/trailing dashes - kept for clarity/intent, not correctness.\n value = value.trim()\n value = value.replace(/[^\\w\\s-]/g, '')\n }\n\n value = value.toLowerCase()\n\n return value.replace(/[-\\s]+/g, '-').replace(/^[-_]+|[-_]+$/g, '')\n}\n","import { format } from 'date-fns'\n\nexport function formatDate(date: Date, pattern: string): string {\n return format(date, pattern)\n}\n","import { formatDate } from './_format'\n\nexport const LONG_DATE_FORMAT = \"EEEE, MMMM dd, yyyy 'at' hh:mm a\"\nexport const SHORT_DATE_FORMAT = 'dd.MM.yyyy'\nexport const SHORT_DATETIME_FORMAT = 'dd.MM.yyyy HH:mm a'\n\nexport function formattedDate(pattern: string, date: Date = new Date()): string {\n return formatDate(date, pattern)\n}\n\nexport function longFormattedDate(date: Date = new Date()): string {\n return formattedDate(LONG_DATE_FORMAT, date)\n}\n\nexport function shortFormattedDate(date: Date = new Date()): string {\n return formattedDate(SHORT_DATE_FORMAT, date)\n}\n\nexport function shortFormattedDateTime(date: Date = new Date()): string {\n return formattedDate(SHORT_DATETIME_FORMAT, date)\n}\n\nexport function optionalDate(date?: string): Date | undefined {\n return date ? new Date(date) : undefined\n}\n","type MimeType = 'image/png' | 'image/jpeg' | 'image/webp'\n\nexport function guessImageMimeType(filename: string): MimeType {\n const withoutQueryOrHash = filename.split(/[?#]/)[0]\n // Stryker disable next-line OptionalChaining: equivalent mutant. String#split always returns at\n // least one element for any input (including ''), so .pop() here can never actually be\n // undefined - the `?.` exists only to satisfy Array#pop()'s TypeScript signature.\n const extension = withoutQueryOrHash.split('.').pop()?.toLowerCase()\n switch (extension) {\n // Stryker disable next-line StringLiteral: equivalent mutant. This case and `default` below\n // both return 'image/png', so no input can distinguish which of the two branches ran it.\n case 'png':\n return 'image/png'\n case 'jfif':\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg'\n case 'webp':\n return 'image/webp'\n default:\n return 'image/png'\n }\n}\n\nexport function isImageMimeType(mimeType: string): mimeType is MimeType {\n return mimeType === 'image/png' || mimeType === 'image/jpeg' || mimeType === 'image/webp'\n}\n\nexport function escapeName(name: string): string {\n return name.replace(/[^a-zA-Z0-9-_.]/g, '_')\n}\n\nexport function safeFileName(filename: string, maxLength: number = 255): string {\n if (filename.length <= maxLength) return filename\n\n const dotIndex = filename.lastIndexOf('.')\n const hasExtension = dotIndex > 0\n const extension = escapeName(hasExtension ? filename.slice(dotIndex) : '')\n // Stryker disable next-line MethodExpression: equivalent mutant. This branch only runs when\n // filename.length > maxLength, and escapeName preserves length, so\n // maxLength - extension.length < maxLength - (filename.length - dotIndex) = dotIndex always\n // holds. The slice below therefore never reads past index dotIndex, which is exactly where\n // filename and filename.slice(0, dotIndex) still agree - dropping the slice can't change it.\n const name = escapeName(hasExtension ? filename.slice(0, dotIndex) : filename)\n\n return name.slice(0, Math.max(0, maxLength - extension.length)) + extension\n}\n\nexport async function downloadAndFormatImage(\n src: string,\n name: string = 'image.png',\n mimeType: MimeType = guessImageMimeType(name),\n quality: number = 1\n): Promise<void> {\n name = safeFileName(name)\n try {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n\n await new Promise((resolve, reject) => {\n img.onload = resolve\n img.onerror = reject\n img.src = src\n })\n\n const canvas = document.createElement('canvas')\n canvas.width = img.width\n canvas.height = img.height\n const ctx = canvas.getContext('2d')\n\n if (!ctx) {\n throw new Error('Could not get canvas context')\n }\n\n ctx.drawImage(img, 0, 0)\n\n const blob = await new Promise<Blob | null>((resolve) => {\n canvas.toBlob(resolve, mimeType, quality)\n })\n\n if (!blob) {\n throw new Error('Could not generate blob')\n }\n\n const link = document.createElement('a')\n const downloadUrl = URL.createObjectURL(blob)\n try {\n link.href = downloadUrl\n link.download = name\n document.body.appendChild(link)\n link.click()\n } finally {\n document.body.removeChild(link)\n URL.revokeObjectURL(downloadUrl)\n }\n } catch (error) {\n console.error('Failed to download image:', error)\n }\n}\n\nexport async function fileToBase64Native(file: File): Promise<string> {\n const result = await new Promise<string | ArrayBuffer | null>((resolve, reject) => {\n const reader = new FileReader()\n reader.readAsDataURL(file)\n reader.onload = () => resolve(reader.result)\n reader.onerror = (error) => reject(error)\n })\n\n if (typeof result === 'string') {\n return result\n } else {\n throw new Error('Failed to read file as Data URL')\n }\n}\n\nexport async function fileToBase64(file: File, quality: number = 1): Promise<string> {\n if (isImageMimeType(file.type)) {\n const img = new Image()\n const url = URL.createObjectURL(file)\n try {\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve()\n img.onerror = () => reject(new Error('Failed to load image for metadata removal'))\n img.src = url\n })\n\n const canvas = document.createElement('canvas')\n canvas.width = img.width\n canvas.height = img.height\n\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n throw new Error('Failed to get canvas context')\n }\n ctx.drawImage(img, 0, 0)\n\n const cleanDataUrl = canvas.toDataURL(file.type, quality)\n if (cleanDataUrl === 'data:,') {\n return await fileToBase64Native(file)\n }\n\n return cleanDataUrl\n } finally {\n URL.revokeObjectURL(url)\n }\n } else {\n return await fileToBase64Native(file)\n }\n}\n","export function getCookie(name: string): string | undefined {\n for (const pair of document.cookie.split('; ')) {\n const separatorIndex = pair.indexOf('=')\n if (separatorIndex === -1) {\n continue\n }\n if (pair.slice(0, separatorIndex) === name) {\n return pair.slice(separatorIndex + 1)\n }\n }\n return undefined\n}\n\nexport interface SetCookieOptions {\n /** Days until the cookie expires. Omit for a session cookie (cleared when the browser closes). */\n days?: number\n path?: string\n}\n\nexport function setCookie(name: string, value: string, options: SetCookieOptions = {}): void {\n const { days, path = '/' } = options\n const expires = days === undefined ? '' : `; expires=${new Date(Date.now() + days * 86_400_000).toUTCString()}`\n document.cookie = `${name}=${value}${expires}; path=${path}`\n}\n\nexport function removeCookie(name: string, path: string = '/'): void {\n document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}`\n}\n","type ConsoleMethod = (...args: unknown[]) => void\ntype WindowLike = Window & typeof globalThis\n\nconst patchedWindows = new WeakMap<WindowLike, Set<string>>()\n\nexport function createConsoleDebugSwitch(targetWindow: WindowLike, options: { namespace: string }): void {\n if (!targetWindow) {\n return\n }\n\n const { namespace } = options\n\n let enabledNamespaces = patchedWindows.get(targetWindow)\n if (!enabledNamespaces) {\n enabledNamespaces = new Set<string>()\n patchedWindows.set(targetWindow, enabledNamespaces)\n\n const original = {\n log: targetWindow.console.log.bind(targetWindow.console),\n info: targetWindow.console.info.bind(targetWindow.console),\n warn: targetWindow.console.warn.bind(targetWindow.console),\n error: targetWindow.console.error.bind(targetWindow.console),\n }\n\n const conditional =\n (method: ConsoleMethod): ConsoleMethod =>\n (...args) => {\n if (enabledNamespaces!.size > 0) {\n method(...args)\n }\n }\n\n targetWindow.console.log = conditional(original.log)\n targetWindow.console.info = conditional(original.info)\n targetWindow.console.warn = conditional(original.warn)\n targetWindow.console.error = conditional(original.error)\n }\n\n type Namespace = { debug: (enabled: boolean) => void }\n const globals = targetWindow as unknown as Record<string, Namespace | undefined>\n const existing = Object.prototype.hasOwnProperty.call(globals, namespace)\n ? (Object.getOwnPropertyDescriptor(globals, namespace)?.value as Namespace | undefined)\n : undefined\n const target = existing ?? ({} as Namespace)\n target.debug = (flag: boolean) => {\n if (flag) {\n enabledNamespaces!.add(namespace)\n } else {\n enabledNamespaces!.delete(namespace)\n }\n }\n // Object.defineProperty (unlike a plain `globals[namespace] = target` assignment) always\n // creates/overwrites an own property, even when namespace is a name like \"__proto__\" that\n // would otherwise be intercepted by Object.prototype's special __proto__ accessor and\n // pollute the shared prototype instead of setting a property on this specific object.\n Object.defineProperty(globals, namespace, { value: target, writable: true, configurable: true, enumerable: true })\n}\n","export type TailwindShade = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950\n\nexport type TailwindColorScale = Record<TailwindShade, string>\n\ninterface Rgb {\n r: number\n g: number\n b: number\n}\n\nconst HEX_PATTERN = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i\n\nfunction hexToRgb(hex: string): Rgb {\n const match = HEX_PATTERN.exec(hex.trim())\n if (!match) {\n throw new Error(`Invalid hex color: \"${hex}\"`)\n }\n\n const digits = match[1]\n const normalized =\n digits.length === 3\n ? digits\n .split('')\n .map((char) => char + char)\n .join('')\n : digits\n\n return {\n r: parseInt(normalized.slice(0, 2), 16),\n g: parseInt(normalized.slice(2, 4), 16),\n b: parseInt(normalized.slice(4, 6), 16),\n }\n}\n\nfunction rgbToHex({ r, g, b }: Rgb): string {\n return `#${[r, g, b].map((channel) => Math.round(channel).toString(16).padStart(2, '0')).join('')}`\n}\n\nfunction mixRgb(base: Rgb, target: Rgb, weight: number): Rgb {\n return {\n r: base.r + (target.r - base.r) * weight,\n g: base.g + (target.g - base.g) * weight,\n b: base.b + (target.b - base.b) * weight,\n }\n}\n\nconst WHITE: Rgb = { r: 255, g: 255, b: 255 }\nconst BLACK: Rgb = { r: 0, g: 0, b: 0 }\n\n// Weight of white/black mixed into the base color at each shade, tuned so 500 is the input\n// color unchanged and the rest approximate the spread of Tailwind's own default palettes.\nconst TINT_WEIGHTS: Record<50 | 100 | 200 | 300 | 400, number> = { 50: 0.95, 100: 0.9, 200: 0.75, 300: 0.6, 400: 0.3 }\nconst SHADE_WEIGHTS: Record<600 | 700 | 800 | 900 | 950, number> = {\n 600: 0.15,\n 700: 0.3,\n 800: 0.45,\n 900: 0.6,\n 950: 0.8,\n}\n\n/**\n * Generates a Tailwind-style 50-950 color scale from a single base hex color, treated as the 500 shade.\n */\nexport function generateTailwindColorScale(baseColor: string): TailwindColorScale {\n const base = hexToRgb(baseColor)\n\n return {\n 50: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[50])),\n 100: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[100])),\n 200: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[200])),\n 300: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[300])),\n 400: rgbToHex(mixRgb(base, WHITE, TINT_WEIGHTS[400])),\n 500: rgbToHex(base),\n 600: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[600])),\n 700: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[700])),\n 800: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[800])),\n 900: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[900])),\n 950: rgbToHex(mixRgb(base, BLACK, SHADE_WEIGHTS[950])),\n }\n}\n\n/**\n * Like {@link generateTailwindColorScale}, but prefixes each shade with `name` (e.g. `primary500`)\n * so multiple scales can be spread into one flat palette object.\n */\nexport function generateNamedTailwindColorScale<T extends string>(\n baseColor: string,\n name: T\n): Record<`${T}${TailwindShade}`, string> {\n const scale = generateTailwindColorScale(baseColor)\n\n return Object.fromEntries(Object.entries(scale).map(([shade, hex]) => [`${name}${shade}`, hex])) as Record<\n `${T}${TailwindShade}`,\n string\n >\n}\n\nfunction rgbToHsl({ r, g, b }: Rgb): { h: number; s: number; l: number } {\n const rN = r / 255\n const gN = g / 255\n const bN = b / 255\n\n const max = Math.max(rN, gN, bN)\n const min = Math.min(rN, gN, bN)\n const l = (max + min) / 2\n\n if (max === min) {\n return { h: 0, s: 0, l: l * 100 }\n }\n\n const delta = max - min\n // Stryker disable next-line EqualityOperator: equivalent mutant. l === 0.5 iff max + min === 1,\n // in which case 2 - max - min === max + min too, so both branches compute the same value and\n // no test can ever distinguish `>` from `>=` here.\n const s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min)\n\n let h: number\n if (max === rN) {\n h = ((gN - bN) / delta + (gN < bN ? 6 : 0)) * 60\n } else if (max === gN) {\n h = ((bN - rN) / delta + 2) * 60\n } else {\n h = ((rN - gN) / delta + 4) * 60\n }\n\n return { h, s: s * 100, l: l * 100 }\n}\n\n/**\n * Formats a hex color as the \"H S% L%\" triplet shadcn/Tailwind CSS variable themes expect,\n * e.g. for `--primary: 240 5.9% 10%;` consumed as `hsl(var(--primary))`.\n */\nexport function hexToHslTriplet(hex: string, precision: number = 1): string {\n const { h, s, l } = rgbToHsl(hexToRgb(hex))\n const round = (value: number) => Number(value.toFixed(precision))\n\n return `${round(h)} ${round(s)}% ${round(l)}%`\n}\n"],"mappings":";AAAO,IAAM,UAAU,OAAO;AAQvB,SAAS,WAAc,KAAiB;AAC7C,SAAO;AACT;;;ACVO,SAAS,QAAW,OAAyC;AAClE,SAAO,UAAU,QAAQ,UAAU;AACrC;AAEA,SAAS,mBAAsB,OAAY,MAAqB;AAC9D,MAAI,SAAS,GAAG;AACd,WAAO,CAAC,CAAC,CAAC;AAAA,EACZ;AACA,MAAI,OAAO,MAAM,QAAQ;AACvB,WAAO,CAAC;AAAA,EACV;AACA,QAAM,CAAC,OAAO,GAAG,IAAI,IAAI;AACzB,QAAM,YAAY,mBAAmB,MAAM,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,OAAO,GAAG,WAAW,CAAC;AACjG,QAAM,eAAe,mBAAmB,MAAM,IAAI;AAClD,SAAO,CAAC,GAAG,WAAW,GAAG,YAAY;AACvC;AAEO,SAAS,gBAAmB,SAAqB;AACtD,QAAM,SAAgB,CAAC;AACvB,WAAS,OAAO,GAAG,QAAQ,QAAQ,QAAQ,QAAQ;AACjD,WAAO,KAAK,GAAG,mBAAmB,SAAS,IAAI,CAAC;AAAA,EAClD;AACA,SAAO;AACT;;;ACvBO,SAAS,eACd,IACA,YACY;AACZ,aAAW,OAAO,OAAO,KAAK,UAAU,GAAG;AAKzC,WAAO,eAAe,IAAI,KAAK;AAAA,MAC7B,OAAO,WAAW,GAAG;AAAA,MACrB,UAAU;AAAA,MACV,cAAc;AAAA,MACd,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEO,SAAS,aAAmB,kBAAiC;AAClE,SAAO,CAAC,SAAY,MAAM,iBAAiB,IAAI;AACjD;AAEO,SAAS,aAAgB,OAAyB;AACvD,MAAI,OAAO,UAAU,YAAY;AAC/B,WAAQ,MAAkB;AAAA,EAC5B;AACA,SAAO;AACT;AAEA,eAAsB,kBAAqB,OAAuD;AAChG,MAAI,OAAO,UAAU,YAAY;AAC/B,UAAM,SAAU,MAA2B;AAK3C,QAAI,kBAAkB,SAAS;AAC7B,aAAO,MAAM;AAAA,IACf;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,SACd,YACA,IACA,SACqB;AACrB,MAAI;AACF,WAAO,GAAG;AAAA,EACZ,SAAS,OAAO;AACd,QAAI,WAAW,KAAK,CAAC,cAAc,iBAAiB,SAAS,GAAG;AAC9D,aAAO,UAAU,QAAQ,KAAK,IAAI;AAAA,IACpC;AACA,UAAM;AAAA,EACR;AACF;AAEO,SAAS,eAAmC,UAA8D;AAC/G,SAAO,eAAgB,OAA+B;AACpD,UAAM,eAAe;AACrB,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B;AACF;AAEO,SAAS,cAAc,UAAkB,SAAiB,iBAA2B,CAAC,GAAY;AACvG,MAAI,eAAe,KAAK,CAAC,WAAW,OAAO,KAAK,QAAQ,CAAC,GAAG;AAC1D,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,KAAK,QAAQ;AAC9B;AAEO,SAAS,OAAO,OAA6C;AAClE,SAAO,MAAM;AACX,UAAM;AAAA,EACR;AACF;AAEO,SAAS,OAAiD,IAAY;AAC3E,UAAQ,IAAI,SAAyB,GAAG,GAAG,IAAI;AACjD;AAEO,SAAS,UAAa,WAAsC,SAAyC;AAC1G,QAAM,UAAU,OAAO,cAAc,aAAa,UAAU,IAAI;AAEhE,SAAO,SAA8C,IAAY;AAC/D,QAAI,CAAC,SAAS;AACZ,aAAO,QAAQ,MAAM,QAAQ,wBAA8B;AAAA,IAC7D;AACA,WAAO,OAAO,EAAE;AAAA,EAClB;AACF;AAEO,SAAS,oBACd,gBACA,WACA,UAAsC,CAAC,GACvC;AACA,QAAM,EAAE,eAAe,KAAK,IAAI;AAEhC,SAAO,SAAoD,IAAY;AACrE,YAAQ,IAAI,SAAyB;AACnC,UAAI;AACF,eAAO,GAAG,GAAG,IAAI;AAAA,MACnB,SAAS,OAAO;AACd,YAAI,CAAC,eAAe,KAAK,CAAC,kBAAkB,iBAAiB,aAAa,GAAG;AAC3E,gBAAM;AAAA,QACR;AACA,cAAM,WAAW,UAAU,KAAU;AACrC,YAAI,cAAc;AAChB,mBAAS,QAAQ;AAAA,QACnB;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;;;ACtHO,SAAS,kBACd,KACA,YACS;AACT,QAAM,qBAAqB,OAAO,QAAQ,UAAU,EAAE;AAAA,IACpD,CAAC,CAAC,EAAE,IAAI,MACN,KAAK,MAAM,CAAC,QAAQ,IAAI,GAAG,MAAM,MAAS,KAC1C,OAAO,KAAK,GAAG,EAAE,MAAM,CAAC,QAAQ,KAAK,SAAS,GAAc,KAAK,IAAI,GAAG,MAAM,MAAS;AAAA,EAC3F;AAEA,MAAI,mBAAmB,WAAW,GAAG;AACnC,UAAM,IAAI,MAAM,4DAA4D,KAAK,UAAU,UAAU,CAAC,EAAE;AAAA,EAC1G;AAEA,SAAO,mBAAmB,CAAC,EAAE,CAAC;AAChC;AAEO,SAAS,qBACd,YACA,UAAoC,CAAC,GACrC;AACA,QAAM,mBAAmB,OAAO,QAAQ,UAAU;AAClD,MAAI,iBAAiB,WAAW,GAAG;AACjC,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,QAAM,EAAE,aAAa,MAAM,IAAI;AAC/B,QAAM,eAAe,IAAI,IAAI,iBAAiB,QAAQ,CAAC,CAAC,EAAE,IAAI,MAAM,IAAI,CAAC;AAEzE,SAAO,SAA0C,IAAY;AAC3D,YAAQ,CAAC,QAAW;AAKlB,YAAM,WAAW,IAAI;AAAA,QACnB,OAAO,KAAK,GAAG,EAAE,OAAO,CAAC,QAAQ,aAAa,IAAI,GAAc,KAAK,IAAI,GAAG,MAAM,MAAS;AAAA,MAC7F;AAEA,UAAI,cAAc,SAAS,SAAS,GAAG;AACrC,eAAO,GAAG,GAAG;AAAA,MACf;AAEA,YAAM,UAAU,iBAAiB;AAAA,QAC/B,CAAC,CAAC,EAAE,IAAI,MAAM,KAAK,WAAW,SAAS,QAAQ,KAAK,MAAM,CAAC,QAAQ,SAAS,IAAI,GAAa,CAAC;AAAA,MAChG;AACA,UAAI,QAAQ,WAAW,GAAG;AACxB,cAAM,IAAI,MAAM,4DAA4D,KAAK,UAAU,UAAU,CAAC,EAAE;AAAA,MAC1G;AACA,aAAO,GAAG,GAAG;AAAA,IACf;AAAA,EACF;AACF;AAEO,SAAS,2BAA2B,KAAa,OAAgB,QAAiC;AACvG,MAAI,OAAO;AAKT,WAAO,eAAe,QAAQ,KAAK,EAAE,OAAO,UAAU,MAAM,cAAc,MAAM,YAAY,KAAK,CAAC;AAAA,EACpG;AACF;;;AC7DO,SAAS,QAAQ,OAAe,eAAwB,OAAe;AAC5E,MAAI,cAAc;AAChB,YAAQ,MAAM,UAAU,MAAM,EAAE,QAAQ,uBAAuB,EAAE;AAAA,EACnE,OAAO;AACL,YAAQ,MAAM,UAAU,MAAM;AAE9B,YAAQ,MAAM,QAAQ,iBAAiB,EAAE;AAIzC,YAAQ,MAAM,QAAQ,YAAY,GAAG;AAIrC,YAAQ,MAAM,KAAK;AACnB,YAAQ,MAAM,QAAQ,aAAa,EAAE;AAAA,EACvC;AAEA,UAAQ,MAAM,YAAY;AAE1B,SAAO,MAAM,QAAQ,WAAW,GAAG,EAAE,QAAQ,kBAAkB,EAAE;AACnE;;;ACrBA,SAAS,cAAc;AAEhB,SAAS,WAAW,MAAY,SAAyB;AAC9D,SAAO,OAAO,MAAM,OAAO;AAC7B;;;ACFO,IAAM,mBAAmB;AACzB,IAAM,oBAAoB;AAC1B,IAAM,wBAAwB;AAE9B,SAAS,cAAc,SAAiB,OAAa,oBAAI,KAAK,GAAW;AAC9E,SAAO,WAAW,MAAM,OAAO;AACjC;AAEO,SAAS,kBAAkB,OAAa,oBAAI,KAAK,GAAW;AACjE,SAAO,cAAc,kBAAkB,IAAI;AAC7C;AAEO,SAAS,mBAAmB,OAAa,oBAAI,KAAK,GAAW;AAClE,SAAO,cAAc,mBAAmB,IAAI;AAC9C;AAEO,SAAS,uBAAuB,OAAa,oBAAI,KAAK,GAAW;AACtE,SAAO,cAAc,uBAAuB,IAAI;AAClD;AAEO,SAAS,aAAa,MAAiC;AAC5D,SAAO,OAAO,IAAI,KAAK,IAAI,IAAI;AACjC;;;ACtBO,SAAS,mBAAmB,UAA4B;AAC7D,QAAM,qBAAqB,SAAS,MAAM,MAAM,EAAE,CAAC;AAInD,QAAM,YAAY,mBAAmB,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY;AACnE,UAAQ,WAAW;AAAA;AAAA;AAAA,IAGjB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,SAAS,gBAAgB,UAAwC;AACtE,SAAO,aAAa,eAAe,aAAa,gBAAgB,aAAa;AAC/E;AAEO,SAAS,WAAW,MAAsB;AAC/C,SAAO,KAAK,QAAQ,oBAAoB,GAAG;AAC7C;AAEO,SAAS,aAAa,UAAkB,YAAoB,KAAa;AAC9E,MAAI,SAAS,UAAU,UAAW,QAAO;AAEzC,QAAM,WAAW,SAAS,YAAY,GAAG;AACzC,QAAM,eAAe,WAAW;AAChC,QAAM,YAAY,WAAW,eAAe,SAAS,MAAM,QAAQ,IAAI,EAAE;AAMzE,QAAM,OAAO,WAAW,eAAe,SAAS,MAAM,GAAG,QAAQ,IAAI,QAAQ;AAE7E,SAAO,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,YAAY,UAAU,MAAM,CAAC,IAAI;AACpE;AAEA,eAAsB,uBACpB,KACA,OAAe,aACf,WAAqB,mBAAmB,IAAI,GAC5C,UAAkB,GACH;AACf,SAAO,aAAa,IAAI;AACxB,MAAI;AACF,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,cAAc;AAElB,UAAM,IAAI,QAAQ,CAAC,SAAS,WAAW;AACrC,UAAI,SAAS;AACb,UAAI,UAAU;AACd,UAAI,MAAM;AAAA,IACZ,CAAC;AAED,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ,IAAI;AACnB,WAAO,SAAS,IAAI;AACpB,UAAM,MAAM,OAAO,WAAW,IAAI;AAElC,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAEA,QAAI,UAAU,KAAK,GAAG,CAAC;AAEvB,UAAM,OAAO,MAAM,IAAI,QAAqB,CAAC,YAAY;AACvD,aAAO,OAAO,SAAS,UAAU,OAAO;AAAA,IAC1C,CAAC;AAED,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,UAAM,cAAc,IAAI,gBAAgB,IAAI;AAC5C,QAAI;AACF,WAAK,OAAO;AACZ,WAAK,WAAW;AAChB,eAAS,KAAK,YAAY,IAAI;AAC9B,WAAK,MAAM;AAAA,IACb,UAAE;AACA,eAAS,KAAK,YAAY,IAAI;AAC9B,UAAI,gBAAgB,WAAW;AAAA,IACjC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,6BAA6B,KAAK;AAAA,EAClD;AACF;AAEA,eAAsB,mBAAmB,MAA6B;AACpE,QAAM,SAAS,MAAM,IAAI,QAAqC,CAAC,SAAS,WAAW;AACjF,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,cAAc,IAAI;AACzB,WAAO,SAAS,MAAM,QAAQ,OAAO,MAAM;AAC3C,WAAO,UAAU,CAAC,UAAU,OAAO,KAAK;AAAA,EAC1C,CAAC;AAED,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO;AAAA,EACT,OAAO;AACL,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACF;AAEA,eAAsB,aAAa,MAAY,UAAkB,GAAoB;AACnF,MAAI,gBAAgB,KAAK,IAAI,GAAG;AAC9B,UAAM,MAAM,IAAI,MAAM;AACtB,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,QAAI;AACF,YAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,YAAI,SAAS,MAAM,QAAQ;AAC3B,YAAI,UAAU,MAAM,OAAO,IAAI,MAAM,2CAA2C,CAAC;AACjF,YAAI,MAAM;AAAA,MACZ,CAAC;AAED,YAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,aAAO,QAAQ,IAAI;AACnB,aAAO,SAAS,IAAI;AAEpB,YAAM,MAAM,OAAO,WAAW,IAAI;AAClC,UAAI,CAAC,KAAK;AACR,cAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AACA,UAAI,UAAU,KAAK,GAAG,CAAC;AAEvB,YAAM,eAAe,OAAO,UAAU,KAAK,MAAM,OAAO;AACxD,UAAI,iBAAiB,UAAU;AAC7B,eAAO,MAAM,mBAAmB,IAAI;AAAA,MACtC;AAEA,aAAO;AAAA,IACT,UAAE;AACA,UAAI,gBAAgB,GAAG;AAAA,IACzB;AAAA,EACF,OAAO;AACL,WAAO,MAAM,mBAAmB,IAAI;AAAA,EACtC;AACF;;;ACpJO,SAAS,UAAU,MAAkC;AAC1D,aAAW,QAAQ,SAAS,OAAO,MAAM,IAAI,GAAG;AAC9C,UAAM,iBAAiB,KAAK,QAAQ,GAAG;AACvC,QAAI,mBAAmB,IAAI;AACzB;AAAA,IACF;AACA,QAAI,KAAK,MAAM,GAAG,cAAc,MAAM,MAAM;AAC1C,aAAO,KAAK,MAAM,iBAAiB,CAAC;AAAA,IACtC;AAAA,EACF;AACA,SAAO;AACT;AAQO,SAAS,UAAU,MAAc,OAAe,UAA4B,CAAC,GAAS;AAC3F,QAAM,EAAE,MAAM,OAAO,IAAI,IAAI;AAC7B,QAAM,UAAU,SAAS,SAAY,KAAK,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAU,EAAE,YAAY,CAAC;AAC7G,WAAS,SAAS,GAAG,IAAI,IAAI,KAAK,GAAG,OAAO,UAAU,IAAI;AAC5D;AAEO,SAAS,aAAa,MAAc,OAAe,KAAW;AACnE,WAAS,SAAS,GAAG,IAAI,kDAAkD,IAAI;AACjF;;;ACxBA,IAAM,iBAAiB,oBAAI,QAAiC;AAErD,SAAS,yBAAyB,cAA0B,SAAsC;AACvG,MAAI,CAAC,cAAc;AACjB;AAAA,EACF;AAEA,QAAM,EAAE,UAAU,IAAI;AAEtB,MAAI,oBAAoB,eAAe,IAAI,YAAY;AACvD,MAAI,CAAC,mBAAmB;AACtB,wBAAoB,oBAAI,IAAY;AACpC,mBAAe,IAAI,cAAc,iBAAiB;AAElD,UAAM,WAAW;AAAA,MACf,KAAK,aAAa,QAAQ,IAAI,KAAK,aAAa,OAAO;AAAA,MACvD,MAAM,aAAa,QAAQ,KAAK,KAAK,aAAa,OAAO;AAAA,MACzD,MAAM,aAAa,QAAQ,KAAK,KAAK,aAAa,OAAO;AAAA,MACzD,OAAO,aAAa,QAAQ,MAAM,KAAK,aAAa,OAAO;AAAA,IAC7D;AAEA,UAAM,cACJ,CAAC,WACD,IAAI,SAAS;AACX,UAAI,kBAAmB,OAAO,GAAG;AAC/B,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AAEF,iBAAa,QAAQ,MAAM,YAAY,SAAS,GAAG;AACnD,iBAAa,QAAQ,OAAO,YAAY,SAAS,IAAI;AACrD,iBAAa,QAAQ,OAAO,YAAY,SAAS,IAAI;AACrD,iBAAa,QAAQ,QAAQ,YAAY,SAAS,KAAK;AAAA,EACzD;AAGA,QAAM,UAAU;AAChB,QAAM,WAAW,OAAO,UAAU,eAAe,KAAK,SAAS,SAAS,IACnE,OAAO,yBAAyB,SAAS,SAAS,GAAG,QACtD;AACJ,QAAM,SAAS,YAAa,CAAC;AAC7B,SAAO,QAAQ,CAAC,SAAkB;AAChC,QAAI,MAAM;AACR,wBAAmB,IAAI,SAAS;AAAA,IAClC,OAAO;AACL,wBAAmB,OAAO,SAAS;AAAA,IACrC;AAAA,EACF;AAKA,SAAO,eAAe,SAAS,WAAW,EAAE,OAAO,QAAQ,UAAU,MAAM,cAAc,MAAM,YAAY,KAAK,CAAC;AACnH;;;AC9CA,IAAM,cAAc;AAEpB,SAAS,SAAS,KAAkB;AAClC,QAAM,QAAQ,YAAY,KAAK,IAAI,KAAK,CAAC;AACzC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,uBAAuB,GAAG,GAAG;AAAA,EAC/C;AAEA,QAAM,SAAS,MAAM,CAAC;AACtB,QAAM,aACJ,OAAO,WAAW,IACd,OACG,MAAM,EAAE,EACR,IAAI,CAAC,SAAS,OAAO,IAAI,EACzB,KAAK,EAAE,IACV;AAEN,SAAO;AAAA,IACL,GAAG,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACtC,GAAG,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACtC,GAAG,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,EACxC;AACF;AAEA,SAAS,SAAS,EAAE,GAAG,GAAG,EAAE,GAAgB;AAC1C,SAAO,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,YAAY,KAAK,MAAM,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;AACnG;AAEA,SAAS,OAAO,MAAW,QAAa,QAAqB;AAC3D,SAAO;AAAA,IACL,GAAG,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK;AAAA,IAClC,GAAG,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK;AAAA,IAClC,GAAG,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK;AAAA,EACpC;AACF;AAEA,IAAM,QAAa,EAAE,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI;AAC5C,IAAM,QAAa,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAItC,IAAM,eAA2D,EAAE,IAAI,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,IAAI;AACrH,IAAM,gBAA6D;AAAA,EACjE,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAKO,SAAS,2BAA2B,WAAuC;AAChF,QAAM,OAAO,SAAS,SAAS;AAE/B,SAAO;AAAA,IACL,IAAI,SAAS,OAAO,MAAM,OAAO,aAAa,EAAE,CAAC,CAAC;AAAA,IAClD,KAAK,SAAS,OAAO,MAAM,OAAO,aAAa,GAAG,CAAC,CAAC;AAAA,IACpD,KAAK,SAAS,OAAO,MAAM,OAAO,aAAa,GAAG,CAAC,CAAC;AAAA,IACpD,KAAK,SAAS,OAAO,MAAM,OAAO,aAAa,GAAG,CAAC,CAAC;AAAA,IACpD,KAAK,SAAS,OAAO,MAAM,OAAO,aAAa,GAAG,CAAC,CAAC;AAAA,IACpD,KAAK,SAAS,IAAI;AAAA,IAClB,KAAK,SAAS,OAAO,MAAM,OAAO,cAAc,GAAG,CAAC,CAAC;AAAA,IACrD,KAAK,SAAS,OAAO,MAAM,OAAO,cAAc,GAAG,CAAC,CAAC;AAAA,IACrD,KAAK,SAAS,OAAO,MAAM,OAAO,cAAc,GAAG,CAAC,CAAC;AAAA,IACrD,KAAK,SAAS,OAAO,MAAM,OAAO,cAAc,GAAG,CAAC,CAAC;AAAA,IACrD,KAAK,SAAS,OAAO,MAAM,OAAO,cAAc,GAAG,CAAC,CAAC;AAAA,EACvD;AACF;AAMO,SAAS,gCACd,WACA,MACwC;AACxC,QAAM,QAAQ,2BAA2B,SAAS;AAElD,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;AAIjG;AAEA,SAAS,SAAS,EAAE,GAAG,GAAG,EAAE,GAA6C;AACvE,QAAM,KAAK,IAAI;AACf,QAAM,KAAK,IAAI;AACf,QAAM,KAAK,IAAI;AAEf,QAAM,MAAM,KAAK,IAAI,IAAI,IAAI,EAAE;AAC/B,QAAM,MAAM,KAAK,IAAI,IAAI,IAAI,EAAE;AAC/B,QAAM,KAAK,MAAM,OAAO;AAExB,MAAI,QAAQ,KAAK;AACf,WAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI;AAAA,EAClC;AAEA,QAAM,QAAQ,MAAM;AAIpB,QAAM,IAAI,IAAI,MAAM,SAAS,IAAI,MAAM,OAAO,SAAS,MAAM;AAE7D,MAAI;AACJ,MAAI,QAAQ,IAAI;AACd,UAAM,KAAK,MAAM,SAAS,KAAK,KAAK,IAAI,MAAM;AAAA,EAChD,WAAW,QAAQ,IAAI;AACrB,UAAM,KAAK,MAAM,QAAQ,KAAK;AAAA,EAChC,OAAO;AACL,UAAM,KAAK,MAAM,QAAQ,KAAK;AAAA,EAChC;AAEA,SAAO,EAAE,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,IAAI;AACrC;AAMO,SAAS,gBAAgB,KAAa,YAAoB,GAAW;AAC1E,QAAM,EAAE,GAAG,GAAG,EAAE,IAAI,SAAS,SAAS,GAAG,CAAC;AAC1C,QAAM,QAAQ,CAAC,UAAkB,OAAO,MAAM,QAAQ,SAAS,CAAC;AAEhE,SAAO,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;AAC7C;","names":[]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { C as ConfigSchema, P as PublicConfigOptions, a as PublicConfig } from '../../
|
|
1
|
+
import { C as ConfigSchema, P as PublicConfigOptions, a as PublicConfig } from '../../configError-BtEWY-oE.js';
|
|
2
|
+
export { b as Caster, c as ConfigError, I as InferConfig, d as PublicConfigScriptComponent, e as PublicConfigScriptProps, f as boolean, g as caster, h as commaSeparatedFloatList, i as commaSeparatedIntList, j as commaSeparatedList, k as float, l as integer, s as string } from '../../configError-BtEWY-oE.js';
|
|
2
3
|
import 'react';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -11,8 +12,9 @@ import 'react';
|
|
|
11
12
|
* The schema argument is accepted and ignored - values arrive already cast, through the injected
|
|
12
13
|
* global. It stays in the signature so `InferConfig<S>` produces the identical type on both
|
|
13
14
|
* sides, which is what lets one `app/config.ts` be imported by server and client components
|
|
14
|
-
* alike.
|
|
15
|
+
* alike. `options.globalKey` is not ignored: it is the only thing this half needs, and it is read
|
|
16
|
+
* from the same options object the server half was given.
|
|
15
17
|
*/
|
|
16
|
-
declare function publicConfig<S extends ConfigSchema>(_schema: S, options
|
|
18
|
+
declare function publicConfig<S extends ConfigSchema>(_schema: S, options: PublicConfigOptions): PublicConfig<S>;
|
|
17
19
|
|
|
18
|
-
export { publicConfig };
|
|
20
|
+
export { ConfigSchema, PublicConfig, PublicConfigOptions, publicConfig };
|
|
@@ -3,9 +3,14 @@ var ConfigError = class extends Error {
|
|
|
3
3
|
};
|
|
4
4
|
|
|
5
5
|
// src/next/config/shared.ts
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
function requireGlobalKey(options) {
|
|
7
|
+
const { globalKey } = options;
|
|
8
|
+
if (typeof globalKey !== "string" || globalKey === "") {
|
|
9
|
+
throw new ConfigError(
|
|
10
|
+
'publicConfig: globalKey is required and must be a non-empty string - it names the window property the config is injected under, e.g. { globalKey: "__MY_APP_CONFIG__" }. There is no default, so the name is yours and two configs cannot collide on one neither of them chose.'
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
return globalKey;
|
|
9
14
|
}
|
|
10
15
|
function memoize(resolve) {
|
|
11
16
|
let value;
|
|
@@ -30,9 +35,52 @@ function lazyConfigProxy(resolve) {
|
|
|
30
35
|
});
|
|
31
36
|
}
|
|
32
37
|
|
|
38
|
+
// src/node/casters.ts
|
|
39
|
+
function caster(fn) {
|
|
40
|
+
return function(options = {}) {
|
|
41
|
+
const clone = ((value) => fn(value));
|
|
42
|
+
if ("missingDefault" in options) {
|
|
43
|
+
clone.missingDefault = options.missingDefault;
|
|
44
|
+
}
|
|
45
|
+
if ("errorDefault" in options) {
|
|
46
|
+
clone.errorDefault = options.errorDefault;
|
|
47
|
+
}
|
|
48
|
+
return clone;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function parseStrictInteger(value) {
|
|
52
|
+
if (value.trim() === "" || !Number.isInteger(Number(value))) {
|
|
53
|
+
throw new Error(`Value ${JSON.stringify(value)} can not be parsed into an integer.`);
|
|
54
|
+
}
|
|
55
|
+
return Number(value);
|
|
56
|
+
}
|
|
57
|
+
function parseStrictFloat(value) {
|
|
58
|
+
if (value.trim() === "" || Number.isNaN(Number(value))) {
|
|
59
|
+
throw new Error(`Value ${JSON.stringify(value)} can not be parsed into a float.`);
|
|
60
|
+
}
|
|
61
|
+
return Number(value);
|
|
62
|
+
}
|
|
63
|
+
var string = caster((value) => value);
|
|
64
|
+
var integer = caster(parseStrictInteger);
|
|
65
|
+
var float = caster(parseStrictFloat);
|
|
66
|
+
var boolean = caster((value) => {
|
|
67
|
+
const truthy = ["true", "True", "1"];
|
|
68
|
+
const falsy = ["false", "False", "0"];
|
|
69
|
+
if (truthy.includes(value)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (falsy.includes(value)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`Value ${JSON.stringify(value)} can not be parsed into a boolean.`);
|
|
76
|
+
});
|
|
77
|
+
var commaSeparatedList = caster((value) => value.split(","));
|
|
78
|
+
var commaSeparatedIntList = caster((value) => value.split(",").map(parseStrictInteger));
|
|
79
|
+
var commaSeparatedFloatList = caster((value) => value.split(",").map(parseStrictFloat));
|
|
80
|
+
|
|
33
81
|
// src/next/config/browser.ts
|
|
34
|
-
function publicConfig(_schema, options
|
|
35
|
-
const globalKey =
|
|
82
|
+
function publicConfig(_schema, options) {
|
|
83
|
+
const globalKey = requireGlobalKey(options);
|
|
36
84
|
return {
|
|
37
85
|
CONFIG: lazyConfigProxy(memoize(() => readInjectedConfig(globalKey))),
|
|
38
86
|
// Injection is a server-render concern; there is nothing to emit once the document exists.
|
|
@@ -49,6 +97,15 @@ function readInjectedConfig(globalKey) {
|
|
|
49
97
|
return injected;
|
|
50
98
|
}
|
|
51
99
|
export {
|
|
52
|
-
|
|
100
|
+
ConfigError,
|
|
101
|
+
boolean,
|
|
102
|
+
caster,
|
|
103
|
+
commaSeparatedFloatList,
|
|
104
|
+
commaSeparatedIntList,
|
|
105
|
+
commaSeparatedList,
|
|
106
|
+
float,
|
|
107
|
+
integer,
|
|
108
|
+
publicConfig,
|
|
109
|
+
string
|
|
53
110
|
};
|
|
54
111
|
//# sourceMappingURL=browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/node/configError.ts","../../../src/next/config/shared.ts","../../../src/next/config/browser.ts"],"sourcesContent":["/**\n * Isolated in its own module - with no `process.env` access anywhere in it - so that the browser\n * half of `@isikk/core/next/config` can throw the same error type without importing\n * anything that reads the environment. Keeping the split structural means the guarantee holds\n * because of what the file contains, not because a bundler happened to tree-shake it away.\n */\nexport class ConfigError extends Error {}\n","import type { ReactNode } from 'react'\n\nimport type { ConfigSchema, InferConfig } from '../../node/configCore'\n\nexport interface PublicConfigOptions {\n /** Prepended to every environment variable name this call reads, joined with `sep`. */\n prefix?: string\n /** Joins the prefix and the nested key path into a variable name. Defaults to `\"__\"`. */\n sep?: string\n}\n\nexport interface PublicConfigScriptProps {\n /** Forwarded to the injected `<script>` so a CSP with a per-request nonce keeps working. */\n nonce?: string\n}\n\nexport type PublicConfigScriptComponent = (props: PublicConfigScriptProps) => ReactNode | Promise<ReactNode>\n\nexport interface PublicConfig<S extends ConfigSchema> {\n CONFIG: InferConfig<S>\n PublicConfigScript: PublicConfigScriptComponent\n}\n\nconst GLOBAL_KEY_BASE = '__ISIK_PUBLIC_CONFIG__'\n\n/**\n * Namespaces the injected global by prefix, so two `publicConfig()` calls land on two properties\n * instead of the second one failing to redefine the first. Prefixes are already required to be\n * distinct from any server namespace, which makes them a usable key.\n */\nexport function globalKeyFor(prefix: string): string {\n return prefix === '' ? GLOBAL_KEY_BASE : `${GLOBAL_KEY_BASE}${prefix}__`\n}\n\n/**\n * Encodes a string as a JavaScript string literal that is safe to interpolate into a `<script>`\n * body. `JSON.stringify` alone is not: `</script>` inside a value closes the tag early and drops\n * the rest of the payload into the document as markup, and U+2028/U+2029 are literal line\n * terminators in JavaScript source, so a value containing one produces a syntax error. Escaping\n * `<` covers the first (the sequence can no longer be written) and the two explicit replacements\n * cover the second. `>` and `&` need no handling - a script element is raw text, so nothing in it\n * is parsed as markup or entities once `<` can't start a closing tag.\n */\nexport function jsStringLiteral(value: string): string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029')\n}\n\n/**\n * The script that hands the resolved config to the browser. Values travel as a JSON string parsed\n * at runtime rather than as an object literal: it parses faster than equivalent JS source, and it\n * narrows everything that needs escaping down to the single quoted string handled above.\n *\n * The definition is deep-frozen and non-writable, so nothing can reshape config after hydration,\n * and re-entrant if the script somehow runs twice - redefining a non-configurable property would\n * throw, so an existing key means there is nothing left to do.\n */\nexport function serializePublicConfigScript(key: string, value: unknown): string {\n return (\n '(function(w,k,v){if(k in w)return;' +\n 'var f=function(o){if(o&&typeof o==\"object\"){for(var p in o)f(o[p]);Object.freeze(o)}};' +\n 'f(v);Object.defineProperty(w,k,{value:v,enumerable:true})})' +\n `(window,${jsStringLiteral(key)},JSON.parse(${jsStringLiteral(JSON.stringify(value))}))`\n )\n}\n\nexport function memoize<T>(resolve: () => T): () => T {\n let value: T\n let resolved = false\n return () => {\n if (!resolved) {\n value = resolve()\n resolved = true\n }\n return value\n }\n}\n\n/**\n * Presents `resolve()`'s result as a plain object without calling it until something is actually\n * read. That deferral is load-bearing on both sides of the package. On the server it keeps\n * `next build` from resolving anything while collecting page data, so a missing variable no\n * longer fails the build - \"can this build\" stops depending on \"is this configured\". In the\n * browser it means the injected global is read at access time rather than at chunk-evaluation\n * time, so an async chunk that happens to run before the inline script still sees the config.\n */\nexport function lazyConfigProxy<T>(resolve: () => T): T {\n return new Proxy({} as object, {\n get: (_target, property) => Reflect.get(resolve() as object, property),\n has: (_target, property) => Reflect.has(resolve() as object, property),\n ownKeys: () => Reflect.ownKeys(resolve() as object),\n getOwnPropertyDescriptor: (_target, property) => {\n const descriptor = Reflect.getOwnPropertyDescriptor(resolve() as object, property)\n // The proxy target is an empty object, and a proxy may not report a non-configurable\n // property that its target doesn't have - so re-mark descriptors as configurable, or\n // Object.keys()/JSON.stringify() over the config throw a TypeError.\n return descriptor === undefined ? undefined : { ...descriptor, configurable: true }\n },\n }) as T\n}\n","import type { ConfigSchema, InferConfig } from '../../node/configCore'\nimport { ConfigError } from '../../node/configError'\nimport { type PublicConfig, type PublicConfigOptions, globalKeyFor, lazyConfigProxy, memoize } from './shared'\n\n/**\n * The browser half of `publicConfig()`, substituted for the server module by the `browser`\n * export condition in package.json rather than branched to at runtime. That substitution is what\n * makes the split safe: this file contains no reference to `process.env` at all, so bundling the\n * config module for the client cannot ship a server value no matter what the schema says. It is a\n * property of what the file contains, not a discipline anyone has to maintain.\n *\n * The schema argument is accepted and ignored - values arrive already cast, through the injected\n * global. It stays in the signature so `InferConfig<S>` produces the identical type on both\n * sides, which is what lets one `app/config.ts` be imported by server and client components\n * alike.\n */\nexport function publicConfig<S extends ConfigSchema>(_schema: S, options: PublicConfigOptions = {}): PublicConfig<S> {\n const globalKey = globalKeyFor(options.prefix ?? '')\n\n return {\n CONFIG: lazyConfigProxy<InferConfig<S>>(memoize(() => readInjectedConfig<S>(globalKey))),\n // Injection is a server-render concern; there is nothing to emit once the document exists.\n PublicConfigScript: () => null,\n }\n}\n\nfunction readInjectedConfig<S extends ConfigSchema>(globalKey: string): InferConfig<S> {\n const injected = (globalThis as unknown as Record<string, unknown>)[globalKey]\n\n if (injected === undefined) {\n throw new ConfigError(\n `window.${globalKey} is not set, so there is no public config to read. Render <PublicConfigScript /> ` +\n 'once in your root layout (inside a <Suspense> boundary if Cache Components is enabled). If this is a ' +\n 'test or a non-Next renderer, assign the object yourself before anything reads the config.'\n )\n }\n\n return injected as InferConfig<S>\n}\n"],"mappings":";AAMO,IAAM,cAAN,cAA0B,MAAM;AAAC;;;ACiBxC,IAAM,kBAAkB;AAOjB,SAAS,aAAa,QAAwB;AACnD,SAAO,WAAW,KAAK,kBAAkB,GAAG,eAAe,GAAG,MAAM;AACtE;AAoCO,SAAS,QAAW,SAA2B;AACpD,MAAI;AACJ,MAAI,WAAW;AACf,SAAO,MAAM;AACX,QAAI,CAAC,UAAU;AACb,cAAQ,QAAQ;AAChB,iBAAW;AAAA,IACb;AACA,WAAO;AAAA,EACT;AACF;AAUO,SAAS,gBAAmB,SAAqB;AACtD,SAAO,IAAI,MAAM,CAAC,GAAa;AAAA,IAC7B,KAAK,CAAC,SAAS,aAAa,QAAQ,IAAI,QAAQ,GAAa,QAAQ;AAAA,IACrE,KAAK,CAAC,SAAS,aAAa,QAAQ,IAAI,QAAQ,GAAa,QAAQ;AAAA,IACrE,SAAS,MAAM,QAAQ,QAAQ,QAAQ,CAAW;AAAA,IAClD,0BAA0B,CAAC,SAAS,aAAa;AAC/C,YAAM,aAAa,QAAQ,yBAAyB,QAAQ,GAAa,QAAQ;AAIjF,aAAO,eAAe,SAAY,SAAY,EAAE,GAAG,YAAY,cAAc,KAAK;AAAA,IACpF;AAAA,EACF,CAAC;AACH;;;ACrFO,SAAS,aAAqC,SAAY,UAA+B,CAAC,GAAoB;AACnH,QAAM,YAAY,aAAa,QAAQ,UAAU,EAAE;AAEnD,SAAO;AAAA,IACL,QAAQ,gBAAgC,QAAQ,MAAM,mBAAsB,SAAS,CAAC,CAAC;AAAA;AAAA,IAEvF,oBAAoB,MAAM;AAAA,EAC5B;AACF;AAEA,SAAS,mBAA2C,WAAmC;AACrF,QAAM,WAAY,WAAkD,SAAS;AAE7E,MAAI,aAAa,QAAW;AAC1B,UAAM,IAAI;AAAA,MACR,UAAU,SAAS;AAAA,IAGrB;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/node/configError.ts","../../../src/next/config/shared.ts","../../../src/node/casters.ts","../../../src/next/config/browser.ts"],"sourcesContent":["/**\n * Isolated in its own module - with no `process.env` access anywhere in it - so that the browser\n * half of `@isikk/core/next/config` can throw the same error type without importing\n * anything that reads the environment. Keeping the split structural means the guarantee holds\n * because of what the file contains, not because a bundler happened to tree-shake it away.\n */\nexport class ConfigError extends Error {}\n","import type { ReactNode } from 'react'\n\nimport type { ConfigSchema, InferConfig } from '../../node/configCore'\nimport { ConfigError } from '../../node/configError'\n\nexport interface PublicConfigOptions {\n /**\n * The property the payload is injected under on `window`. Required, with no default and no\n * derived fallback: the name belongs in your application's namespace, not this package's, and\n * naming it at the call site is what stops two configs from silently landing on a name neither\n * of them chose.\n */\n globalKey: string\n /** Prepended to every environment variable name this call reads, joined with `sep`. */\n prefix?: string\n /** Joins the prefix and the nested key path into a variable name. Defaults to `\"__\"`. */\n sep?: string\n}\n\nexport interface PublicConfigScriptProps {\n /** Forwarded to the injected `<script>` so a CSP with a per-request nonce keeps working. */\n nonce?: string\n}\n\nexport type PublicConfigScriptComponent = (props: PublicConfigScriptProps) => ReactNode | Promise<ReactNode>\n\nexport interface PublicConfig<S extends ConfigSchema> {\n CONFIG: InferConfig<S>\n PublicConfigScript: PublicConfigScriptComponent\n}\n\n/**\n * Validates the caller-supplied global key. There is deliberately no default and nothing derived\n * from `prefix` to fall back to: a package-chosen name would put this package's identity into\n * every consuming app's `window`, and - worse - two `publicConfig()` calls could quietly agree on\n * a name neither of them wrote down. Since the payload is injected non-writable, that agreement\n * loses the second config silently in the browser while both still resolve on the server. Making\n * the name mandatory turns that from an invisible default into a line you can read at the call\n * site.\n *\n * Both halves of the module go through this one function, from the same options object: the\n * schema and options live at a single call site in the consuming app, and only the library import\n * flips between builds. That is what makes the two sides agree by construction - a server that\n * wrote one key and a browser that read another would fail with nothing to point at.\n *\n * No character restrictions, since the key is emitted as an escaped string literal and read back\n * with bracket notation. The runtime check covers callers without types, for whom a missing key\n * would otherwise mean reading `window[undefined]`.\n */\nexport function requireGlobalKey(options: PublicConfigOptions): string {\n const { globalKey } = options\n\n if (typeof globalKey !== 'string' || globalKey === '') {\n throw new ConfigError(\n 'publicConfig: globalKey is required and must be a non-empty string - it names the window ' +\n 'property the config is injected under, e.g. { globalKey: \"__MY_APP_CONFIG__\" }. There is no ' +\n 'default, so the name is yours and two configs cannot collide on one neither of them chose.'\n )\n }\n\n return globalKey\n}\n\n/**\n * Encodes a string as a JavaScript string literal that is safe to interpolate into a `<script>`\n * body. `JSON.stringify` alone is not: `</script>` inside a value closes the tag early and drops\n * the rest of the payload into the document as markup, and U+2028/U+2029 are literal line\n * terminators in JavaScript source, so a value containing one produces a syntax error. Escaping\n * `<` covers the first (the sequence can no longer be written) and the two explicit replacements\n * cover the second. `>` and `&` need no handling - a script element is raw text, so nothing in it\n * is parsed as markup or entities once `<` can't start a closing tag.\n */\nexport function jsStringLiteral(value: string): string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029')\n}\n\n/**\n * The script that hands the resolved config to the browser. Values travel as a JSON string parsed\n * at runtime rather than as an object literal: it parses faster than equivalent JS source, and it\n * narrows everything that needs escaping down to the single quoted string handled above.\n *\n * The definition is deep-frozen and non-writable, so nothing can reshape config after hydration,\n * and re-entrant if the script somehow runs twice - redefining a non-configurable property would\n * throw, so an existing key means there is nothing left to do.\n */\nexport function serializePublicConfigScript(key: string, value: unknown): string {\n return (\n '(function(w,k,v){if(k in w)return;' +\n 'var f=function(o){if(o&&typeof o==\"object\"){for(var p in o)f(o[p]);Object.freeze(o)}};' +\n 'f(v);Object.defineProperty(w,k,{value:v,enumerable:true})})' +\n `(window,${jsStringLiteral(key)},JSON.parse(${jsStringLiteral(JSON.stringify(value))}))`\n )\n}\n\nexport function memoize<T>(resolve: () => T): () => T {\n let value: T\n let resolved = false\n return () => {\n if (!resolved) {\n value = resolve()\n resolved = true\n }\n return value\n }\n}\n\n/**\n * Presents `resolve()`'s result as a plain object without calling it until something is actually\n * read. That deferral is load-bearing on both sides of the package. On the server it keeps\n * `next build` from resolving anything while collecting page data, so a missing variable no\n * longer fails the build - \"can this build\" stops depending on \"is this configured\". In the\n * browser it means the injected global is read at access time rather than at chunk-evaluation\n * time, so an async chunk that happens to run before the inline script still sees the config.\n */\nexport function lazyConfigProxy<T>(resolve: () => T): T {\n return new Proxy({} as object, {\n get: (_target, property) => Reflect.get(resolve() as object, property),\n has: (_target, property) => Reflect.has(resolve() as object, property),\n ownKeys: () => Reflect.ownKeys(resolve() as object),\n getOwnPropertyDescriptor: (_target, property) => {\n const descriptor = Reflect.getOwnPropertyDescriptor(resolve() as object, property)\n // The proxy target is an empty object, and a proxy may not report a non-configurable\n // property that its target doesn't have - so re-mark descriptors as configurable, or\n // Object.keys()/JSON.stringify() over the config throw a TypeError.\n return descriptor === undefined ? undefined : { ...descriptor, configurable: true }\n },\n }) as T\n}\n","export type Caster<T> = ((value: string) => T) & { missingDefault?: T; errorDefault?: T }\n\nexport function caster<T>(fn: (value: string) => T) {\n return function (options: { missingDefault?: T; errorDefault?: T } = {}): Caster<T> {\n const clone = ((value: string) => fn(value)) as Caster<T>\n if ('missingDefault' in options) {\n clone.missingDefault = options.missingDefault\n }\n if ('errorDefault' in options) {\n clone.errorDefault = options.errorDefault\n }\n return clone\n }\n}\n\n// JS's Number()/parseInt()/parseFloat() don't throw on unparseable input the way Python's int()/\n// float() do (parseInt('123abc') silently returns 123, Number('') silently returns 0) - these\n// helpers add back the \"either it's a clean, fully-parsed number or it throws\" contract the\n// missingDefault/errorDefault fallback system above depends on.\nfunction parseStrictInteger(value: string): number {\n if (value.trim() === '' || !Number.isInteger(Number(value))) {\n throw new Error(`Value ${JSON.stringify(value)} can not be parsed into an integer.`)\n }\n return Number(value)\n}\n\nfunction parseStrictFloat(value: string): number {\n if (value.trim() === '' || Number.isNaN(Number(value))) {\n throw new Error(`Value ${JSON.stringify(value)} can not be parsed into a float.`)\n }\n return Number(value)\n}\n\nexport const string = caster((value: string) => value)\n\nexport const integer = caster(parseStrictInteger)\n\nexport const float = caster(parseStrictFloat)\n\nexport const boolean = caster((value: string) => {\n const truthy = ['true', 'True', '1']\n const falsy = ['false', 'False', '0']\n if (truthy.includes(value)) {\n return true\n }\n if (falsy.includes(value)) {\n return false\n }\n throw new Error(`Value ${JSON.stringify(value)} can not be parsed into a boolean.`)\n})\n\nexport const commaSeparatedList = caster((value: string) => value.split(','))\n\nexport const commaSeparatedIntList = caster((value: string) => value.split(',').map(parseStrictInteger))\n\nexport const commaSeparatedFloatList = caster((value: string) => value.split(',').map(parseStrictFloat))\n","import type { ConfigSchema, InferConfig } from '../../node/configCore'\nimport { ConfigError } from '../../node/configError'\nimport { type PublicConfig, type PublicConfigOptions, lazyConfigProxy, memoize, requireGlobalKey } from './shared'\n\n// Mirrors the server half's re-export, so the shared schema call site resolves the same caster\n// names in the browser bundle. Pure functions, no environment access - see index.tsx for why they\n// cannot be imported from `@isikk/core/node` here.\nexport * from '../../node/casters'\nexport { ConfigError } from '../../node/configError'\nexport type { ConfigSchema, InferConfig } from '../../node/configCore'\nexport type { PublicConfig, PublicConfigOptions, PublicConfigScriptComponent, PublicConfigScriptProps } from './shared'\n\n/**\n * The browser half of `publicConfig()`, substituted for the server module by the `browser`\n * export condition in package.json rather than branched to at runtime. That substitution is what\n * makes the split safe: this file contains no reference to `process.env` at all, so bundling the\n * config module for the client cannot ship a server value no matter what the schema says. It is a\n * property of what the file contains, not a discipline anyone has to maintain.\n *\n * The schema argument is accepted and ignored - values arrive already cast, through the injected\n * global. It stays in the signature so `InferConfig<S>` produces the identical type on both\n * sides, which is what lets one `app/config.ts` be imported by server and client components\n * alike. `options.globalKey` is not ignored: it is the only thing this half needs, and it is read\n * from the same options object the server half was given.\n */\nexport function publicConfig<S extends ConfigSchema>(_schema: S, options: PublicConfigOptions): PublicConfig<S> {\n const globalKey = requireGlobalKey(options)\n\n return {\n CONFIG: lazyConfigProxy<InferConfig<S>>(memoize(() => readInjectedConfig<S>(globalKey))),\n // Injection is a server-render concern; there is nothing to emit once the document exists.\n PublicConfigScript: () => null,\n }\n}\n\nfunction readInjectedConfig<S extends ConfigSchema>(globalKey: string): InferConfig<S> {\n const injected = (globalThis as unknown as Record<string, unknown>)[globalKey]\n\n if (injected === undefined) {\n throw new ConfigError(\n `window.${globalKey} is not set, so there is no public config to read. Render <PublicConfigScript /> ` +\n 'once in your root layout (inside a <Suspense> boundary if Cache Components is enabled). If this is a ' +\n 'test or a non-Next renderer, assign the object yourself before anything reads the config.'\n )\n }\n\n return injected as InferConfig<S>\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { C as ConfigSchema, P as PublicConfigOptions, a as PublicConfig } from '../../
|
|
2
|
-
export { I as InferConfig,
|
|
1
|
+
import { C as ConfigSchema, P as PublicConfigOptions, a as PublicConfig } from '../../configError-BtEWY-oE.js';
|
|
2
|
+
export { b as Caster, c as ConfigError, I as InferConfig, d as PublicConfigScriptComponent, e as PublicConfigScriptProps, f as boolean, g as caster, h as commaSeparatedFloatList, i as commaSeparatedIntList, j as commaSeparatedList, k as float, l as integer, s as string } from '../../configError-BtEWY-oE.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Isolated in its own module - with no `process.env` access anywhere in it - so that the browser
|
|
7
|
-
* half of `@isikk/core/next/config` can throw the same error type without importing
|
|
8
|
-
* anything that reads the environment. Keeping the split structural means the guarantee holds
|
|
9
|
-
* because of what the file contains, not because a bundler happened to tree-shake it away.
|
|
10
|
-
*/
|
|
11
|
-
declare class ConfigError extends Error {
|
|
12
|
-
}
|
|
13
|
-
|
|
14
5
|
/**
|
|
15
6
|
* The browser-visible sibling of `config()`: same schema, same casters, same variable naming, but
|
|
16
7
|
* the resolved values are serialized into the document so client components can read them at
|
|
@@ -21,10 +12,13 @@ declare class ConfigError extends Error {
|
|
|
21
12
|
* must not overlap one already claimed by `config()`, so a server-only key pasted into this
|
|
22
13
|
* schema by mistake resolves to nothing and throws rather than getting published.
|
|
23
14
|
*
|
|
15
|
+
* `options.globalKey` is required - it names the `window` property the payload is injected under,
|
|
16
|
+
* and there is no default to fall back to.
|
|
17
|
+
*
|
|
24
18
|
* Values are read per request, not baked in at build - which is the entire point next to
|
|
25
19
|
* `NEXT_PUBLIC_*`, and what lets one image run in staging and production. Nothing resolves until
|
|
26
20
|
* something reads it, so `next build` needs none of these variables set.
|
|
27
21
|
*/
|
|
28
|
-
declare function publicConfig<S extends ConfigSchema>(schema: S, options
|
|
22
|
+
declare function publicConfig<S extends ConfigSchema>(schema: S, options: PublicConfigOptions): PublicConfig<S>;
|
|
29
23
|
|
|
30
|
-
export {
|
|
24
|
+
export { ConfigSchema, PublicConfig, PublicConfigOptions, publicConfig };
|
|
@@ -70,6 +70,9 @@ function namespacesOverlap(a, b) {
|
|
|
70
70
|
function describeNamespace(namespace) {
|
|
71
71
|
return namespace.prefix === "" ? "no prefix" : `prefix ${JSON.stringify(namespace.prefix)}`;
|
|
72
72
|
}
|
|
73
|
+
function sameNamespace(a, b) {
|
|
74
|
+
return a.kind === b.kind && a.prefix === b.prefix && a.sep === b.sep;
|
|
75
|
+
}
|
|
73
76
|
function claimConfigNamespace(claim) {
|
|
74
77
|
const registry = getRegistry();
|
|
75
78
|
for (const existing of registry) {
|
|
@@ -77,9 +80,7 @@ function claimConfigNamespace(claim) {
|
|
|
77
80
|
return `${CALL_NAME[claim.kind]} was called with ${describeNamespace(claim)}, but ${CALL_NAME[existing.kind]} already claimed ${describeNamespace(existing)} - they would read the same environment variable namespace, so a key added to the public schema can resolve to a server-only value and be serialized into the browser. Give one of them a prefix the other does not use.`;
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
|
-
const alreadyClaimed = registry.some(
|
|
81
|
-
(existing) => existing.kind === claim.kind && existing.prefix === claim.prefix && existing.sep === claim.sep
|
|
82
|
-
);
|
|
83
|
+
const alreadyClaimed = registry.some((existing) => sameNamespace(existing, claim));
|
|
83
84
|
if (!alreadyClaimed) {
|
|
84
85
|
registry.push(claim);
|
|
85
86
|
}
|
|
@@ -90,9 +91,14 @@ function claimConfigNamespace(claim) {
|
|
|
90
91
|
import { PublicConfigInsert } from "./insert.js";
|
|
91
92
|
|
|
92
93
|
// src/next/config/shared.ts
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
function requireGlobalKey(options) {
|
|
95
|
+
const { globalKey } = options;
|
|
96
|
+
if (typeof globalKey !== "string" || globalKey === "") {
|
|
97
|
+
throw new ConfigError(
|
|
98
|
+
'publicConfig: globalKey is required and must be a non-empty string - it names the window property the config is injected under, e.g. { globalKey: "__MY_APP_CONFIG__" }. There is no default, so the name is yours and two configs cannot collide on one neither of them chose.'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return globalKey;
|
|
96
102
|
}
|
|
97
103
|
function jsStringLiteral(value) {
|
|
98
104
|
return JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
@@ -123,15 +129,58 @@ function lazyConfigProxy(resolve) {
|
|
|
123
129
|
});
|
|
124
130
|
}
|
|
125
131
|
|
|
132
|
+
// src/node/casters.ts
|
|
133
|
+
function caster(fn) {
|
|
134
|
+
return function(options = {}) {
|
|
135
|
+
const clone = ((value) => fn(value));
|
|
136
|
+
if ("missingDefault" in options) {
|
|
137
|
+
clone.missingDefault = options.missingDefault;
|
|
138
|
+
}
|
|
139
|
+
if ("errorDefault" in options) {
|
|
140
|
+
clone.errorDefault = options.errorDefault;
|
|
141
|
+
}
|
|
142
|
+
return clone;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function parseStrictInteger(value) {
|
|
146
|
+
if (value.trim() === "" || !Number.isInteger(Number(value))) {
|
|
147
|
+
throw new Error(`Value ${JSON.stringify(value)} can not be parsed into an integer.`);
|
|
148
|
+
}
|
|
149
|
+
return Number(value);
|
|
150
|
+
}
|
|
151
|
+
function parseStrictFloat(value) {
|
|
152
|
+
if (value.trim() === "" || Number.isNaN(Number(value))) {
|
|
153
|
+
throw new Error(`Value ${JSON.stringify(value)} can not be parsed into a float.`);
|
|
154
|
+
}
|
|
155
|
+
return Number(value);
|
|
156
|
+
}
|
|
157
|
+
var string = caster((value) => value);
|
|
158
|
+
var integer = caster(parseStrictInteger);
|
|
159
|
+
var float = caster(parseStrictFloat);
|
|
160
|
+
var boolean = caster((value) => {
|
|
161
|
+
const truthy = ["true", "True", "1"];
|
|
162
|
+
const falsy = ["false", "False", "0"];
|
|
163
|
+
if (truthy.includes(value)) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
if (falsy.includes(value)) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
throw new Error(`Value ${JSON.stringify(value)} can not be parsed into a boolean.`);
|
|
170
|
+
});
|
|
171
|
+
var commaSeparatedList = caster((value) => value.split(","));
|
|
172
|
+
var commaSeparatedIntList = caster((value) => value.split(",").map(parseStrictInteger));
|
|
173
|
+
var commaSeparatedFloatList = caster((value) => value.split(",").map(parseStrictFloat));
|
|
174
|
+
|
|
126
175
|
// src/next/config/index.tsx
|
|
127
176
|
import { jsx } from "react/jsx-runtime";
|
|
128
|
-
function publicConfig(schema, options
|
|
177
|
+
function publicConfig(schema, options) {
|
|
178
|
+
const globalKey = requireGlobalKey(options);
|
|
129
179
|
const { prefix, sep = "__" } = options;
|
|
130
180
|
const conflict = claimConfigNamespace({ kind: "public", prefix: prefix ?? "", sep });
|
|
131
181
|
if (conflict) {
|
|
132
182
|
throw new ConfigError(conflict);
|
|
133
183
|
}
|
|
134
|
-
const globalKey = globalKeyFor(prefix ?? "");
|
|
135
184
|
const resolve = memoize(() => buildConfig(schema, prefix, sep));
|
|
136
185
|
async function PublicConfigScript({ nonce }) {
|
|
137
186
|
await connection();
|
|
@@ -144,6 +193,14 @@ function publicConfig(schema, options = {}) {
|
|
|
144
193
|
}
|
|
145
194
|
export {
|
|
146
195
|
ConfigError,
|
|
147
|
-
|
|
196
|
+
boolean,
|
|
197
|
+
caster,
|
|
198
|
+
commaSeparatedFloatList,
|
|
199
|
+
commaSeparatedIntList,
|
|
200
|
+
commaSeparatedList,
|
|
201
|
+
float,
|
|
202
|
+
integer,
|
|
203
|
+
publicConfig,
|
|
204
|
+
string
|
|
148
205
|
};
|
|
149
206
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/next/config/index.tsx","../../../src/node/configError.ts","../../../src/node/configCore.ts","../../../src/node/configRegistry.ts","../../../src/next/config/shared.ts"],"sourcesContent":["import { connection } from 'next/server'\n\nimport { type ConfigSchema, type InferConfig, buildConfig } from '../../node/configCore'\nimport { ConfigError } from '../../node/configError'\nimport { claimConfigNamespace } from '../../node/configRegistry'\n// Imported by built path, and marked external in tsup.next-config.config.ts, so esbuild leaves\n// the import alone instead of inlining insert.tsx into this bundle - which would concatenate\n// modules ahead of its `'use client'` directive and destroy it.\nimport { PublicConfigInsert } from './insert.js'\nimport {\n type PublicConfig,\n type PublicConfigOptions,\n type PublicConfigScriptProps,\n globalKeyFor,\n lazyConfigProxy,\n memoize,\n serializePublicConfigScript,\n} from './shared'\n\nexport { ConfigError } from '../../node/configError'\nexport type { ConfigSchema, InferConfig } from '../../node/configCore'\nexport type { PublicConfig, PublicConfigOptions, PublicConfigScriptComponent, PublicConfigScriptProps } from './shared'\n\n/**\n * The browser-visible sibling of `config()`: same schema, same casters, same variable naming, but\n * the resolved values are serialized into the document so client components can read them at\n * runtime. Returns the config object plus the component that injects it, which the root layout\n * renders exactly once.\n *\n * Everything in `schema` ends up in the HTML of every page, in plaintext. The prefix claimed here\n * must not overlap one already claimed by `config()`, so a server-only key pasted into this\n * schema by mistake resolves to nothing and throws rather than getting published.\n *\n * Values are read per request, not baked in at build - which is the entire point next to\n * `NEXT_PUBLIC_*`, and what lets one image run in staging and production. Nothing resolves until\n * something reads it, so `next build` needs none of these variables set.\n */\nexport function publicConfig<S extends ConfigSchema>(schema: S, options: PublicConfigOptions = {}): PublicConfig<S> {\n const { prefix, sep = '__' } = options\n\n const conflict = claimConfigNamespace({ kind: 'public', prefix: prefix ?? '', sep })\n if (conflict) {\n throw new ConfigError(conflict)\n }\n\n const globalKey = globalKeyFor(prefix ?? '')\n const resolve = memoize(() => buildConfig(schema, prefix, sep))\n\n async function PublicConfigScript({ nonce }: PublicConfigScriptProps) {\n // Opts the route out of static prerendering, so the values are read on the request rather\n // than frozen into the build output. Under Cache Components this has to sit inside a\n // <Suspense> boundary - see docs/next/config.md.\n await connection()\n return <PublicConfigInsert script={serializePublicConfigScript(globalKey, resolve())} nonce={nonce} />\n }\n\n return {\n CONFIG: lazyConfigProxy<InferConfig<S>>(resolve),\n PublicConfigScript,\n }\n}\n","/**\n * Isolated in its own module - with no `process.env` access anywhere in it - so that the browser\n * half of `@isikk/core/next/config` can throw the same error type without importing\n * anything that reads the environment. Keeping the split structural means the guarantee holds\n * because of what the file contains, not because a bundler happened to tree-shake it away.\n */\nexport class ConfigError extends Error {}\n","import type { Caster } from './casters'\nimport { ConfigError } from './configError'\n\nexport type ConfigSchema = { [key: string]: Caster<unknown> | ConfigSchema }\n\nexport type InferConfig<S> = {\n [K in keyof S]: S[K] extends Caster<infer T> ? T : S[K] extends ConfigSchema ? InferConfig<S[K]> : never\n}\n\nexport interface ConfigOptions {\n /** Prepended to every environment variable name this call reads, joined with `sep`. */\n prefix?: string\n /** Joins the prefix and the nested key path into a variable name. Defaults to `\"__\"`. */\n sep?: string\n}\n\nfunction isCaster(value: unknown): value is Caster<unknown> {\n return typeof value === 'function'\n}\n\nfunction environmentKey(prefix: string | undefined, path: string[], sep: string): string {\n return [...(prefix ? [prefix] : []), ...path].join(sep)\n}\n\nfunction readLeaf<T>(leafCaster: Caster<T>, key: string): T {\n const rawValue = process.env[key]\n\n if (rawValue === undefined) {\n if ('missingDefault' in leafCaster) {\n return leafCaster.missingDefault as T\n }\n throw new ConfigError(\n `Environment variable ${key} not found. Please set it or provide a missingDefault to your caster.`\n )\n }\n\n try {\n return leafCaster(rawValue)\n } catch (error) {\n if ('errorDefault' in leafCaster) {\n return leafCaster.errorDefault as T\n }\n throw new ConfigError(\n `Error while parsing ${key}=${JSON.stringify(rawValue)}: ${error instanceof Error ? error.message : String(error)}. ` +\n 'Please check the value and the caster, or provide an errorDefault to your caster.'\n )\n }\n}\n\n/**\n * Walks the schema and reads every leaf out of `process.env`. Shared by `config()` and by the\n * server half of `publicConfig()` so the two agree on variable naming and on the\n * `missingDefault`/`errorDefault` fallback rules by construction rather than by duplication.\n * Claims no namespace of its own - that is the caller's job, and the two callers claim different\n * kinds.\n */\nexport function buildConfig<S extends ConfigSchema>(\n schema: S,\n prefix: string | undefined,\n sep: string,\n path: string[] = []\n): InferConfig<S> {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(schema)) {\n const keyPath = [...path, key]\n result[key] = isCaster(value)\n ? readLeaf(value, environmentKey(prefix, keyPath, sep))\n : buildConfig(value, prefix, sep, keyPath)\n }\n return result as InferConfig<S>\n}\n","/**\n * Process-wide record of which environment variable namespace each config call has claimed, so a\n * server-only `config()` and a browser-visible `publicConfig()` can be stopped from reading the\n * same one. That overlap is the mistake worth catching: with a shared namespace, a key pasted\n * into the public schema by accident resolves to the real server value and gets serialized into\n * the HTML of every page, silently. With disjoint namespaces it resolves to nothing and throws.\n *\n * Kept on `globalThis` under a `Symbol.for` key rather than in module scope because\n * `@isikk/core/node` and `@isikk/core/next/config` are separate tsup entries built\n * with `splitting: false` - a module-scoped registry would be duplicated into each bundle, giving\n * the two sides one registry each and so nothing to ever collide in.\n *\n * Claims are keyed by kind, so any number of `config()` calls (or any number of `publicConfig()`\n * calls) may share a namespace - two server reads of the same variable are harmless. Only a\n * server/public overlap is a conflict, which is also why re-registration is always safe: Next\n * evaluates the same module once per bundler layer (RSC, SSR, edge) and again on every Fast\n * Refresh, and every one of those repeats is the same kind claiming the same namespace.\n */\nexport type ConfigKind = 'server' | 'public'\n\nexport interface ConfigNamespace {\n kind: ConfigKind\n /** Empty string means \"no prefix\" - the root of the environment. */\n prefix: string\n sep: string\n}\n\nconst REGISTRY_KEY = Symbol.for('@isikk/core/config-namespace-registry')\n\nconst CALL_NAME: Record<ConfigKind, string> = {\n server: 'config()',\n public: 'publicConfig()',\n}\n\nfunction getRegistry(): ConfigNamespace[] {\n const host = globalThis as unknown as Record<symbol, ConfigNamespace[] | undefined>\n const existing = host[REGISTRY_KEY]\n if (existing) {\n return existing\n }\n const created: ConfigNamespace[] = []\n host[REGISTRY_KEY] = created\n return created\n}\n\n/**\n * Two namespaces overlap when one can produce an environment variable name the other can also\n * produce. Identical prefixes always overlap. A prefix nested under another at a separator\n * boundary overlaps too (`APP` and `APP__PUBLIC` both reach `APP__PUBLIC__TOKEN`).\n *\n * An absent prefix is deliberately treated as disjoint from every non-empty one rather than as\n * the root that technically contains them all: unprefixed server config alongside prefixed public\n * config is the most natural setup there is, and the only way it actually collides is a server\n * schema with a top-level key named exactly like the public prefix. Rejecting the whole shape to\n * catch that would cost far more than it buys - docs/next/config.md says so out loud.\n */\nfunction namespacesOverlap(a: ConfigNamespace, b: ConfigNamespace): boolean {\n if (a.prefix === b.prefix) {\n return true\n }\n if (a.prefix === '' || b.prefix === '') {\n return false\n }\n return a.prefix.startsWith(`${b.prefix}${b.sep}`) || b.prefix.startsWith(`${a.prefix}${a.sep}`)\n}\n\nfunction describeNamespace(namespace: ConfigNamespace): string {\n return namespace.prefix === '' ? 'no prefix' : `prefix ${JSON.stringify(namespace.prefix)}`\n}\n\n/**\n * Records `claim`, returning `null` when it is allowed or an explanatory message when it overlaps\n * a namespace already claimed by the other kind. Returns the message instead of throwing so each\n * entry point can throw its own bundled copy of `ConfigError`, keeping `instanceof` working\n * against the class imported from the same entry point the call came from.\n */\nexport function claimConfigNamespace(claim: ConfigNamespace): string | null {\n const registry = getRegistry()\n\n for (const existing of registry) {\n if (existing.kind !== claim.kind && namespacesOverlap(existing, claim)) {\n return (\n `${CALL_NAME[claim.kind]} was called with ${describeNamespace(claim)}, but ` +\n `${CALL_NAME[existing.kind]} already claimed ${describeNamespace(existing)} - they would read ` +\n 'the same environment variable namespace, so a key added to the public schema can resolve to ' +\n 'a server-only value and be serialized into the browser. Give one of them a prefix the other ' +\n 'does not use.'\n )\n }\n }\n\n const alreadyClaimed = registry.some(\n (existing) => existing.kind === claim.kind && existing.prefix === claim.prefix && existing.sep === claim.sep\n )\n if (!alreadyClaimed) {\n registry.push(claim)\n }\n\n return null\n}\n\n/** Test-only reset. Deliberately not re-exported from any of the package's public entry points. */\nexport function resetConfigNamespaces(): void {\n getRegistry().length = 0\n}\n","import type { ReactNode } from 'react'\n\nimport type { ConfigSchema, InferConfig } from '../../node/configCore'\n\nexport interface PublicConfigOptions {\n /** Prepended to every environment variable name this call reads, joined with `sep`. */\n prefix?: string\n /** Joins the prefix and the nested key path into a variable name. Defaults to `\"__\"`. */\n sep?: string\n}\n\nexport interface PublicConfigScriptProps {\n /** Forwarded to the injected `<script>` so a CSP with a per-request nonce keeps working. */\n nonce?: string\n}\n\nexport type PublicConfigScriptComponent = (props: PublicConfigScriptProps) => ReactNode | Promise<ReactNode>\n\nexport interface PublicConfig<S extends ConfigSchema> {\n CONFIG: InferConfig<S>\n PublicConfigScript: PublicConfigScriptComponent\n}\n\nconst GLOBAL_KEY_BASE = '__ISIK_PUBLIC_CONFIG__'\n\n/**\n * Namespaces the injected global by prefix, so two `publicConfig()` calls land on two properties\n * instead of the second one failing to redefine the first. Prefixes are already required to be\n * distinct from any server namespace, which makes them a usable key.\n */\nexport function globalKeyFor(prefix: string): string {\n return prefix === '' ? GLOBAL_KEY_BASE : `${GLOBAL_KEY_BASE}${prefix}__`\n}\n\n/**\n * Encodes a string as a JavaScript string literal that is safe to interpolate into a `<script>`\n * body. `JSON.stringify` alone is not: `</script>` inside a value closes the tag early and drops\n * the rest of the payload into the document as markup, and U+2028/U+2029 are literal line\n * terminators in JavaScript source, so a value containing one produces a syntax error. Escaping\n * `<` covers the first (the sequence can no longer be written) and the two explicit replacements\n * cover the second. `>` and `&` need no handling - a script element is raw text, so nothing in it\n * is parsed as markup or entities once `<` can't start a closing tag.\n */\nexport function jsStringLiteral(value: string): string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029')\n}\n\n/**\n * The script that hands the resolved config to the browser. Values travel as a JSON string parsed\n * at runtime rather than as an object literal: it parses faster than equivalent JS source, and it\n * narrows everything that needs escaping down to the single quoted string handled above.\n *\n * The definition is deep-frozen and non-writable, so nothing can reshape config after hydration,\n * and re-entrant if the script somehow runs twice - redefining a non-configurable property would\n * throw, so an existing key means there is nothing left to do.\n */\nexport function serializePublicConfigScript(key: string, value: unknown): string {\n return (\n '(function(w,k,v){if(k in w)return;' +\n 'var f=function(o){if(o&&typeof o==\"object\"){for(var p in o)f(o[p]);Object.freeze(o)}};' +\n 'f(v);Object.defineProperty(w,k,{value:v,enumerable:true})})' +\n `(window,${jsStringLiteral(key)},JSON.parse(${jsStringLiteral(JSON.stringify(value))}))`\n )\n}\n\nexport function memoize<T>(resolve: () => T): () => T {\n let value: T\n let resolved = false\n return () => {\n if (!resolved) {\n value = resolve()\n resolved = true\n }\n return value\n }\n}\n\n/**\n * Presents `resolve()`'s result as a plain object without calling it until something is actually\n * read. That deferral is load-bearing on both sides of the package. On the server it keeps\n * `next build` from resolving anything while collecting page data, so a missing variable no\n * longer fails the build - \"can this build\" stops depending on \"is this configured\". In the\n * browser it means the injected global is read at access time rather than at chunk-evaluation\n * time, so an async chunk that happens to run before the inline script still sees the config.\n */\nexport function lazyConfigProxy<T>(resolve: () => T): T {\n return new Proxy({} as object, {\n get: (_target, property) => Reflect.get(resolve() as object, property),\n has: (_target, property) => Reflect.has(resolve() as object, property),\n ownKeys: () => Reflect.ownKeys(resolve() as object),\n getOwnPropertyDescriptor: (_target, property) => {\n const descriptor = Reflect.getOwnPropertyDescriptor(resolve() as object, property)\n // The proxy target is an empty object, and a proxy may not report a non-configurable\n // property that its target doesn't have - so re-mark descriptors as configurable, or\n // Object.keys()/JSON.stringify() over the config throw a TypeError.\n return descriptor === undefined ? undefined : { ...descriptor, configurable: true }\n },\n }) as T\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/next/config/index.tsx","../../../src/node/configError.ts","../../../src/node/configCore.ts","../../../src/node/configRegistry.ts","../../../src/next/config/shared.ts","../../../src/node/casters.ts"],"sourcesContent":["import { connection } from 'next/server'\n\nimport { type ConfigSchema, type InferConfig, buildConfig } from '../../node/configCore'\nimport { ConfigError } from '../../node/configError'\nimport { claimConfigNamespace } from '../../node/configRegistry'\n// Imported by built path, and marked external in tsup.next-config.config.ts, so esbuild leaves\n// the import alone instead of inlining insert.tsx into this bundle - which would concatenate\n// modules ahead of its `'use client'` directive and destroy it.\nimport { PublicConfigInsert } from './insert.js'\nimport {\n type PublicConfig,\n type PublicConfigOptions,\n type PublicConfigScriptProps,\n lazyConfigProxy,\n memoize,\n requireGlobalKey,\n serializePublicConfigScript,\n} from './shared'\n\n// Re-exported so a schema can be written without importing `@isikk/core/node`. That entry\n// point's barrel also carries `contextLocal` (async_hooks) and `getFileAsString` (fs), and the\n// schema call site is shared with client components and edge routes by design - so importing\n// casters from there drags Node builtins into bundles that have none, and the build fails. The\n// casters themselves are pure `(value: string) => T` factories, safe in any runtime.\nexport * from '../../node/casters'\nexport { ConfigError } from '../../node/configError'\nexport type { ConfigSchema, InferConfig } from '../../node/configCore'\nexport type { PublicConfig, PublicConfigOptions, PublicConfigScriptComponent, PublicConfigScriptProps } from './shared'\n\n/**\n * The browser-visible sibling of `config()`: same schema, same casters, same variable naming, but\n * the resolved values are serialized into the document so client components can read them at\n * runtime. Returns the config object plus the component that injects it, which the root layout\n * renders exactly once.\n *\n * Everything in `schema` ends up in the HTML of every page, in plaintext. The prefix claimed here\n * must not overlap one already claimed by `config()`, so a server-only key pasted into this\n * schema by mistake resolves to nothing and throws rather than getting published.\n *\n * `options.globalKey` is required - it names the `window` property the payload is injected under,\n * and there is no default to fall back to.\n *\n * Values are read per request, not baked in at build - which is the entire point next to\n * `NEXT_PUBLIC_*`, and what lets one image run in staging and production. Nothing resolves until\n * something reads it, so `next build` needs none of these variables set.\n */\nexport function publicConfig<S extends ConfigSchema>(schema: S, options: PublicConfigOptions): PublicConfig<S> {\n // Validated before the namespace is claimed, so a call that is going to throw anyway doesn't\n // leave a claim behind for the next call to collide with.\n const globalKey = requireGlobalKey(options)\n const { prefix, sep = '__' } = options\n\n const conflict = claimConfigNamespace({ kind: 'public', prefix: prefix ?? '', sep })\n if (conflict) {\n throw new ConfigError(conflict)\n }\n\n const resolve = memoize(() => buildConfig(schema, prefix, sep))\n\n async function PublicConfigScript({ nonce }: PublicConfigScriptProps) {\n // Opts the route out of static prerendering, so the values are read on the request rather\n // than frozen into the build output. Under Cache Components this has to sit inside a\n // <Suspense> boundary - see docs/next/config.md.\n await connection()\n return <PublicConfigInsert script={serializePublicConfigScript(globalKey, resolve())} nonce={nonce} />\n }\n\n return {\n CONFIG: lazyConfigProxy<InferConfig<S>>(resolve),\n PublicConfigScript,\n }\n}\n","/**\n * Isolated in its own module - with no `process.env` access anywhere in it - so that the browser\n * half of `@isikk/core/next/config` can throw the same error type without importing\n * anything that reads the environment. Keeping the split structural means the guarantee holds\n * because of what the file contains, not because a bundler happened to tree-shake it away.\n */\nexport class ConfigError extends Error {}\n","import type { Caster } from './casters'\nimport { ConfigError } from './configError'\n\nexport type ConfigSchema = { [key: string]: Caster<unknown> | ConfigSchema }\n\nexport type InferConfig<S> = {\n [K in keyof S]: S[K] extends Caster<infer T> ? T : S[K] extends ConfigSchema ? InferConfig<S[K]> : never\n}\n\nexport interface ConfigOptions {\n /** Prepended to every environment variable name this call reads, joined with `sep`. */\n prefix?: string\n /** Joins the prefix and the nested key path into a variable name. Defaults to `\"__\"`. */\n sep?: string\n}\n\nfunction isCaster(value: unknown): value is Caster<unknown> {\n return typeof value === 'function'\n}\n\nfunction environmentKey(prefix: string | undefined, path: string[], sep: string): string {\n return [...(prefix ? [prefix] : []), ...path].join(sep)\n}\n\nfunction readLeaf<T>(leafCaster: Caster<T>, key: string): T {\n const rawValue = process.env[key]\n\n if (rawValue === undefined) {\n if ('missingDefault' in leafCaster) {\n return leafCaster.missingDefault as T\n }\n throw new ConfigError(\n `Environment variable ${key} not found. Please set it or provide a missingDefault to your caster.`\n )\n }\n\n try {\n return leafCaster(rawValue)\n } catch (error) {\n if ('errorDefault' in leafCaster) {\n return leafCaster.errorDefault as T\n }\n throw new ConfigError(\n `Error while parsing ${key}=${JSON.stringify(rawValue)}: ${error instanceof Error ? error.message : String(error)}. ` +\n 'Please check the value and the caster, or provide an errorDefault to your caster.'\n )\n }\n}\n\n/**\n * Walks the schema and reads every leaf out of `process.env`. Shared by `config()` and by the\n * server half of `publicConfig()` so the two agree on variable naming and on the\n * `missingDefault`/`errorDefault` fallback rules by construction rather than by duplication.\n * Claims no namespace of its own - that is the caller's job, and the two callers claim different\n * kinds.\n */\nexport function buildConfig<S extends ConfigSchema>(\n schema: S,\n prefix: string | undefined,\n sep: string,\n path: string[] = []\n): InferConfig<S> {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(schema)) {\n const keyPath = [...path, key]\n result[key] = isCaster(value)\n ? readLeaf(value, environmentKey(prefix, keyPath, sep))\n : buildConfig(value, prefix, sep, keyPath)\n }\n return result as InferConfig<S>\n}\n","/**\n * Process-wide record of which environment variable namespace each config call has claimed, so a\n * server-only `config()` and a browser-visible `publicConfig()` can be stopped from reading the\n * same one. That overlap is the mistake worth catching: with a shared namespace, a key pasted\n * into the public schema by accident resolves to the real server value and gets serialized into\n * the HTML of every page, silently. With disjoint namespaces it resolves to nothing and throws.\n *\n * Kept on `globalThis` under a `Symbol.for` key rather than in module scope because\n * `@isikk/core/node` and `@isikk/core/next/config` are separate tsup entries built\n * with `splitting: false` - a module-scoped registry would be duplicated into each bundle, giving\n * the two sides one registry each and so nothing to ever collide in.\n *\n * Claims are keyed by kind, so any number of `config()` calls (or any number of `publicConfig()`\n * calls) may share a namespace - two server reads of the same variable are harmless. Only a\n * server/public overlap is a conflict, which is also why re-registration is always safe: Next\n * evaluates the same module once per bundler layer (RSC, SSR, edge) and again on every Fast\n * Refresh, and every one of those repeats is the same kind claiming the same namespace.\n */\nexport type ConfigKind = 'server' | 'public'\n\nexport interface ConfigNamespace {\n kind: ConfigKind\n /** Empty string means \"no prefix\" - the root of the environment. */\n prefix: string\n sep: string\n}\n\n// Stryker disable next-line StringLiteral: equivalent as far as this module's own behavior goes -\n// any distinct key works identically for read/write here. The specific, namespaced string only\n// matters for avoiding a collision with unrelated code that also stashes state on `globalThis`\n// via `Symbol.for`, which isn't something a test *of this module* can observe or verify.\nconst REGISTRY_KEY = Symbol.for('@isikk/core/config-namespace-registry')\n\nconst CALL_NAME: Record<ConfigKind, string> = {\n server: 'config()',\n public: 'publicConfig()',\n}\n\nfunction getRegistry(): ConfigNamespace[] {\n const host = globalThis as unknown as Record<symbol, ConfigNamespace[] | undefined>\n const existing = host[REGISTRY_KEY]\n if (existing) {\n return existing\n }\n const created: ConfigNamespace[] = []\n host[REGISTRY_KEY] = created\n return created\n}\n\n/**\n * Two namespaces overlap when one can produce an environment variable name the other can also\n * produce. Identical prefixes always overlap. A prefix nested under another at a separator\n * boundary overlaps too (`APP` and `APP__PUBLIC` both reach `APP__PUBLIC__TOKEN`).\n *\n * An absent prefix is deliberately treated as disjoint from every non-empty one rather than as\n * the root that technically contains them all: unprefixed server config alongside prefixed public\n * config is the most natural setup there is, and the only way it actually collides is a server\n * schema with a top-level key named exactly like the public prefix. Rejecting the whole shape to\n * catch that would cost far more than it buys - docs/next/config.md says so out loud.\n */\nfunction namespacesOverlap(a: ConfigNamespace, b: ConfigNamespace): boolean {\n if (a.prefix === b.prefix) {\n return true\n }\n if (a.prefix === '' || b.prefix === '') {\n return false\n }\n return a.prefix.startsWith(`${b.prefix}${b.sep}`) || b.prefix.startsWith(`${a.prefix}${a.sep}`)\n}\n\nfunction describeNamespace(namespace: ConfigNamespace): string {\n return namespace.prefix === '' ? 'no prefix' : `prefix ${JSON.stringify(namespace.prefix)}`\n}\n\nfunction sameNamespace(a: ConfigNamespace, b: ConfigNamespace): boolean {\n // Stryker disable next-line ConditionalExpression: equivalent mutant on the `kind` comparison\n // specifically. Every caller of this function only ever compares entries the earlier conflict\n // check in claimConfigNamespace has already let through - and that check has already returned\n // for any existing entry of a *different* kind whose prefix overlaps claim's, and an equal\n // prefix always overlaps (namespacesOverlap's first check) - so an existing entry with a\n // matching prefix reaching here is guaranteed to already be the same kind. Checking `kind`\n // again can't change it.\n return a.kind === b.kind && a.prefix === b.prefix && a.sep === b.sep\n}\n\n/**\n * Records `claim`, returning `null` when it is allowed or an explanatory message when it overlaps\n * a namespace already claimed by the other kind. Returns the message instead of throwing so each\n * entry point can throw its own bundled copy of `ConfigError`, keeping `instanceof` working\n * against the class imported from the same entry point the call came from.\n */\nexport function claimConfigNamespace(claim: ConfigNamespace): string | null {\n const registry = getRegistry()\n\n for (const existing of registry) {\n if (existing.kind !== claim.kind && namespacesOverlap(existing, claim)) {\n return (\n `${CALL_NAME[claim.kind]} was called with ${describeNamespace(claim)}, but ` +\n `${CALL_NAME[existing.kind]} already claimed ${describeNamespace(existing)} - they would read ` +\n 'the same environment variable namespace, so a key added to the public schema can resolve to ' +\n 'a server-only value and be serialized into the browser. Give one of them a prefix the other ' +\n 'does not use.'\n )\n }\n }\n\n const alreadyClaimed = registry.some((existing) => sameNamespace(existing, claim))\n if (!alreadyClaimed) {\n registry.push(claim)\n }\n\n return null\n}\n\n/** Test-only reset. Deliberately not re-exported from any of the package's public entry points. */\nexport function resetConfigNamespaces(): void {\n getRegistry().length = 0\n}\n\n/**\n * Test-only: number of currently-registered claims, so the growth-prevention in\n * `claimConfigNamespace` (a repeated identical claim - e.g. from Next Fast Refresh re-evaluating\n * the same `config()` call - must not grow the registry) is verifiable without exposing the\n * registry's contents. Deliberately not re-exported from any of the package's public entry points.\n */\nexport function configNamespaceCount(): number {\n return getRegistry().length\n}\n\n/**\n * Test-only: removes the registry from `globalThis` entirely, so the next call that touches it\n * re-creates it from scratch - lets a test observe the freshly-created registry's initial value\n * without duplicating the `Symbol.for` key string. Deliberately not re-exported from any of the\n * package's public entry points.\n */\nexport function deleteConfigNamespaceRegistry(): void {\n delete (globalThis as unknown as Record<symbol, unknown>)[REGISTRY_KEY]\n}\n","import type { ReactNode } from 'react'\n\nimport type { ConfigSchema, InferConfig } from '../../node/configCore'\nimport { ConfigError } from '../../node/configError'\n\nexport interface PublicConfigOptions {\n /**\n * The property the payload is injected under on `window`. Required, with no default and no\n * derived fallback: the name belongs in your application's namespace, not this package's, and\n * naming it at the call site is what stops two configs from silently landing on a name neither\n * of them chose.\n */\n globalKey: string\n /** Prepended to every environment variable name this call reads, joined with `sep`. */\n prefix?: string\n /** Joins the prefix and the nested key path into a variable name. Defaults to `\"__\"`. */\n sep?: string\n}\n\nexport interface PublicConfigScriptProps {\n /** Forwarded to the injected `<script>` so a CSP with a per-request nonce keeps working. */\n nonce?: string\n}\n\nexport type PublicConfigScriptComponent = (props: PublicConfigScriptProps) => ReactNode | Promise<ReactNode>\n\nexport interface PublicConfig<S extends ConfigSchema> {\n CONFIG: InferConfig<S>\n PublicConfigScript: PublicConfigScriptComponent\n}\n\n/**\n * Validates the caller-supplied global key. There is deliberately no default and nothing derived\n * from `prefix` to fall back to: a package-chosen name would put this package's identity into\n * every consuming app's `window`, and - worse - two `publicConfig()` calls could quietly agree on\n * a name neither of them wrote down. Since the payload is injected non-writable, that agreement\n * loses the second config silently in the browser while both still resolve on the server. Making\n * the name mandatory turns that from an invisible default into a line you can read at the call\n * site.\n *\n * Both halves of the module go through this one function, from the same options object: the\n * schema and options live at a single call site in the consuming app, and only the library import\n * flips between builds. That is what makes the two sides agree by construction - a server that\n * wrote one key and a browser that read another would fail with nothing to point at.\n *\n * No character restrictions, since the key is emitted as an escaped string literal and read back\n * with bracket notation. The runtime check covers callers without types, for whom a missing key\n * would otherwise mean reading `window[undefined]`.\n */\nexport function requireGlobalKey(options: PublicConfigOptions): string {\n const { globalKey } = options\n\n if (typeof globalKey !== 'string' || globalKey === '') {\n throw new ConfigError(\n 'publicConfig: globalKey is required and must be a non-empty string - it names the window ' +\n 'property the config is injected under, e.g. { globalKey: \"__MY_APP_CONFIG__\" }. There is no ' +\n 'default, so the name is yours and two configs cannot collide on one neither of them chose.'\n )\n }\n\n return globalKey\n}\n\n/**\n * Encodes a string as a JavaScript string literal that is safe to interpolate into a `<script>`\n * body. `JSON.stringify` alone is not: `</script>` inside a value closes the tag early and drops\n * the rest of the payload into the document as markup, and U+2028/U+2029 are literal line\n * terminators in JavaScript source, so a value containing one produces a syntax error. Escaping\n * `<` covers the first (the sequence can no longer be written) and the two explicit replacements\n * cover the second. `>` and `&` need no handling - a script element is raw text, so nothing in it\n * is parsed as markup or entities once `<` can't start a closing tag.\n */\nexport function jsStringLiteral(value: string): string {\n return JSON.stringify(value)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029')\n}\n\n/**\n * The script that hands the resolved config to the browser. Values travel as a JSON string parsed\n * at runtime rather than as an object literal: it parses faster than equivalent JS source, and it\n * narrows everything that needs escaping down to the single quoted string handled above.\n *\n * The definition is deep-frozen and non-writable, so nothing can reshape config after hydration,\n * and re-entrant if the script somehow runs twice - redefining a non-configurable property would\n * throw, so an existing key means there is nothing left to do.\n */\nexport function serializePublicConfigScript(key: string, value: unknown): string {\n return (\n '(function(w,k,v){if(k in w)return;' +\n 'var f=function(o){if(o&&typeof o==\"object\"){for(var p in o)f(o[p]);Object.freeze(o)}};' +\n 'f(v);Object.defineProperty(w,k,{value:v,enumerable:true})})' +\n `(window,${jsStringLiteral(key)},JSON.parse(${jsStringLiteral(JSON.stringify(value))}))`\n )\n}\n\nexport function memoize<T>(resolve: () => T): () => T {\n let value: T\n let resolved = false\n return () => {\n if (!resolved) {\n value = resolve()\n resolved = true\n }\n return value\n }\n}\n\n/**\n * Presents `resolve()`'s result as a plain object without calling it until something is actually\n * read. That deferral is load-bearing on both sides of the package. On the server it keeps\n * `next build` from resolving anything while collecting page data, so a missing variable no\n * longer fails the build - \"can this build\" stops depending on \"is this configured\". In the\n * browser it means the injected global is read at access time rather than at chunk-evaluation\n * time, so an async chunk that happens to run before the inline script still sees the config.\n */\nexport function lazyConfigProxy<T>(resolve: () => T): T {\n return new Proxy({} as object, {\n get: (_target, property) => Reflect.get(resolve() as object, property),\n has: (_target, property) => Reflect.has(resolve() as object, property),\n ownKeys: () => Reflect.ownKeys(resolve() as object),\n getOwnPropertyDescriptor: (_target, property) => {\n const descriptor = Reflect.getOwnPropertyDescriptor(resolve() as object, property)\n // The proxy target is an empty object, and a proxy may not report a non-configurable\n // property that its target doesn't have - so re-mark descriptors as configurable, or\n // Object.keys()/JSON.stringify() over the config throw a TypeError.\n return descriptor === undefined ? undefined : { ...descriptor, configurable: true }\n },\n }) as T\n}\n","export type Caster<T> = ((value: string) => T) & { missingDefault?: T; errorDefault?: T }\n\nexport function caster<T>(fn: (value: string) => T) {\n return function (options: { missingDefault?: T; errorDefault?: T } = {}): Caster<T> {\n const clone = ((value: string) => fn(value)) as Caster<T>\n if ('missingDefault' in options) {\n clone.missingDefault = options.missingDefault\n }\n if ('errorDefault' in options) {\n clone.errorDefault = options.errorDefault\n }\n return clone\n }\n}\n\n// JS's Number()/parseInt()/parseFloat() don't throw on unparseable input the way Python's int()/\n// float() do (parseInt('123abc') silently returns 123, Number('') silently returns 0) - these\n// helpers add back the \"either it's a clean, fully-parsed number or it throws\" contract the\n// missingDefault/errorDefault fallback system above depends on.\nfunction parseStrictInteger(value: string): number {\n if (value.trim() === '' || !Number.isInteger(Number(value))) {\n throw new Error(`Value ${JSON.stringify(value)} can not be parsed into an integer.`)\n }\n return Number(value)\n}\n\nfunction parseStrictFloat(value: string): number {\n if (value.trim() === '' || Number.isNaN(Number(value))) {\n throw new Error(`Value ${JSON.stringify(value)} can not be parsed into a float.`)\n }\n return Number(value)\n}\n\nexport const string = caster((value: string) => value)\n\nexport const integer = caster(parseStrictInteger)\n\nexport const float = caster(parseStrictFloat)\n\nexport const boolean = caster((value: string) => {\n const truthy = ['true', 'True', '1']\n const falsy = ['false', 'False', '0']\n if (truthy.includes(value)) {\n return true\n }\n if (falsy.includes(value)) {\n return false\n }\n throw new Error(`Value ${JSON.stringify(value)} can not be parsed into a boolean.`)\n})\n\nexport const commaSeparatedList = caster((value: string) => value.split(','))\n\nexport const commaSeparatedIntList = caster((value: string) => value.split(',').map(parseStrictInteger))\n\nexport const commaSeparatedFloatList = caster((value: string) => value.split(',').map(parseStrictFloat))\n"],"mappings":";AAAA,SAAS,kBAAkB;;;ACMpB,IAAM,cAAN,cAA0B,MAAM;AAAC;;;ACUxC,SAAS,SAAS,OAA0C;AAC1D,SAAO,OAAO,UAAU;AAC1B;AAEA,SAAS,eAAe,QAA4B,MAAgB,KAAqB;AACvF,SAAO,CAAC,GAAI,SAAS,CAAC,MAAM,IAAI,CAAC,GAAI,GAAG,IAAI,EAAE,KAAK,GAAG;AACxD;AAEA,SAAS,SAAY,YAAuB,KAAgB;AAC1D,QAAM,WAAW,QAAQ,IAAI,GAAG;AAEhC,MAAI,aAAa,QAAW;AAC1B,QAAI,oBAAoB,YAAY;AAClC,aAAO,WAAW;AAAA,IACpB;AACA,UAAM,IAAI;AAAA,MACR,wBAAwB,GAAG;AAAA,IAC7B;AAAA,EACF;AAEA,MAAI;AACF,WAAO,WAAW,QAAQ;AAAA,EAC5B,SAAS,OAAO;AACd,QAAI,kBAAkB,YAAY;AAChC,aAAO,WAAW;AAAA,IACpB;AACA,UAAM,IAAI;AAAA,MACR,uBAAuB,GAAG,IAAI,KAAK,UAAU,QAAQ,CAAC,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAEnH;AAAA,EACF;AACF;AASO,SAAS,YACd,QACA,QACA,KACA,OAAiB,CAAC,GACF;AAChB,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,UAAM,UAAU,CAAC,GAAG,MAAM,GAAG;AAC7B,WAAO,GAAG,IAAI,SAAS,KAAK,IACxB,SAAS,OAAO,eAAe,QAAQ,SAAS,GAAG,CAAC,IACpD,YAAY,OAAO,QAAQ,KAAK,OAAO;AAAA,EAC7C;AACA,SAAO;AACT;;;ACvCA,IAAM,eAAe,uBAAO,IAAI,uCAAuC;AAEvE,IAAM,YAAwC;AAAA,EAC5C,QAAQ;AAAA,EACR,QAAQ;AACV;AAEA,SAAS,cAAiC;AACxC,QAAM,OAAO;AACb,QAAM,WAAW,KAAK,YAAY;AAClC,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AACA,QAAM,UAA6B,CAAC;AACpC,OAAK,YAAY,IAAI;AACrB,SAAO;AACT;AAaA,SAAS,kBAAkB,GAAoB,GAA6B;AAC1E,MAAI,EAAE,WAAW,EAAE,QAAQ;AACzB,WAAO;AAAA,EACT;AACA,MAAI,EAAE,WAAW,MAAM,EAAE,WAAW,IAAI;AACtC,WAAO;AAAA,EACT;AACA,SAAO,EAAE,OAAO,WAAW,GAAG,EAAE,MAAM,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,WAAW,GAAG,EAAE,MAAM,GAAG,EAAE,GAAG,EAAE;AAChG;AAEA,SAAS,kBAAkB,WAAoC;AAC7D,SAAO,UAAU,WAAW,KAAK,cAAc,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC;AAC3F;AAEA,SAAS,cAAc,GAAoB,GAA6B;AAQtE,SAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE;AACnE;AAQO,SAAS,qBAAqB,OAAuC;AAC1E,QAAM,WAAW,YAAY;AAE7B,aAAW,YAAY,UAAU;AAC/B,QAAI,SAAS,SAAS,MAAM,QAAQ,kBAAkB,UAAU,KAAK,GAAG;AACtE,aACE,GAAG,UAAU,MAAM,IAAI,CAAC,oBAAoB,kBAAkB,KAAK,CAAC,SACjE,UAAU,SAAS,IAAI,CAAC,oBAAoB,kBAAkB,QAAQ,CAAC;AAAA,IAK9E;AAAA,EACF;AAEA,QAAM,iBAAiB,SAAS,KAAK,CAAC,aAAa,cAAc,UAAU,KAAK,CAAC;AACjF,MAAI,CAAC,gBAAgB;AACnB,aAAS,KAAK,KAAK;AAAA,EACrB;AAEA,SAAO;AACT;;;AHxGA,SAAS,0BAA0B;;;AIyC5B,SAAS,iBAAiB,SAAsC;AACrE,QAAM,EAAE,UAAU,IAAI;AAEtB,MAAI,OAAO,cAAc,YAAY,cAAc,IAAI;AACrD,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,gBAAgB,OAAuB;AACrD,SAAO,KAAK,UAAU,KAAK,EACxB,QAAQ,MAAM,SAAS,EACvB,QAAQ,WAAW,SAAS,EAC5B,QAAQ,WAAW,SAAS;AACjC;AAWO,SAAS,4BAA4B,KAAa,OAAwB;AAC/E,SACE,8LAGW,gBAAgB,GAAG,CAAC,eAAe,gBAAgB,KAAK,UAAU,KAAK,CAAC,CAAC;AAExF;AAEO,SAAS,QAAW,SAA2B;AACpD,MAAI;AACJ,MAAI,WAAW;AACf,SAAO,MAAM;AACX,QAAI,CAAC,UAAU;AACb,cAAQ,QAAQ;AAChB,iBAAW;AAAA,IACb;AACA,WAAO;AAAA,EACT;AACF;AAUO,SAAS,gBAAmB,SAAqB;AACtD,SAAO,IAAI,MAAM,CAAC,GAAa;AAAA,IAC7B,KAAK,CAAC,SAAS,aAAa,QAAQ,IAAI,QAAQ,GAAa,QAAQ;AAAA,IACrE,KAAK,CAAC,SAAS,aAAa,QAAQ,IAAI,QAAQ,GAAa,QAAQ;AAAA,IACrE,SAAS,MAAM,QAAQ,QAAQ,QAAQ,CAAW;AAAA,IAClD,0BAA0B,CAAC,SAAS,aAAa;AAC/C,YAAM,aAAa,QAAQ,yBAAyB,QAAQ,GAAa,QAAQ;AAIjF,aAAO,eAAe,SAAY,SAAY,EAAE,GAAG,YAAY,cAAc,KAAK;AAAA,IACpF;AAAA,EACF,CAAC;AACH;;;AChIO,SAAS,OAAU,IAA0B;AAClD,SAAO,SAAU,UAAoD,CAAC,GAAc;AAClF,UAAM,SAAS,CAAC,UAAkB,GAAG,KAAK;AAC1C,QAAI,oBAAoB,SAAS;AAC/B,YAAM,iBAAiB,QAAQ;AAAA,IACjC;AACA,QAAI,kBAAkB,SAAS;AAC7B,YAAM,eAAe,QAAQ;AAAA,IAC/B;AACA,WAAO;AAAA,EACT;AACF;AAMA,SAAS,mBAAmB,OAAuB;AACjD,MAAI,MAAM,KAAK,MAAM,MAAM,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,GAAG;AAC3D,UAAM,IAAI,MAAM,SAAS,KAAK,UAAU,KAAK,CAAC,qCAAqC;AAAA,EACrF;AACA,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,iBAAiB,OAAuB;AAC/C,MAAI,MAAM,KAAK,MAAM,MAAM,OAAO,MAAM,OAAO,KAAK,CAAC,GAAG;AACtD,UAAM,IAAI,MAAM,SAAS,KAAK,UAAU,KAAK,CAAC,kCAAkC;AAAA,EAClF;AACA,SAAO,OAAO,KAAK;AACrB;AAEO,IAAM,SAAS,OAAO,CAAC,UAAkB,KAAK;AAE9C,IAAM,UAAU,OAAO,kBAAkB;AAEzC,IAAM,QAAQ,OAAO,gBAAgB;AAErC,IAAM,UAAU,OAAO,CAAC,UAAkB;AAC/C,QAAM,SAAS,CAAC,QAAQ,QAAQ,GAAG;AACnC,QAAM,QAAQ,CAAC,SAAS,SAAS,GAAG;AACpC,MAAI,OAAO,SAAS,KAAK,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,MAAI,MAAM,SAAS,KAAK,GAAG;AACzB,WAAO;AAAA,EACT;AACA,QAAM,IAAI,MAAM,SAAS,KAAK,UAAU,KAAK,CAAC,oCAAoC;AACpF,CAAC;AAEM,IAAM,qBAAqB,OAAO,CAAC,UAAkB,MAAM,MAAM,GAAG,CAAC;AAErE,IAAM,wBAAwB,OAAO,CAAC,UAAkB,MAAM,MAAM,GAAG,EAAE,IAAI,kBAAkB,CAAC;AAEhG,IAAM,0BAA0B,OAAO,CAAC,UAAkB,MAAM,MAAM,GAAG,EAAE,IAAI,gBAAgB,CAAC;;;ALS5F;AAlBJ,SAAS,aAAqC,QAAW,SAA+C;AAG7G,QAAM,YAAY,iBAAiB,OAAO;AAC1C,QAAM,EAAE,QAAQ,MAAM,KAAK,IAAI;AAE/B,QAAM,WAAW,qBAAqB,EAAE,MAAM,UAAU,QAAQ,UAAU,IAAI,IAAI,CAAC;AACnF,MAAI,UAAU;AACZ,UAAM,IAAI,YAAY,QAAQ;AAAA,EAChC;AAEA,QAAM,UAAU,QAAQ,MAAM,YAAY,QAAQ,QAAQ,GAAG,CAAC;AAE9D,iBAAe,mBAAmB,EAAE,MAAM,GAA4B;AAIpE,UAAM,WAAW;AACjB,WAAO,oBAAC,sBAAmB,QAAQ,4BAA4B,WAAW,QAAQ,CAAC,GAAG,OAAc;AAAA,EACtG;AAEA,SAAO;AAAA,IACL,QAAQ,gBAAgC,OAAO;AAAA,IAC/C;AAAA,EACF;AACF;","names":[]}
|