@esmalley/ts-utils 6.4.5 → 6.4.6
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/esm/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/Arithmetic.ts", "../../src/Arrayifier.ts", "../../src/CSV.ts", "../../src/Color.ts", "../../src/Dates.ts", "../../src/Kontororu.ts", "../../src/Kontororu/Socket.ts", "../../src/Objector.ts", "../../src/Kontororu/Store.ts", "../../src/Sorter.ts", "../../src/Style.ts", "../../src/Textor.ts", "../../src/Theme.ts", "../../src/Toaster.ts", "../../src/UuidService.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nexport class Arithmetic {\n public static clamp(number: number, min: number, max: number): number {\n return Math.max(min, Math.min(number, max));\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nexport class Arrayifier {\n // constructor() {\n // }\n\n\n /**\n * Shuffle / ranomize elements in an array\n * @param {array} array The array to shuffle\n * @return array\n */\n public static shuffle<T>(array: T[]): T[] {\n let currentIndex: number = array.length;\n let randomIndex: number;\n\n // While there remain elements to shuffle.\n while (currentIndex !== 0) {\n // Pick a remaining element.\n randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex--;\n\n // And swap it with the current element.\n // eslint-disable-next-line no-param-reassign\n [array[currentIndex], array[randomIndex]] = [\n array[randomIndex], array[currentIndex]];\n }\n\n return array;\n }\n\n /**\n * Recursively generates all combinations of size `r` from an array of `n` elements.\n *\n * @param {T[]} arr - The source array to generate combinations from\n * @param {number} n - The total number of elements in `arr` (i.e. arr.length)\n * @param {number} r - The size of each combination to generate\n * @param {number} index - Current position being filled in the combination (increments toward r)\n * @param {T[]} data - Temporary buffer holding the current combination being built\n * @param {number} i - Current index in `arr` being considered for inclusion\n * @param {T[][]} results - Accumulator array that collects each completed combination\n * @returns {T[][]} The accumulated list of all combinations once recursion completes\n *\n * @example\n * combination([1, 2, 3], 3, 2, 0, [], 0, [])\n * // returns [[1, 2], [1, 3], [2, 3]]\n */\n public static combination<T>(\n arr: T[],\n n: number,\n r: number,\n index: number,\n data: T[],\n i: number,\n results: T[][],\n ): T[][] {\n if (index === r) {\n results.push(data.slice(0, r));\n return results;\n }\n\n if (i >= n) {\n return results;\n }\n\n // eslint-disable-next-line no-param-reassign\n data[index] = arr[i];\n this.combination(arr, n, r, index + 1, data, i + 1, results);\n this.combination(arr, n, r, index, data, i + 1, results);\n\n return results;\n }\n\n /**\n * Get all combinations of every value in the provided array for a specified number\n * @param {Array} arr\n * @param {number} n\n * @param {number} r\n * @returns Array\n */\n public static getCombinations<T>(arr: T[], n: number, r: number): T[][] {\n const data: T[] = new Array(r);\n\n let results: T[][] = [];\n results = this.combination(arr, n, r, 0, data, 0, results);\n return results;\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/**\n * Everything to help with CSV generation\n */\nexport class CSV {\n /**\n * Convert an object to a CSV file and then download it\n */\n public static download(data: Record<string, Record<string, unknown>>): void {\n const rows: string[] = [];\n\n let setHeaders = false;\n let headers: string[] = [];\n for (const id in data) {\n const row = data[id];\n\n if (!setHeaders) {\n headers = Object.keys(row);\n rows.push(headers.join(','));\n setHeaders = true;\n }\n\n const values = headers.map((header) => JSON.stringify(row[header] || ''));\n rows.push(values.join(','));\n }\n\n const content = rows.join('\\n');\n\n // Create a Blob and trigger download\n const blob = new Blob([content], { type: 'text/csv' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'srating-data.csv';\n\n // Trigger download and clean up\n document.body.appendChild(a);\n a.click();\n URL.revokeObjectURL(url);\n a.remove();\n }\n}\n", "/* eslint-disable no-param-reassign */\n/* eslint-disable default-case */\n/* eslint-disable no-multi-assign */\n/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/* eslint-disable no-mixed-operators */\n/* eslint-disable no-bitwise */\n\n\nexport class Color {\n // constructor() {\n // }\n\n\n /**\n * A linear interpolator for hexadecimal colors\n * @param {string} a\n * @param {string} b\n * @param {number} amount\n * @example\n * // returns #7F7F7F\n * lerpColor('#000000', '#ffffff', 0.5)\n * @return {string}\n */\n public static lerpColor(a: string, b: string, amount: number): string {\n const ah = +a.replace('#', '0x');\n const ar = ah >> 16;\n const ag = ah >> 8 & 0xff;\n const ab = ah & 0xff;\n\n const bh = +b.replace('#', '0x');\n const br = bh >> 16;\n const bg = bh >> 8 & 0xff;\n const bb = bh & 0xff;\n\n const rr = ar + amount * (br - ar);\n const rg = ag + amount * (bg - ag);\n const rb = ab + amount * (bb - ab);\n\n return `#${((1 << 24) + (rr << 16) + (rg << 8) + rb | 0).toString(16).slice(1)}`;\n }\n\n /**\n * Get a color that will look readable based on a background color\n */\n public static getTextColor(color: string, backgroundColor: string, debug = false): string {\n // Convert hex colors to RGB\n /*\n let [r1, g1, b1] = Color.hexToRgb(color);\n const [r2, g2, b2] = Color.hexToRgb(backgroundColor);\n\n const brightnessBg = Color.calculateBrightness(r2, g2, b2);\n\n const targetBrightness = brightnessBg > 128 ? 50 : 150; // target brightness threshold for contrast\n\n while (true) {\n const brightnessColor = Color.calculateBrightness(r1, g1, b1);\n\n if (\n (brightnessBg > 128 && brightnessColor < targetBrightness) ||\n (brightnessBg <= 128 && brightnessColor > targetBrightness)\n ) {\n break;\n }\n\n if (brightnessBg > 128) {\n r1 = Math.max(0, r1 - 25);\n g1 = Math.max(0, g1 - 25);\n b1 = Math.max(0, b1 - 25);\n } else {\n r1 = Math.min(255, r1 + 25);\n g1 = Math.min(255, g1 + 25);\n b1 = Math.min(255, b1 + 25);\n }\n\n if ((r1 === 0 && g1 === 0 && b1 === 0) || (r1 === 255 && g1 === 255 && b1 === 255)) {\n break; // avoid infinite loop\n }\n }\n\n // Convert back to hex\n return Color.rgbToHex(r1, g1, b1);\n */\n let [r, g, b] = Color.hexToRgb(color);\n const [br, bg, bb] = Color.hexToRgb(backgroundColor);\n const contrastTarget = 4.5;\n\n if (debug) {\n console.log('Color.getContrastRatio([r, g, b], [br, bg, bb])', Color.getContrastRatio([r, g, b], [br, bg, bb]));\n }\n\n if (Color.getContrastRatio([r, g, b], [br, bg, bb]) >= contrastTarget) {\n return Color.rgbToHex(r, g, b);\n }\n\n const contrastToBlack = Color.getContrastRatio([0, 0, 0], [br, bg, bb]);\n const contrastToWhite = Color.getContrastRatio([255, 255, 255], [br, bg, bb]);\n\n const direction: 'lighter' | 'darker' =\n contrastToWhite > contrastToBlack ? 'lighter' : 'darker';\n\n\n if (debug) {\n console.log('contrastToBlack', contrastToBlack);\n console.log('contrastToWhite', contrastToWhite);\n console.log('direction', direction);\n }\n\n const adjust = (c: number, lighter: boolean) => {\n return lighter ? Math.min(255, c + 10) : Math.max(0, c - 10);\n };\n\n for (let i = 0; i < 25; i++) {\n r = adjust(r, direction === 'lighter');\n g = adjust(g, direction === 'lighter');\n b = adjust(b, direction === 'lighter');\n\n if (debug) {\n console.log('Color.getContrastRatio([r, g, b], [br, bg, bb]) 2', Color.getContrastRatio([r, g, b], [br, bg, bb]));\n }\n\n if (Color.getContrastRatio([r, g, b], [br, bg, bb]) >= contrastTarget) {\n break;\n }\n }\n\n return Color.rgbToHex(r, g, b);\n }\n\n public static getContrastRatio(rgb1: [number, number, number], rgb2: [number, number, number]): number {\n const luminance = (r: number, g: number, b: number): number => {\n const a = [r, g, b].map((v) => {\n v /= 255;\n return v <= 0.03928\n ? v / 12.92\n : Math.pow((v + 0.055) / 1.055, 2.4);\n });\n return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;\n };\n\n const lum1 = luminance(...rgb1) + 0.05;\n const lum2 = luminance(...rgb2) + 0.05;\n\n return lum1 > lum2 ? lum1 / lum2 : lum2 / lum1;\n }\n\n /**\n * Take a hex (#fff) and an amount and darken the color, return a hex\n * @param {string} hex\n * @param {number} amount\n * @return {string} hex\n */\n // public static darken(hex: string, amount: number = 0.02): string {\n // const [r, g, b] = this.hexToRgb(hex);\n // const [h, s, l] = this.rgbToHsl(r, g, b);\n\n // const newL = Math.max(0, (l / 100) - amount) * 100;\n // const [r2, g2, b2] = this.hslToRgb(h, s, newL);\n\n // return this.rgbToHex(r2, g2, b2);\n // }\n\n /**\n * Take a hex (#fff) and an amount and lighten the color, return a hex\n * @param {string} hex\n * @param {number} amount\n * @return {string} hex\n */\n // public static lighten(hex: string, amount: number = 0.02): string {\n // const [r, g, b] = this.hexToRgb(hex);\n // const [h, s, l] = this.rgbToHsl(r, g, b);\n\n // const newL = Math.min(1, (l / 100) + amount) * 100;\n // const [r2, g2, b2] = this.hslToRgb(h, s, newL);\n\n // return this.rgbToHex(r2, g2, b2);\n // }\n\n /**\n * Mixes the color with black to create a Shade.\n * Prevents the \"muddy/brown\" look of HSL darkening.\n * @param {string} hex - The color to darken\n * @param {number} amount - 0 to 1 (e.g. 0.1 is 10% darker)\n * @return {string} hex\n */\n public static darken(hex: string, amount: number = 0.1): string {\n const [r, g, b] = this.hexToRgb(hex);\n\n // Calculate new color by mixing with black (0)\n // Formula: Current * (1 - amount)\n const remaining = 1 - amount;\n const r2 = Math.round(r * remaining);\n const g2 = Math.round(g * remaining);\n const b2 = Math.round(b * remaining);\n\n return this.rgbToHex(r2, g2, b2);\n }\n\n /**\n * Mixes the color with white to create a Tint.\n * cleaner and less \"washed out\" than HSL lightness adjustment.\n * @param {string} hex - The color to lighten\n * @param {number} amount - 0 to 1 (e.g. 0.1 is 10% lighter)\n * @return {string} hex\n */\n public static lighten(hex: string, amount: number = 0.1): string {\n const [r, g, b] = this.hexToRgb(hex);\n\n // Calculate new color by mixing with white (255)\n // Formula: Current + ((Target - Current) * amount)\n const r2 = Math.round(r + (255 - r) * amount);\n const g2 = Math.round(g + (255 - g) * amount);\n const b2 = Math.round(b + (255 - b) * amount);\n\n return this.rgbToHex(r2, g2, b2);\n }\n\n\n public static shadeColor(hex: string, percent: number): string {\n let [r, g, b] = Color.hexToRgb(hex);\n\n r = Math.min(255, Math.max(0, Math.round(r + (r * (percent / 100)))));\n g = Math.min(255, Math.max(0, Math.round(g + (g * (percent / 100)))));\n b = Math.min(255, Math.max(0, Math.round(b + (b * (percent / 100)))));\n\n return Color.rgbToHex(r, g, b);\n }\n\n\n /**\n * Are 2 colors similar to each other?\n * @param {string} color1\n * @param {string} color2\n * @param {number} threshold\n * @return {boolean}\n */\n public static areColorsSimilar(color1: string, color2: string, threshold = 50): boolean {\n const distance = Color.colorDistance(color1, color2);\n return distance < threshold;\n }\n\n\n /**\n * Inverts a hex color\n * @param {string} hex\n * @return {string} hex\n */\n public static invertColor(hex: string): string {\n const [r, g, b] = Color.hexToRgb(hex);\n\n // Invert each color component\n const invertedR = 255 - r;\n const invertedG = 255 - g;\n const invertedB = 255 - b;\n\n return Color.rgbToHex(invertedR, invertedG, invertedB);\n }\n\n\n /**\n * Takes a hex (#fff) and returns an rgba with the provided alpha\n * @param {string} hex\n * @param {number} alpha\n * @return {string} rgba()\n */\n public static alphaColor(hex: string, alpha: number): string {\n const [r, g, b] = this.hexToRgb(hex);\n\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n }\n\n\n /**\n * Gets analogous colors\n * @param {string} hex\n * @return {Array<string>}\n */\n public static getAnalogousColors(hex: string): string[] {\n const [r, g, b] = Color.hexToRgb(hex);\n const [h, s, l] = Color.rgbToHsl(r, g, b);\n\n const analogousColors: string[] = [];\n const offset = 30; // Offset for analogous colors, usually 30 degrees\n\n for (let i = -1; i <= 1; i++) {\n if (i !== 0) {\n const newHue = (h + i * offset + 360) % 360;\n const [newR, newG, newB] = Color.hslToRgb(newHue, s, l);\n analogousColors.push(Color.rgbToHex(newR, newG, newB));\n }\n }\n\n return analogousColors;\n }\n\n\n /**\n * Convert hex to rgb\n * @param {string} hex\n * @return {Array} rgb\n */\n public static hexToRgb(hex: string): Array<number> {\n // Remove the hash at the start if it's there\n let h = hex.replace(/^#/, '');\n\n // Handle 3-character hex codes by expanding them to 6-character\n if (h.length === 3) {\n h = h.split('').map((char) => { return char + char; }).join('');\n }\n\n // Ensure it's a valid 6-character hex code\n if (h.length !== 6) {\n throw new Error(`Invalid hex color format: ${hex}`);\n }\n\n // Parse r, g, b values\n const bigint = parseInt(h, 16);\n const r = (bigint >> 16) & 255;\n const g = (bigint >> 8) & 255;\n const b = bigint & 255;\n\n return [r, g, b];\n }\n\n\n /**\n * Convert rgb to hex\n * @param {number} r\n * @param {number} g\n * @param {number} b\n * @return {string}\n */\n private static rgbToHex(r: number, g: number, b: number): string {\n return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()}`;\n }\n\n private static rgbToHsl(r: number, g: number, b: number) {\n r /= 255;\n g /= 255;\n b /= 255;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n let h = 0;\n let s = 0;\n const l = (max + min) / 2;\n\n if (max === min) {\n h = s = 0; // achromatic\n } else {\n const d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n case g: h = (b - r) / d + 2; break;\n case b: h = (r - g) / d + 4; break;\n }\n h /= 6;\n }\n return [h * 360, s * 100, l * 100];\n }\n\n private static hslToRgb(h: number, s: number, l: number) {\n let r;\n let g;\n let b;\n h /= 360;\n s /= 100;\n l /= 100;\n\n if (s === 0) {\n r = g = b = l; // achromatic\n } else {\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 3) return q;\n if (t < 1 / 2) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n r = hue2rgb(p, q, h + 1 / 3);\n g = hue2rgb(p, q, h);\n b = hue2rgb(p, q, h - 1 / 3);\n }\n\n return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];\n }\n\n private static calculateBrightness(r: number, g: number, b: number): number {\n // Calculate the brightness of the color\n return (r * 299 + g * 587 + b * 114) / 1000;\n }\n\n private static colorDistance(color1: string, color2: string): number {\n const [r1, g1, b1] = Color.hexToRgb(color1);\n const [r2, g2, b2] = Color.hexToRgb(color2);\n\n const dr = r1 - r2;\n const dg = g1 - g2;\n const db = b1 - b2;\n\n return Math.sqrt(dr * dr + dg * dg + db * db);\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/* eslint-disable one-var-declaration-per-line */\n/* eslint-disable one-var */\n\nimport { IANATimeZone } from './Timezones.js';\n\n\nexport class Dates {\n // constructor() {\n // }\n\n /*\n * Robust Date Parsing\n * Handles:\n * - Date Objects / Numbers (Timestamps)\n * - ISO Strings (2025-01-01) -> Forces Local Midnight\n * - US Formats (01/05/2026)\n * - Mixed Time Formats (23:00 pm, 5:00pm, 14:30:00)\n */\n public static parse(\n str?: Date | string | number | undefined | null,\n utc = false,\n ): Date {\n // 1. Handle Null / Undefined -> Return Now\n if (!str) {\n return new Date();\n }\n\n // 2. Handle Existing Date Objects -> Return Copy\n if (str instanceof Date) {\n return new Date(str.getTime());\n }\n\n // 3. Handle Timestamps (Numbers)\n if (typeof str === 'number') {\n return new Date(str);\n }\n\n // 4. Handle Strings\n if (typeof str === 'string') {\n const input = str.trim();\n\n // CASE A: Strict ISO Date \"YYYY-MM-DD\"\n // Native JS parses this as UTC Midnight, which often shows as\n // previous day 7pm EST. We force \"T00:00:00\" to make it Local Midnight.\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) {\n return utc ? new Date(`${input}T00:00:00Z`) : new Date(`${input}T00:00:00`);\n }\n\n // CASE B: Manual Parsing for Complex Strings\n // This handles \"2026-01-05 23:03:19 pm\", \"01/05/2026\", etc.\n\n // Step 1: Extract Date Part (YYYY-MM-DD or MM/DD/YYYY)\n // Regex looks for: (Group 1: Year/Month) -or/ (Group 2: Month/Day) -or/ (Group 3: Day/Year)\n let year, month, day, timePart = '';\n\n // Match YYYY-MM-DD or YYYY/MM/DD\n const isoMatch = input.match(/^(\\d{4})[-/](\\d{1,2})[-/](\\d{1,2})(.*)$/);\n\n // Match MM/DD/YYYY or MM-DD-YYYY\n const usMatch = input.match(/^(\\d{1,2})[-/](\\d{1,2})[-/](\\d{4})(.*)$/);\n\n if (isoMatch) {\n year = parseInt(isoMatch[1], 10);\n month = parseInt(isoMatch[2], 10) - 1; // JS Months are 0-11\n day = parseInt(isoMatch[3], 10);\n timePart = isoMatch[4];\n } else if (usMatch) {\n year = parseInt(usMatch[3], 10);\n month = parseInt(usMatch[1], 10) - 1;\n day = parseInt(usMatch[2], 10);\n timePart = usMatch[4];\n } else {\n // Fallback: Let the browser try its best if our regex fails\n const d = new Date(input);\n return isNaN(d.getTime()) ? new Date() : d;\n }\n\n // Step 2: Extract Time Part\n let hours = 0;\n let minutes = 0;\n let seconds = 0;\n\n // Look for HH:MM(:SS) and optional AM/PM in the remaining string\n if (timePart && timePart.trim().length > 0) {\n // Matches: 23:03, 23:03:19, 5:00pm, 5:00 pm\n const timeMatch = timePart.match(/(\\d{1,2}):(\\d{1,2})(?::(\\d{1,2}))?\\s*(am|pm|AM|PM)?/);\n\n if (timeMatch) {\n hours = parseInt(timeMatch[1], 10);\n minutes = parseInt(timeMatch[2], 10);\n seconds = timeMatch[3] ? parseInt(timeMatch[3], 10) : 0;\n const meridiem = timeMatch[4] ? timeMatch[4].toLowerCase() : null;\n\n // Step 3: Normalize Hours (12h to 24h)\n if (meridiem === 'pm' && hours < 12) {\n hours += 12;\n }\n if (meridiem === 'am' && hours === 12) {\n hours = 0;\n }\n // Note: If input is \"23:00 pm\", we ignore the 'pm' because 23 > 12.\n }\n }\n\n if (utc) {\n return new Date(Date.UTC(year, month, day, hours, minutes, seconds));\n }\n\n // Step 4: Construct Date in Local Time\n return new Date(year, month, day, hours, minutes, seconds);\n }\n\n return new Date();\n }\n\n public static getMonthsShort(): string[] {\n return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n }\n\n public static getMonths(): string[] {\n return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\n }\n\n public static getDaysShort(): string[] {\n return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n }\n\n public static getDays(): string[] {\n return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n }\n\n /**\n * Format a date using php syntax\n *\n | Token | Meaning | Example |\n | ----- | ------------------------- | ------- |\n | `Y` | 4-digit year | 2025 |\n | `y` | 2-digit year | 25 |\n | `m` | 2-digit month | 03 |\n | `n` | month (no leading zero) | 3 |\n | `d` | day (2-digit) | 09 |\n | `j` | day (no leading zero) | 9 |\n | `S` | Ordinal suffix | th |\n | `H` | 24-hour | 14 |\n | `G` | 24-hour (no leading zero) | 14 |\n | `h` | 12-hour | 02 |\n | `g` | 12-hour (no leading zero) | 2 |\n | `i` | minutes | 05 |\n | `s` | seconds | 09 |\n | `A` | AM/PM | PM |\n | `a` | am/pm | pm |\n | `w` | day of week (0\u20136) | 1 |\n | `N` | day of week (1\u20137) | 2 |\n | `M` | short month name | Mar |\n | `F` | full month name | March |\n | `D` | short weekday | Mon |\n | `l` | full weekday | Monday |\n | `T` | Timezone abbreviation | EST |\n | `e` | Timezone identifier | America/New_York |\n */\n public static format(dateInput: Date | string, format: string, utc = false): string {\n const date = this.parse(dateInput);\n const pad = (n: number) => String(n).padStart(2, '0');\n\n const monthsShort = this.getMonthsShort();\n const monthsLong = this.getMonths();\n const daysShort = this.getDaysShort();\n const daysLong = this.getDays();\n\n const Y = utc ? date.getUTCFullYear() : date.getFullYear();\n const y = String(Y).slice(-2);\n const month = utc ? date.getUTCMonth() : date.getMonth();\n const dateNum = utc ? date.getUTCDate() : date.getDate();\n const day = utc ? date.getUTCDay() : date.getDay();\n const hours = utc ? date.getUTCHours() : date.getHours();\n const minutes = utc ? date.getUTCMinutes() : date.getMinutes();\n const seconds = utc ? date.getUTCSeconds() : date.getSeconds();\n\n // Dynamically look up current runtime/system timezone strings\n const tzAbbr = utc\n ? 'UTC'\n : new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' })\n .format(date)\n .split(', ')\n .pop() || '';\n\n const tzIdentifier = utc\n ? 'UTC'\n : new Intl.DateTimeFormat('en-US', { timeZoneName: 'long' })\n .resolvedOptions().timeZone || '';\n\n // Logic for ordinal suffix (st, nd, rd, th)\n const getOrdinalSuffix = (n: number) => {\n const v = n % 100;\n // 11th, 12th, 13th are exceptions to the 1st, 2nd, 3rd rule\n if (v >= 11 && v <= 13) {\n return 'th';\n }\n\n switch (n % 10) {\n case 1: {\n return 'st';\n }\n case 2: {\n return 'nd';\n }\n case 3: {\n return 'rd';\n }\n default: {\n return 'th';\n }\n }\n };\n\n const tokens: Record<string, string> = {\n /// Year\n Y: String(Y),\n y,\n\n // Month\n m: pad(month + 1),\n n: String(month + 1),\n M: monthsShort[month],\n F: monthsLong[month],\n\n // Day\n d: pad(dateNum),\n j: String(dateNum),\n D: daysShort[day],\n l: daysLong[day],\n w: String(day), // 0 (Sun) - 6\n N: String(day === 0 ? 7 : day), // 1 (Mon) - 7 (Sun)\n S: getOrdinalSuffix(dateNum),\n\n // Time\n H: pad(hours),\n G: String(hours),\n h: pad(((hours + 11) % 12) + 1),\n g: String(((hours + 11) % 12) + 1),\n i: pad(minutes),\n s: pad(seconds),\n\n // AM/PM\n A: hours < 12 ? 'AM' : 'PM',\n a: hours < 12 ? 'am' : 'pm',\n\n // Timezone\n T: tzAbbr,\n e: tzIdentifier,\n };\n\n // Replace tokens using regex\n return format.replace(/\\\\(.)|([a-zA-Z])/g, (_, esc, token) => {\n if (esc) {\n // literal escaped char like \\H or \\Y \u2192 return the raw letter\n return esc;\n }\n return tokens[token] ?? token;\n });\n }\n\n public static add(date: Date | string, amount: number, unit: 'years' | 'months' | 'days' | 'hours' | 'minutes'): Date {\n const d = this.parse(date);\n\n if (unit === 'years') {\n const originalDay = d.getDate();\n d.setFullYear(d.getFullYear() + amount);\n // Handle Leap Year Rollover:\n // Feb 29, 2024 + 1 year -> Mar 1, 2025 (Standard JS behavior)\n // If strict \"same day or last day of month\" logic is desired (turning it into Feb 28):\n if (d.getDate() !== originalDay) {\n d.setDate(0); // Set to last day of previous month (Feb 28)\n }\n } else if (unit === 'months') {\n const originalDay = d.getDate();\n d.setMonth(d.getMonth() + amount);\n // Handle rollover: Jan 31 + 1 month -> Feb 28/29\n if (d.getDate() !== originalDay) {\n d.setDate(0); // Set to last day of previous month\n }\n } else if (unit === 'days') {\n // Use setDate to be DST safe (24h addition via ms is unsafe across DST)\n d.setDate(d.getDate() + amount);\n } else {\n const map: Record<'hours' | 'minutes', number> = {\n hours: amount * 60 * 60 * 1000,\n minutes: amount * 60 * 1000,\n };\n // Use getTime() for day/hour/minute units for simple millisecond addition\n d.setTime(d.getTime() + map[unit]);\n }\n\n return d;\n }\n\n public static subtract(\n date: Date | string,\n amount: number,\n unit: 'years' | 'months' | 'days' | 'hours' | 'minutes',\n ): Date {\n return this.add(date, -amount, unit);\n }\n\n public static fromNow(date: Date | string): string {\n const d = this.parse(date);\n const diff = Date.now() - d.getTime();\n const mins = Math.floor(diff / 60000);\n\n if (Math.abs(mins) < 1) {\n return 'just now';\n }\n\n // Handle future dates roughly\n if (mins < 0) {\n return 'in the future';\n }\n\n if (mins < 60) {\n return `${mins}m ago`;\n }\n\n const hours = Math.floor(mins / 60);\n\n if (hours < 24) {\n return `${hours}h ago`;\n }\n\n const days = Math.floor(hours / 24);\n\n return `${days}d ago`;\n }\n\n /**\n * Find the closest date in an array of dates\n */\n public static getClosestDate(dateToMatch: string | Date, datesArray: string[]): string | null {\n if (!datesArray.length) {\n return null;\n }\n\n const matchDate = this.parse(dateToMatch).getTime();\n\n let closestDate: string | null = null;\n let closestDist = Infinity;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const dateStr of datesArray) {\n const currDate = this.parse(dateStr).getTime();\n const dist = Math.abs(currDate - matchDate);\n\n if (dist < closestDist) {\n closestDist = dist;\n closestDate = dateStr;\n } else if (dist === closestDist) {\n // Tie-breaker: Prefer the date that is in the future relative to the matchDate\n // Or if both are same direction, just keep the current one (or implementation defined)\n // Requirement: \"Both 17th and 19th have same dist. It should pick 19th\"\n if (currDate > matchDate) {\n closestDate = dateStr;\n }\n }\n }\n\n return closestDate;\n }\n\n public static getTodayEST(): string {\n return this.format(new Date().toLocaleString('en-US', { timeZone: 'America/New_York' }), 'Y-m-d');\n }\n\n public static getStartOfDay(date: Date | string): Date {\n const d = this.parse(date);\n d.setHours(0, 0, 0, 0);\n return d;\n }\n\n public static getStartOfMonth(date: Date | string): Date {\n const d = this.parse(date);\n d.setDate(1);\n d.setHours(0, 0, 0, 0);\n return d;\n }\n\n public static getStartOfGrid(date: Date | string): Date {\n const d = this.getStartOfMonth(date);\n const dayOfWeek = d.getDay(); // 0 (Sunday) is the start in standard JS\n\n // Move back to the beginning of the week\n const result = this.parse(d);\n // Subtract days to get to the start of the week (Sunday)\n result.setDate(d.getDate() - dayOfWeek);\n return result;\n }\n\n public static isSameDay(date1: Date | string, date2: Date | string): boolean {\n if (!date1 || !date2) {\n return false;\n }\n const d1 = this.parse(date1);\n const d2 = this.parse(date2);\n\n return (\n d1.getFullYear() === d2.getFullYear() &&\n d1.getMonth() === d2.getMonth() &&\n d1.getDate() === d2.getDate()\n );\n }\n\n // Helper to check if one date is before another (ignoring time)\n public static isBeforeDay(date1: Date | string, date2: Date | string): boolean {\n if (!date1 || !date2) {\n return false;\n }\n return this.getStartOfDay(date1).getTime() < this.getStartOfDay(date2).getTime();\n }\n\n // Helper to check if one date is after another (ignoring time)\n public static isAfterDay(date1: Date | string, date2: Date | string): boolean {\n if (!date1 || !date2) {\n return false;\n }\n return this.getStartOfDay(date1).getTime() > this.getStartOfDay(date2).getTime();\n }\n\n /**\n * Determines if a given date is observing Daylight Saving Time (DST)\n * relative to the runtime's local timezone.\n */\n public static isDST(dateInput?: Date | string | number | null): boolean {\n const d = this.parse(dateInput);\n const year = d.getFullYear();\n\n // Get the timezone offset for January 1st and July 1st of the same year\n const janOffset = new Date(year, 0, 1).getTimezoneOffset();\n const julOffset = new Date(year, 6, 1).getTimezoneOffset();\n\n // The standard time offset is always the maximum of the two.\n // Example (New York): EST is 300 mins behind UTC, EDT is 240 mins. Max is 300.\n // Example (Sydney): AEST is -600 mins, AEDT is -660 mins. Max is -600.\n const standardTimezoneOffset = Math.max(janOffset, julOffset);\n\n // If the date's offset is less than the standard offset, it is in DST\n return d.getTimezoneOffset() < standardTimezoneOffset;\n }\n\n /**\n * Extracts the exact wall-clock date and time components for a specific timezone.\n * @param dateInput The date to evaluate (defaults to now)\n * @param timeZone The target IANA timezone (e.g., 'America/New_York')\n * @returns An object containing numeric date components (month is 1-12)\n */\n public static getPartsInZone(\n dateInput?: Date | string | number | null,\n timeZone: IANATimeZone = 'America/New_York',\n ): {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n second: number;\n weekday: string;\n } {\n const d = this.parse(dateInput);\n\n const allTimeZones = Intl.supportedValuesOf('timeZone');\n\n if (!allTimeZones.includes(timeZone)) {\n throw new Error('Unsupported timeZone.');\n }\n\n const formatter = new Intl.DateTimeFormat('en-US', {\n timeZone,\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n weekday: 'long', // Adds \"Monday\", \"Tuesday\", etc. to the output\n hourCycle: 'h23',\n });\n\n const parts = formatter.formatToParts(d);\n\n const getPart = (type: Intl.DateTimeFormatPartTypes) => parseInt(parts.find((p) => p.type === type)?.value || '0', 10);\n\n const weekday = parts.find((p) => p.type === 'weekday')?.value || '';\n\n return {\n year: getPart('year'),\n month: getPart('month'), // 1-12 format\n day: getPart('day'),\n hour: getPart('hour'), // 0-23 format\n minute: getPart('minute'),\n second: getPart('second'),\n weekday,\n };\n }\n\n /**\n * Calculates the difference between two dates (`date1 - date2`).\n *\n * @param date1 Primary date\n * @param date2 Comparison date (defaults to current time)\n * @param utc Whether to parse strings as UTC\n */\n public static diff(\n date1: Date | string | number,\n date2: Date | string | number = new Date(),\n utc = false,\n ): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\n weeks: number;\n months: number;\n years: number;\n abs: {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\n weeks: number;\n months: number;\n years: number;\n }\n } {\n const d1 = this.parse(date1, utc);\n const d2 = this.parse(date2, utc);\n\n const ms = d1.getTime() - d2.getTime();\n\n // Calendar-based month and year differences\n const y1 = utc ? d1.getUTCFullYear() : d1.getFullYear();\n const y2 = utc ? d2.getUTCFullYear() : d2.getFullYear();\n const m1 = utc ? d1.getUTCMonth() : d1.getMonth();\n const m2 = utc ? d2.getUTCMonth() : d2.getMonth();\n\n const months = (y1 - y2) * 12 + (m1 - m2);\n const years = y1 - y2;\n\n const seconds = Math.trunc(ms / 1000);\n const minutes = Math.trunc(ms / (1000 * 60));\n const hours = Math.trunc(ms / (1000 * 60 * 60));\n const days = Math.trunc(ms / (1000 * 60 * 60 * 24));\n const weeks = Math.trunc(ms / (1000 * 60 * 60 * 24 * 7));\n\n return {\n milliseconds: ms,\n seconds,\n minutes,\n hours,\n days,\n weeks,\n months,\n years,\n // Helper containing absolute (positive) values\n abs: {\n milliseconds: Math.abs(ms),\n seconds: Math.abs(seconds),\n minutes: Math.abs(minutes),\n hours: Math.abs(hours),\n days: Math.abs(days),\n weeks: Math.abs(weeks),\n months: Math.abs(months),\n years: Math.abs(years),\n },\n };\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n// \u30B3\u30F3\u30C8\u30ED\u30FC\u30EB\n\ntype Listeners = Array<(...args: unknown[]) => void>;\n\nexport class Kontororu extends EventTarget {\n constructor() {\n super();\n this.listeners = {};\n }\n\n private listeners: {\n [type: string]: Listeners;\n };\n\n addEventListener(type: string, listener: (...args: unknown[]) => void): this {\n super.addEventListener(type, listener);\n\n if (!this.listeners[type]) {\n this.listeners[type] = [];\n }\n this.listeners[type].push(listener);\n\n return this;\n }\n\n removeEventListener(type: string, listener: (...args: unknown[]) => void): this {\n super.removeEventListener(type, listener);\n\n if (this.listeners[type]) {\n this.listeners[type] = this.listeners[type].filter((l) => l !== listener);\n }\n\n return this;\n }\n\n removeAllEventListeners() {\n for (const type in this.listeners) {\n for (let i = this.listeners[type].length; i >= 0; i--) {\n this.removeEventListener(type, this.listeners[type][i]);\n }\n }\n }\n\n getListeners(type: string): Listeners | [] {\n return this.listeners[type] || [];\n }\n}\n\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nimport { Kontororu } from '../Kontororu.js';\n\n\ninterface SocketConfig {\n hostname: string;\n port?: string | number;\n path: string;\n}\n\ntype ConnectionState = 'connected' | 'stale' | 'disconnected' | 'reconnected';\n\ntype SocketMessage = {\n type: 'subscribe' | 'unsubscribe' | 'data' | 'heartbeat';\n table: string;\n id: string;\n}\n\ntype SocketResponseMessage = {\n table: string;\n id: string;\n data: object;\n}\n\nconst debug = false;\n\nclass Socket extends Kontororu {\n private config?: SocketConfig;\n\n private ws?: WebSocket;\n\n private connection_state: ConnectionState = 'connected';\n\n private session_id?: string;\n\n private message_queue: SocketMessage[] = [];\n\n // Reconnection logic\n private reconnect_attempts: number = 0;\n private should_reconnect = true;\n private reconnect_timeout?: NodeJS.Timeout;\n\n // Heartbeat / Sleep Detection Logic\n private last_heartbeat_timestamp: number = Date.now();\n // How often the server pings THIS specific client (5 seconds)\n private readonly HEARTBEAT_INTERVAL_MS = 5000;\n // Calculate threshold: 2 missed beats + 1 second of network jitter buffer\n private readonly SUSPENSION_THRESHOLD_MS = (this.HEARTBEAT_INTERVAL_MS * 2) + 1000;\n // 3 Heartbeats + 1s buffer = 16 seconds\n private readonly DISCONNECT_THRESHOLD_MS = (this.HEARTBEAT_INTERVAL_MS * 3) + 1000;\n\n constructor() {\n super();\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', (event) => {\n if (document.visibilityState === 'visible') {\n this.check_staleness('tab_switch');\n }\n });\n }\n\n if (typeof window !== 'undefined') {\n const offlineChecker = () => {\n const check = 3;\n let checked = 1;\n\n const checker = () => {\n if (checked > check) {\n return;\n }\n setTimeout(\n () => {\n this.check_staleness('offline');\n checked++;\n checker();\n },\n (this.HEARTBEAT_INTERVAL_MS) + 500,\n );\n };\n\n checker();\n };\n\n window.addEventListener('online', () => {\n window.removeEventListener('offline', offlineChecker);\n });\n window.addEventListener('offline', offlineChecker);\n }\n }\n\n private get_url() {\n if (!this.config) {\n throw new Error('Socket not configured');\n }\n\n const { hostname, port, path } = this.config;\n\n const protocol = (typeof window !== 'undefined' && window.location && window.location.protocol && window.location.protocol === 'https:' ? 'wss:' : 'ws:');\n\n return `${protocol}//${hostname}${port ? `:${port}` : ''}/${path}`;\n }\n\n public connect(session_id: string, config?: SocketConfig) {\n if (config) {\n this.config = config;\n }\n\n if (!session_id) {\n console.warn('session_id required to open ws');\n return;\n }\n\n if (\n this.ws &&\n (\n this.ws.readyState === WebSocket.OPEN ||\n this.ws.readyState === WebSocket.CONNECTING\n )\n ) {\n return;\n }\n\n this.ws = new WebSocket(this.get_url());\n\n if (debug) console.log('new websocket');\n\n this.session_id = session_id;\n\n // Reset heartbeat timer on new connection\n this.last_heartbeat_timestamp = Date.now();\n\n this.ws.addEventListener('open', (event) => this.handle_open(event));\n this.ws.addEventListener('message', (event) => this.handle_message(event));\n this.ws.addEventListener('close', (event) => this.handle_close(event));\n this.ws.addEventListener('error', (event) => this.handle_error(event));\n }\n\n /**\n * Send message if the websocket is open,\n * otherwise add it to the message queue\n */\n public message({ type, table, id }: SocketMessage) {\n const payload = { type, table, id };\n\n if (\n this.ws &&\n this.ws.readyState === WebSocket.OPEN\n ) {\n this.ws.send(JSON.stringify(payload));\n } else {\n this.message_queue.push(payload);\n }\n }\n\n public disconnect() {\n if (debug) console.log('websocket disconnect()');\n this.update_connection_state('disconnected');\n // if we are manually disconnecting we do not want an auto reconnect\n this.should_reconnect = false;\n this.ws?.close();\n this.ws = undefined;\n if (this.reconnect_timeout) {\n clearTimeout(this.reconnect_timeout);\n }\n }\n\n /**\n * Update the connection state, dispatch an event if it actually changed.\n */\n private update_connection_state(new_connection_state: ConnectionState) {\n const old_connection_state = this.connection_state;\n if (this.connection_state !== new_connection_state) {\n if (debug) console.log('update_connection_state', new_connection_state);\n this.connection_state = new_connection_state;\n\n if (debug) console.warn(`[Socket] State changed to: ${this.connection_state}`);\n this.dispatchEvent(new CustomEvent('connection_state', { detail: this.connection_state }));\n\n if (\n (new_connection_state === 'connected' || new_connection_state === 'reconnected') &&\n (old_connection_state === 'stale' || old_connection_state === 'disconnected')\n ) {\n this.dispatchEvent(new CustomEvent('refresh', { bubbles: true }));\n }\n }\n }\n\n\n /**\n * Helper to determine if we need to fetch missing data\n */\n private check_staleness(source: string) {\n const now = Date.now();\n const time_since_last = now - this.last_heartbeat_timestamp;\n\n if (debug) console.log('websocket check_staleness()', source, time_since_last);\n\n if (\n !this.ws ||\n this.ws.readyState === this.ws.CLOSED ||\n time_since_last > this.DISCONNECT_THRESHOLD_MS\n ) {\n this.update_connection_state('disconnected');\n return;\n }\n\n // If gap is larger than threshold, we missed messages\n if (time_since_last > this.SUSPENSION_THRESHOLD_MS) {\n this.update_connection_state('stale');\n } else {\n this.update_connection_state('connected');\n }\n }\n\n private handle_open(event: Event) {\n if (debug) console.log('websocket handle open()');\n\n if (\n this.ws &&\n this.ws.readyState === this.ws.OPEN\n ) {\n this.update_connection_state('connected');\n }\n // clear reconnect timeout if we connected\n if (this.reconnect_timeout) {\n clearTimeout(this.reconnect_timeout);\n }\n\n // If we are reconnecting (attempts > 0), we definitely missed data.\n if (this.reconnect_attempts > 0) {\n if (debug) console.log('[Socket] Reconnected. Triggering refresh.');\n this.dispatchEvent(new CustomEvent('refresh', { bubbles: true }));\n }\n\n // reset the reconnect attempts\n this.reconnect_attempts = 0;\n\n this.ws?.send(JSON.stringify({ type: 'session', table: 'session', id: this.session_id }));\n\n while (this.message_queue.length > 0) {\n const queuedMsg = this.message_queue.shift();\n this.ws?.send(JSON.stringify(queuedMsg));\n }\n }\n\n private handle_message(event: MessageEvent) {\n if (debug) console.log('websocket handle message()');\n\n try {\n const data = JSON.parse(event.data);\n\n if (debug) console.log('data', data);\n\n // HEARTBEAT CHECK: Intercept heartbeat messages\n if (data.type === 'heartbeat') {\n this.check_staleness('heartbeat');\n this.last_heartbeat_timestamp = Date.now();\n return; // Do not bubble 'heartbeat' to the UI\n }\n\n // todo not sure I like this\n const messageEvent = new CustomEvent('message', {\n detail: JSON.parse(event.data) as SocketResponseMessage,\n bubbles: true,\n });\n\n this.dispatchEvent(messageEvent);\n } catch (e) {\n const messageEvent = new CustomEvent('message', {\n detail: event.data as SocketResponseMessage,\n bubbles: true,\n });\n this.dispatchEvent(messageEvent);\n }\n }\n\n private handle_close(event: CloseEvent) {\n if (debug) console.log('websocket handle close()');\n this.update_connection_state('disconnected');\n if (this.should_reconnect) {\n const delay = Math.min(1000 * Math.pow(2, this.reconnect_attempts), 30000);\n if (debug) console.log(`Connection lost. Retrying in ${delay}ms... (Attempt ${this.reconnect_attempts + 1})`);\n\n this.reconnect_timeout = setTimeout(() => {\n this.reconnect_attempts++;\n if (this.session_id) {\n this.connect(this.session_id);\n }\n }, delay);\n }\n\n this.ws = undefined;\n }\n\n private handle_error(event: Event) {\n if (debug) console.log('websocket handle error()');\n this.update_connection_state('disconnected');\n console.error('WebSocket Error:', event);\n this.ws?.close();\n }\n}\n\nexport const socket: Socket = new Socket();\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/* eslint-disable no-restricted-syntax */\n\ntype Merge<T, U> = Omit<T, keyof U> & U;\n\ntype MergeAll<T extends object[]> =\n T extends [infer First extends object, ...infer Rest extends object[]]\n ? Rest extends []\n ? First // Base case: If there are no more items, just return the object\n : Merge<First, MergeAll<Rest>> // Otherwise, keep merging\n : unknown;\n\n/**\n * Class to manipulate objects\n */\nexport class Objector {\n // constructor() {\n // }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public static deepClone<T>(obj: T, memo: WeakMap<any, any> = new WeakMap<any, any>()): T {\n // Check if the input is null or not an object/array\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n // Check if the object is already in the memo\n if (memo.has(obj)) {\n return memo.get(obj);\n }\n\n // Handle built-in types\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as unknown as T;\n }\n if (obj instanceof RegExp) {\n return new RegExp(obj.source, obj.flags) as unknown as T;\n }\n if (obj instanceof Map) {\n const clonedMap = new Map();\n memo.set(obj, clonedMap);\n obj.forEach((value, key) => clonedMap.set(key, Objector.deepClone(value, memo)));\n return clonedMap as unknown as T;\n }\n if (obj instanceof Set) {\n const newSet = new Set();\n for (const item of obj) {\n newSet.add(Objector.deepClone(item));\n }\n return newSet as unknown as T;\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n const clonedArray = obj.map((item) => Objector.deepClone(item, memo)) as unknown as T;\n memo.set(obj, clonedArray);\n return clonedArray;\n }\n\n // Handle objects\n const clonedObj = Object.create(Object.getPrototypeOf(obj)) as Record<string | symbol, unknown>;\n memo.set(obj, clonedObj);\n\n // Cast the source 'obj' to a record so we can read its keys dynamically\n const sourceObj = obj as Record<string | symbol, unknown>;\n\n // per Gemini\n /**\n * While it appears to be two steps, the first step (Object.keys()) is a native C++ function in the JavaScript engine.\n * It's highly optimized for this specific task and is often faster than the JIT compiler can make the for...in loop with its conditional checks.\n */\n Object.keys(sourceObj).forEach((key) => {\n clonedObj[key] = Objector.deepClone(sourceObj[key], memo);\n });\n /*\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n clonedObj[key] = Objector.deepClone(obj[key], memo);\n }\n }\n */\n\n // Symbol keys\n Object.getOwnPropertySymbols(sourceObj).forEach((sym) => {\n if (Object.prototype.propertyIsEnumerable.call(sourceObj, sym)) {\n clonedObj[sym] = Objector.deepClone(sourceObj[sym], memo);\n }\n });\n\n return clonedObj as unknown as T;\n }\n\n /**\n * Deeply merges one or more source objects into a target object.\n *\n * - Each property from the sources is deep-cloned before being assigned.\n * - Existing properties in the target are overwritten by matching keys in later sources.\n * - Does not use spread or Object.assign.\n * - Mutates and returns the target object.\n *\n * @template T - The type of the target object.\n * @param {T} target - The object to extend.\n * @param {...U[]} sources - One or more source objects whose properties will be copied to the target.\n * @returns {T & U} The mutated target object containing all deep-cloned properties from the sources.\n *\n * @throws {TypeError} If the target is null or undefined.\n *\n * @example\n * const target = { a: 1 };\n * const source = { b: { nested: 2 } };\n * Objector.extender(target, source);\n * // target is now { a: 1, b: { nested: 2 } }\n */\n public static extender<T extends object, U extends object[]>(\n target: T,\n ...sources: U\n ): MergeAll<[T, ...U]> {\n if (target == null) {\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n const to = Object(target) as Record<string | symbol, unknown>;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const source of sources) {\n if (source != null) {\n // Cast the source to an indexable record\n const s = source as Record<string | symbol, unknown>;\n // String keys\n // eslint-disable-next-line no-restricted-syntax\n for (const key of Object.keys(s)) {\n to[key] = Objector.deepClone(s[key]);\n }\n\n // Symbol keys\n const symbols = Object.getOwnPropertySymbols(s);\n // eslint-disable-next-line no-restricted-syntax\n for (const sym of symbols) {\n if (Object.prototype.propertyIsEnumerable.call(s, sym)) {\n to[sym] = Objector.deepClone(s[sym]);\n }\n }\n }\n }\n\n return to as MergeAll<[T, ...U]>;\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nimport { Kontororu } from '../Kontororu.js';\nimport { Objector } from '../Objector.js';\n\n\nexport type StoreData = Record<string, Record<string, unknown>>;\n\nexport class Store<TStore extends StoreData = StoreData> extends Kontororu {\n private store: TStore = {} as TStore;\n\n /**\n * Load an object into the store\n */\n load(data: TStore) {\n this.store = data;\n }\n\n /**\n * Get the first result\n */\n get<K extends keyof TStore>(table: K, args: Record<string, unknown> = {}): TStore[K][string] | null {\n const results = this.read(table, args);\n const firstId = Object.keys(results)[0];\n return firstId ? (results[firstId] as TStore[K][string]) : null;\n }\n\n /**\n * Read the results\n */\n read<K extends keyof TStore>(table: K, args: Record<string, unknown> = {}): Record<string, TStore[K][string]> {\n const data = this.store[table];\n if (!data) {\n return {};\n }\n\n const primaryKey = `${String(table)}_id`;\n\n // Fast path: Direct primary key lookup\n if (primaryKey in args) {\n const id = args[primaryKey] as string;\n if (data[id]) {\n return { [id]: Objector.deepClone(data[id]) as TStore[K][string] };\n }\n return {};\n }\n\n // If no arguments are provided, return a deep clone of the entire table\n if (Object.keys(args).length === 0) {\n return Objector.deepClone(data) as Record<string, TStore[K][string]>;\n }\n\n const matches: Record<string, TStore[K][string]> = {};\n const mismatches: Record<string, boolean> = {};\n\n for (const id in data) {\n if (id in mismatches) {\n continue;\n }\n\n const row = data[id];\n if (!row || typeof row !== 'object' || Array.isArray(row)) {\n continue;\n }\n\n for (const column in args) {\n let match = false;\n const argVal = args[column];\n const rowVal = (row as Record<string, unknown>)[column];\n\n if (rowVal === argVal) {\n match = true;\n } else if (Array.isArray(argVal) && argVal.includes(rowVal)) {\n match = true;\n }\n\n if (match) {\n matches[id] = Objector.deepClone(row) as TStore[K][string];\n } else {\n mismatches[id] = true;\n delete matches[id];\n break;\n }\n }\n }\n\n return matches;\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/**\n * Table sorting helper utility\n */\nexport class Sorter {\n public static descendingComparator(a: Record<string, string | number>, b: Record<string, string | number>, orderBy: string, direction_?: string): number {\n if ((orderBy in a) && b[orderBy] === null) {\n return 1;\n }\n if (a[orderBy] === null && (orderBy in b)) {\n return -1;\n }\n\n const a_value = a[orderBy];\n const b_value = b[orderBy];\n\n const direction = direction_ || 'lower';\n\n if (b_value < a_value) {\n return direction === 'higher' ? 1 : -1;\n }\n if (b_value > a_value) {\n return direction === 'higher' ? -1 : 1;\n }\n return 0;\n }\n\n public static getComparator(order: string, orderBy: string, direction?: string): (a: Record<string, string | number>, b: Record<string, string | number>) => number {\n return order === 'desc'\n ? (a, b) => this.descendingComparator(a, b, orderBy, direction)\n : (a, b) => -this.descendingComparator(a, b, orderBy, direction);\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/* eslint-disable no-restricted-syntax */\n/* eslint-disable no-bitwise */\n\n\n\n\ntype CSSMap = Map<string, string>;\n\ninterface ZIndexConfig {\n appBar: number;\n drawer: number;\n fab: number;\n calendar: number;\n mobileStepper: number;\n modal: number;\n toast: number;\n speedDial: number;\n tooltip: number;\n}\n\ninterface StyleConfig {\n zIndex: ZIndexConfig;\n}\n\ninterface NavBarStyle {\n width: string;\n display: string;\n justifyContent: string;\n zIndex: number;\n position: string;\n overflowX: string;\n overflowY: string;\n scrollbarWidth: string;\n}\n\n/**\n * CSS in JS processor and other random style functions\n */\nexport class Style {\n public static getStyle(): StyleConfig {\n return {\n zIndex: Style.getZIndex(),\n };\n }\n\n public static getZIndex(): ZIndexConfig {\n return {\n appBar: 1100,\n drawer: 1200,\n fab: 1050,\n calendar: 1000,\n mobileStepper: 1000,\n modal: 1300,\n toast: 1400,\n speedDial: 1050,\n tooltip: 1500,\n };\n }\n\n public static getNavBar(): NavBarStyle {\n return {\n width: '100%',\n display: 'flex',\n justifyContent: 'center',\n zIndex: Style.getZIndex().appBar,\n position: 'fixed',\n overflowX: 'scroll',\n overflowY: 'hidden',\n scrollbarWidth: 'none',\n };\n }\n\n public static getShadow(depth: number): string {\n const shadows = [\n 'none',\n '0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)',\n '0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)',\n '0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)',\n '0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)',\n '0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)',\n '0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)',\n '0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)',\n '0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)',\n '0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)',\n '0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)',\n '0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)',\n '0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)',\n '0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)',\n '0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)',\n '0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)',\n '0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)',\n '0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)',\n '0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)',\n '0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)',\n '0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)',\n '0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)',\n '0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)',\n '0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)',\n '0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)',\n ];\n\n if (depth > shadows.length || depth < 0) {\n throw new Error(`min depth is 0, max depth is ${shadows.length}. Sent ${depth}`);\n }\n\n return shadows[depth];\n }\n\n /**\n *\n *\n *\n *\n * Below is all the CSS injection from js\n *\n *\n *\n */\n\n /**\n * Call this to add css as a style-sheet, so you can do css selectors like hover td {} etc\n */\n public static getStyleClassName(cssString: string | object, debug = false): string {\n if (debug) {\n console.log('getStyleClassName', cssString);\n }\n // console.time('getStyleClassName')\n const className = `css-${this.hashCSS(cssString, debug)}`;\n\n this.injectStyle(className, cssString, debug);\n // console.timeEnd('getStyleClassName')\n return className;\n }\n\n public static getMap(): CSSMap {\n return this.cssMap;\n }\n\n // SSR helper to get all collected styles\n public static getCSS(): string {\n console.warn('this does not work yet, in root layout need to add a context thing so it attaches css to style when streamed from server');\n return Array.from(this.cssMap.values()).join('\\n');\n }\n\n // Call after SSR render to clean up for next render\n public static flush(): void {\n this.styleCache.clear();\n this.cssMap.clear();\n }\n\n private static styleCache: Set<string> = new Set();\n\n private static cssMap: CSSMap = new Map(); // key: className, value: finalCSS\n\n private static hashCSS(css: string | object, debug = false): string {\n const canonicalize = (obj: object | string | number): object | string | number => {\n if (typeof obj !== 'object' || obj === null) {\n // Return primitives as is\n return obj;\n }\n\n if (Array.isArray(obj)) {\n // Recursively canonicalize array elements\n return obj.map(canonicalize);\n }\n\n // 1. Get and sort the keys of the current object level\n const sortedKeys = Object.keys(obj).sort();\n const canonical: { [key: string]: unknown } = {};\n\n // cast object to record\n const sourceObj = obj as Record<string, string | number>;\n\n // 2. Build a new object using the sorted keys, and recursively process values\n for (const key of sortedKeys) {\n canonical[key] = canonicalize(sourceObj[key]);\n }\n\n return canonical;\n };\n\n const normalize = (val: string | object): string => {\n if (typeof val === 'string') {\n return val;\n }\n if (typeof val === 'object' && val !== null) {\n const canonicalObject = canonicalize(val);\n // Step B: Stringify the canonical object without a replacer\n return JSON.stringify(canonicalObject);\n }\n return String(val);\n };\n\n const normalizedInput = normalize(css);\n\n if (debug) {\n console.log('normalizedInput', normalizedInput);\n }\n\n // Example hash using a simple DJB2 hash (or use a stronger hash like SHA-1/MD5 if needed)\n let hash = 5381;\n for (let i = 0; i < normalizedInput.length; i++) {\n hash = (hash * 33) ^ normalizedInput.charCodeAt(i);\n }\n return (hash >>> 0).toString(36); // base36 for short string\n }\n\n private static injectStyle(className: string, css: string | object, debug = false): void {\n if (\n this.styleCache.has(className)\n ) {\n return;\n }\n\n const finalCSS = this.processCSS(className, css, false, debug);\n\n // If on server, store it only\n if (typeof window === 'undefined') {\n this.cssMap.set(className, finalCSS);\n } else {\n const styleEl = document.createElement('style');\n styleEl.textContent = finalCSS;\n document.head.appendChild(styleEl);\n }\n\n this.styleCache.add(className);\n this.cssMap.set(className, finalCSS);\n }\n\n private static processCSS(className: string, css: string | object, isRecursive = false, debug = false): string {\n // Helper: remove trailing colon from selectors (e.g. 'td:' -> 'td')\n const cleanSelector = (sel:string): string => {\n return sel.replace(/:$/g, '');\n };\n\n // Convert camelCase to kebab-case for property names\n const toKebabCase = (str: string): string => {\n return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n };\n\n // Helper: Remove the specific '}' that closed the block from the accumulated lines\n // so we don't duplicate it when wrapping the result in new braces.\n const removeLastBrace = (lines: string[]) => {\n if (lines.length === 0) return;\n const lastIdx = lines.length - 1;\n const lastLine = lines[lastIdx];\n\n const braceIdx = lastLine.lastIndexOf('}');\n if (braceIdx !== -1) {\n // Remove the brace\n const newLine = lastLine.substring(0, braceIdx) + lastLine.substring(braceIdx + 1);\n\n // If the line is now empty (or just whitespace), remove it entirely\n if (!newLine.trim()) {\n lines.pop();\n } else {\n // eslint-disable-next-line no-param-reassign\n lines[lastIdx] = newLine;\n }\n }\n };\n\n const requiresQuotes = new Set([\n 'content',\n 'quotes',\n 'cue',\n 'cue-before',\n 'cue-after',\n 'src',\n ]);\n\n // List of properties that should have units if the value is a number\n const lengthProps = new Set([\n 'width', 'height', 'top', 'left', 'right', 'bottom',\n 'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',\n 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',\n 'font-size', 'border-width', 'border-radius', 'gap', 'column-gap', 'row-gap',\n 'min-width', 'min-height', 'max-width', 'max-height',\n ]);\n\n const non_recursive_at_rules = [\n '@keyframes',\n '@-webkit-keyframes',\n '@font-face',\n '@counter-style',\n ];\n\n const isNonRecursiveRule = (ruleName: string) => {\n return non_recursive_at_rules.some((prefix) => ruleName.startsWith(prefix));\n };\n\n const normalizeValue = (property: string, value: string | number): string | number => {\n if (!lengthProps.has(property)) {\n return value;\n }\n\n // If it's a number, add px\n if (typeof value === 'number') {\n return `${value}px`;\n }\n\n // If it's a numeric string with no unit, add px\n if (typeof value === 'string') {\n const trimmed = value.trim();\n\n // Match numeric string (integer or decimal), no unit\n if (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n return `${trimmed}px`;\n }\n\n // If it ends in known units or keywords, leave it alone\n return trimmed;\n }\n\n return value;\n };\n\n // Convert a line like \"backgroundColor: red;\" to \"background-color: red;\"\n const normalizeCSSLine = (line: string): string => {\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n return line; // Not a CSS property line\n }\n\n const rawProperty = line.slice(0, colonIndex).trim();\n let value: string | number = line.slice(colonIndex + 1).trim();\n\n const property = toKebabCase(rawProperty);\n\n // Remove trailing comma\n if (value.endsWith(',')) {\n value = value.slice(0, -1).trim();\n }\n\n // Only strip quotes if it's NOT a property like 'content'\n if (!requiresQuotes.has(property)) {\n value = value\n .split(',')\n .map((part) => {\n const trimmed = part.trim();\n // Check if the part is wrapped in quotes\n const match = trimmed.match(/^[\"'](.*)[\"']$/);\n\n if (match) {\n const innerValue = match[1];\n // If there's a space, keep the quotes (e.g., \"Segoe UI\")\n // If no space, strip them (e.g., \"Arial\" -> Arial)\n return innerValue.includes(' ') ? trimmed : innerValue;\n }\n return trimmed;\n })\n .join(', ');\n }\n\n value = normalizeValue(property, value);\n\n let cssLine = `${property}: ${value}`;\n if (!cssLine.endsWith(';')) {\n cssLine += ';';\n }\n\n return cssLine;\n };\n\n // Convert CSS object into flat lines\n const objectToLines = (obj: object): string[] => {\n const lines: string[] = [];\n\n const sourceObj = obj as Record<string, unknown>;\n\n for (const key in sourceObj) {\n const value = sourceObj[key];\n\n if (typeof value === 'object' && value !== null) {\n lines.push(`${key} {`);\n const nested = objectToLines(value);\n lines.push(...nested);\n lines.push('}');\n } else {\n // Note:\n // - We add a comma here to support object syntax, normalizeCSSLine will handle removing it and adding semicolons later.\n // - Don't stringify strings, to avoid double-escaping quotes (e.g. content: '\"*\"')\n const finalValue = typeof value === 'string' ? value : String(value);\n lines.push(`${key}: ${finalValue},`);\n }\n }\n\n return lines;\n };\n\n // Prepare raw lines\n const lines = typeof css === 'string'\n ? css.trim().split('\\n').map((line) => line.trim()).filter(Boolean)\n : objectToLines(css);\n\n\n const topLevelRules: string[] = [];\n const nestedRules: string[] = [];\n const atRules: string[] = [];\n\n let currentNestedSelector: string | null = null;\n let currentAtRule: string | null = null;\n let atRuleLines: string[] = [];\n let atRuleBraceCount = 0;\n let nestedLines: string[] = [];\n let nestedBraceCount = 0;\n\n for (const line of lines) {\n // 1. AT-RULE HANDLING (@media, @keyframes)\n if (line.startsWith('@') || currentAtRule) {\n if (!currentAtRule) currentAtRule = line.split('{')[0].trim();\n atRuleLines.push(line);\n atRuleBraceCount += (line.match(/{/g) || []).length;\n atRuleBraceCount -= (line.match(/}/g) || []).length;\n\n if (atRuleBraceCount === 0) {\n const rawBlock = atRuleLines.join('\\n');\n const contentOnly = rawBlock.substring(rawBlock.indexOf('{') + 1, rawBlock.lastIndexOf('}')).trim();\n\n if (currentAtRule.startsWith('@keyframes')) {\n // Keyframes: Process units/semicolons but DO NOT wrap in class\n const processed = contentOnly.split('\\n').map((l) => {\n if (l.includes('{') || l.includes('}')) return l;\n return normalizeCSSLine(l);\n }).join(' ');\n atRules.push(`${currentAtRule} { ${processed} }`);\n } else {\n // Media Queries: Recursive call to wrap in class\n const processed = this.processCSS(className, contentOnly, false, debug);\n atRules.push(`${currentAtRule} { ${processed} }`);\n }\n currentAtRule = null;\n atRuleLines = [];\n }\n continue;\n }\n\n // 2. NESTED SELECTOR HANDLING (&:hover, ::before)\n if (line.includes('{') || currentNestedSelector) {\n if (!currentNestedSelector) {\n currentNestedSelector = line.split('{')[0].trim();\n\n // Identify \"Highlight Pseudo-elements\" that need global scoping for Safari/WebKit compatibility\n const isHighlightPseudo = /::(selection|target-text|highlight|spelling-error|grammar-error)/.test(currentNestedSelector);\n\n // Standard behavior: auto-prefix with '&' if it starts with ':'\n // Special behavior: If it's a Highlight Pseudo, we leave it alone so it stays global\n if (\n currentNestedSelector.startsWith(':') &&\n !currentNestedSelector.startsWith('&') &&\n !isHighlightPseudo\n ) {\n currentNestedSelector = `&${currentNestedSelector}`;\n }\n } else if (!line.includes('}')) {\n nestedLines.push(normalizeCSSLine(line));\n }\n\n nestedBraceCount += (line.match(/{/g) || []).length;\n nestedBraceCount -= (line.match(/}/g) || []).length;\n\n if (nestedBraceCount === 0) {\n const isHighlightPseudo = /::(selection|target-text|highlight|spelling-error|grammar-error)/.test(currentNestedSelector);\n\n // If it's a Highlight Pseudo, we DON'T prefix with the .className.\n // This makes it global, which is required for Safari to render it correctly.\n const selector = isHighlightPseudo\n ? currentNestedSelector\n : currentNestedSelector.replace(/&/g, `.${className}`);\n\n nestedRules.push(`${selector} { ${nestedLines.join(' ')} }`);\n currentNestedSelector = null;\n nestedLines = [];\n }\n continue;\n }\n\n // 3. TOP LEVEL PROPERTIES\n topLevelRules.push(normalizeCSSLine(line));\n }\n\n const topLevelCSS = (!isRecursive && topLevelRules.length > 0)\n ? `.${className} { ${topLevelRules.join(' ')} }`\n : topLevelRules.join(' ');\n\n return `${topLevelCSS} ${nestedRules.join(' ')} ${atRules.join(' ')}`.replace(/\\s\\s+/g, ' ').trim();\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nexport class Textor {\n public static levenshtein(a: string, b: string): number {\n const matrix: number[][] = [];\n\n if (!a || !b) {\n return 0;\n }\n\n // Initialize the matrix with base case values\n for (let i = 0; i <= a.length; i++) {\n matrix[i] = [i];\n }\n for (let j = 0; j <= b.length; j++) {\n matrix[0][j] = j;\n }\n\n // Populate the matrix with distances\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n\n matrix[i][j] = Math.min(\n matrix[i - 1][j] + 1, // Deletion\n matrix[i][j - 1] + 1, // Insertion\n matrix[i - 1][j - 1] + cost, // Substitution\n );\n }\n }\n\n // The final value is the Levenshtein distance\n return matrix[a.length][b.length];\n }\n\n public static toSentenceCase(str: string): string {\n if (!str) {\n return '';\n }\n\n // Trim the string to remove extra whitespace\n const trimmed = str.trim();\n\n // Convert the first letter to uppercase and the rest to lowercase\n return trimmed.charAt(0).toUpperCase() + trimmed.slice(1).toLowerCase();\n }\n\n /**\n * Generates pseudo-Latin Lorem Ipsum placeholder text.\n */\n public static generateLoremIpsum(\n paragraphs = 3,\n sentencesPerParagraph = 5,\n startWithLorem = true,\n ): string {\n const words = [\n 'lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit',\n 'sed', 'do', 'eiusmod', 'tempor', 'incididunt', 'ut', 'labore', 'et', 'dolore',\n 'magna', 'aliqua', 'ut', 'enim', 'ad', 'minim', 'veniam', 'quis', 'nostrud',\n 'exercitation', 'ullamco', 'laboris', 'nisi', 'ut', 'aliquip', 'ex', 'ea',\n 'commodo', 'consequat', 'duis', 'aute', 'irure', 'dolor', 'in', 'reprehenderit',\n 'in', 'voluptate', 'velit', 'esse', 'cillum', 'dolore', 'eu', 'fugiat', 'nulla',\n 'pariatur', 'excepteur', 'sint', 'occaecat', 'cupidatat', 'non', 'proident',\n 'sunt', 'in', 'culpa', 'qui', 'officia', 'deserunt', 'mollit', 'anim', 'id',\n 'est', 'laborum',\n ];\n\n // Helper to get a random word from the pool\n const getRandomWord = () => words[Math.floor(Math.random() * words.length)];\n\n // Helper to generate a single sentence\n const generateSentence = (isFirstSentence = false) => {\n if (isFirstSentence && startWithLorem) {\n return 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';\n }\n\n // Sentences typically range from 5 to 15 words\n const sentenceLength = Math.floor(Math.random() * 11) + 5;\n const sentenceWords = [];\n\n for (let i = 0; i < sentenceLength; i++) {\n sentenceWords.push(getRandomWord());\n }\n\n // Capitalize the first letter of the sentence\n let sentence = sentenceWords.join(' ');\n sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1);\n\n // Occasionally add commas for realistic phrasing (approx. 20% chance if long enough)\n if (sentenceLength > 8 && Math.random() > 0.8) {\n const commaIndex = Math.floor(sentenceLength / 2);\n const splitSentence = sentence.split(' ');\n splitSentence[commaIndex] += ',';\n sentence = splitSentence.join(' ');\n }\n\n return `${sentence}.`;\n };\n\n const paragraphList = [];\n\n for (let p = 0; p < paragraphs; p++) {\n const sentenceCount = Math.max(3, Math.round(sentencesPerParagraph + (Math.random() * 4 - 2))); // slight variance\n const sentences = [];\n\n for (let s = 0; s < sentenceCount; s++) {\n // Only the absolute first sentence of the entire text gets the classic intro\n const isAbsoluteFirst = p === 0 && s === 0;\n sentences.push(generateSentence(isAbsoluteFirst));\n }\n\n paragraphList.push(sentences.join(' '));\n }\n\n // Join paragraphs with double line breaks\n return paragraphList.join('\\n\\n');\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nexport type ThemeType = ReturnType<Theme['getTheme']>;\n\n// all these types are for jsr / deno because it cant use the dynamic one above >.>\n\ninterface ColorScale {\n 50: string;\n 100: string;\n 200: string;\n 300: string;\n 400: string;\n 500: string;\n 600: string;\n 700: string;\n 800: string;\n 900: string;\n A100: string;\n A200: string;\n A400: string;\n A700: string;\n}\n\ninterface BrownScale {\n 50: string;\n 100: string;\n 200: string;\n 300: string;\n 400: string;\n 500: string;\n 600: string;\n 700: string;\n 800: string;\n 900: string;\n}\n\ninterface ColorGroup {\n main: string;\n light: string;\n dark: string;\n}\n\ninterface ColorGroupWithContrast extends ColorGroup {\n contrastText: string;\n}\n\ninterface ActionConfig {\n active: string;\n disabled: string;\n disabledBackground: string;\n disabledOpacity: number;\n focus: string;\n focusOpacity: number;\n hover: string;\n hoverOpacity: number;\n selected: string;\n selectedOpacity: number;\n}\n\ninterface ColorPalette {\n grey: ColorScale;\n red: ColorScale;\n pink: ColorScale;\n purple: ColorScale;\n deepPurple: ColorScale;\n indigo: ColorScale;\n blue: ColorScale;\n lightBlue: ColorScale;\n cyan: ColorScale;\n teal: ColorScale;\n green: ColorScale;\n lightGreen: ColorScale;\n lime: ColorScale;\n yellow: ColorScale;\n amber: ColorScale;\n orange: ColorScale;\n deepOrange: ColorScale;\n brown: BrownScale;\n}\n\ninterface DarkTheme extends ColorPalette {\n mode: 'dark';\n background: { main: string };\n header: { main: string };\n primary: ColorGroup;\n secondary: ColorGroup;\n warning: ColorGroup;\n success: ColorGroup;\n error: ColorGroup;\n info: ColorGroup;\n text: { primary: string; secondary: string; disabled: string; icon: string };\n link: { primary: string };\n action: ActionConfig;\n}\n\ninterface LightTheme extends ColorPalette {\n mode: 'light';\n background: { main: string; light: string };\n header: { main: string };\n primary: ColorGroupWithContrast;\n secondary: ColorGroupWithContrast;\n warning: ColorGroupWithContrast;\n success: ColorGroupWithContrast;\n error: ColorGroupWithContrast;\n info: ColorGroupWithContrast;\n text: { primary: string; secondary: string; disabled: string };\n link: { primary: string };\n action: ActionConfig;\n}\n\n/**\n * Class to get the theme\n */\nexport class Theme {\n public constructor(mode: string) {\n this.mode = mode;\n\n if (mode !== 'light' && mode !== 'dark') {\n throw new Error(`Unknown theme: ${mode}`);\n }\n }\n\n private mode: string;\n\n public getTheme(): DarkTheme | LightTheme {\n if (this.mode === 'light') {\n return this.getLightTheme();\n }\n\n return this.getDarkTheme();\n }\n\n public getDarkTheme(): DarkTheme {\n return {\n mode: 'dark',\n background: {\n main: '#121212',\n },\n header: {\n main: this.getGrey()[900],\n },\n primary: {\n main: '#90caf9',\n light: '#e3f2fd',\n dark: '#42a5f5',\n },\n secondary: {\n main: '#ce93d8',\n light: '#f3e5f5',\n dark: '#ab47bc',\n },\n warning: {\n main: '#ffa726',\n light: '#ffb74d',\n dark: '#f57c00',\n },\n success: {\n main: '#66bb6a',\n light: '#81c784',\n dark: '#388e3c',\n },\n error: {\n main: '#f44336',\n dark: '#d32f2f',\n light: '#e57373',\n },\n info: {\n main: '#29b6f6',\n dark: '#0288d1',\n light: '#4fc3f7',\n },\n text: {\n primary: '#fff',\n secondary: '#B3B3B3',\n disabled: '#808080',\n icon: '#808080',\n },\n link: {\n primary: '#90caf9',\n },\n action: {\n active: '#fff',\n disabled: 'rgba(255, 255, 255, 0.3)',\n disabledBackground: 'rgba(255, 255, 255, 0.12)',\n disabledOpacity: 0.38,\n focus: 'rgba(255, 255, 255, 0.12)',\n focusOpacity: 0.12,\n hover: 'rgba(255, 255, 255, 0.08)',\n hoverOpacity: 0.08,\n selected: 'rgba(255, 255, 255, 0.16)',\n selectedOpacity: 0.16,\n },\n grey: this.getGrey(),\n red: this.getRed(),\n pink: this.getPink(),\n purple: this.getPurple(),\n deepPurple: this.getDeepPurple(),\n indigo: this.getIndigo(),\n blue: this.getBlue(),\n lightBlue: this.getLightBlue(),\n cyan: this.getCyan(),\n teal: this.getTeal(),\n green: this.getGreen(),\n lightGreen: this.getLightGreen(),\n lime: this.getLime(),\n yellow: this.getYellow(),\n amber: this.getAmber(),\n orange: this.getOrange(),\n deepOrange: this.getDeepOrange(),\n brown: this.getBrown(),\n };\n }\n\n public getLightTheme(): LightTheme {\n return {\n mode: 'light',\n background: {\n main: '#efefef',\n light: '#fff',\n },\n header: {\n main: this.getBlue()[700],\n },\n primary: {\n main: '#1976d2',\n light: '#42a5f5',\n dark: '#1565c0',\n contrastText: '#fff',\n },\n secondary: {\n main: '#9c27b0',\n light: '#ba68c8',\n dark: '#7b1fa2',\n contrastText: '#fff',\n },\n error: {\n main: '#d32f2f',\n light: '#ef5350',\n dark: '#c62828',\n contrastText: '#fff',\n },\n warning: {\n main: '#ed6c02',\n light: '#ff9800',\n dark: '#e65100',\n contrastText: '#fff',\n },\n info: {\n main: '#0288d1',\n light: '#03a9f4',\n dark: '#01579b',\n contrastText: '#fff',\n },\n success: {\n main: '#2e7d32',\n light: '#4caf50',\n dark: '#1b5e20',\n contrastText: '#fff',\n },\n text: {\n primary: '#222222',\n secondary: '#666666',\n disabled: '#9E9E9E',\n },\n link: {\n primary: '#1976d2',\n },\n action: {\n active: 'rgba(0, 0, 0, 0.54)',\n disabled: 'rgba(0, 0, 0, 0.26)',\n disabledBackground: 'rgba(0, 0, 0, 0.12)',\n disabledOpacity: 0.38,\n focus: 'rgba(0, 0, 0, 0.12)',\n focusOpacity: 0.12,\n hover: 'rgba(0, 0, 0, 0.04)',\n hoverOpacity: 0.04,\n selected: 'rgba(0, 0, 0, 0.08)',\n selectedOpacity: 0.08,\n },\n grey: this.getGrey(),\n red: this.getRed(),\n pink: this.getPink(),\n purple: this.getPurple(),\n deepPurple: this.getDeepPurple(),\n indigo: this.getIndigo(),\n blue: this.getBlue(),\n lightBlue: this.getLightBlue(),\n cyan: this.getCyan(),\n teal: this.getTeal(),\n green: this.getGreen(),\n lightGreen: this.getLightGreen(),\n lime: this.getLime(),\n yellow: this.getYellow(),\n amber: this.getAmber(),\n orange: this.getOrange(),\n deepOrange: this.getDeepOrange(),\n brown: this.getBrown(),\n };\n }\n\n private getGrey(): ColorScale {\n return {\n 50: '#fafafa',\n 100: '#f5f5f5',\n 200: '#eeeeee',\n 300: '#e0e0e0',\n 400: '#bdbdbd',\n 500: '#9e9e9e',\n 600: '#757575',\n 700: '#616161',\n 800: '#424242',\n 900: '#212121',\n A100: '#f5f5f5',\n A200: '#eeeeee',\n A400: '#bdbdbd',\n A700: '#616161',\n };\n }\n\n private getRed(): ColorScale {\n return {\n 50: '#ffebee',\n 100: '#ffcdd2',\n 200: '#ef9a9a',\n 300: '#e57373',\n 400: '#ef5350',\n 500: '#f44336',\n 600: '#e53935',\n 700: '#d32f2f',\n 800: '#c62828',\n 900: '#b71c1c',\n A100: '#ff8a80',\n A200: '#ff5252',\n A400: '#ff1744',\n A700: '#d50000',\n };\n }\n\n private getPink(): ColorScale {\n return {\n 50: '#fce4ec',\n 100: '#f8bbd0',\n 200: '#f48fb1',\n 300: '#f06292',\n 400: '#ec407a',\n 500: '#e91e63',\n 600: '#d81b60',\n 700: '#c2185b',\n 800: '#ad1457',\n 900: '#880e4f',\n A100: '#ff80ab',\n A200: '#ff4081',\n A400: '#f50057',\n A700: '#c51162',\n };\n }\n\n private getPurple(): ColorScale {\n return {\n 50: '#f3e5f5',\n 100: '#e1bee7',\n 200: '#ce93d8',\n 300: '#ba68c8',\n 400: '#ab47bc',\n 500: '#9c27b0',\n 600: '#8e24aa',\n 700: '#7b1fa2',\n 800: '#6a1b9a',\n 900: '#4a148c',\n A100: '#ea80fc',\n A200: '#e040fb',\n A400: '#d500f8',\n A700: '#aa00ff',\n };\n }\n\n private getDeepPurple(): ColorScale {\n return {\n 50: '#ede7f6',\n 100: '#d1c4e9',\n 200: '#b39ddb',\n 300: '#9575cd',\n 400: '#7e57c2',\n 500: '#673ab7',\n 600: '#5e35b1',\n 700: '#512da8',\n 800: '#4527a0',\n 900: '#311b92',\n A100: '#b388ff',\n A200: '#7c4dff',\n A400: '#651fff',\n A700: '#6200ea',\n };\n }\n\n private getIndigo(): ColorScale {\n return {\n 50: '#e8eaf6',\n 100: '#c5cae9',\n 200: '#9fa8da',\n 300: '#7986cb',\n 400: '#5c6bc0',\n 500: '#3f51b5',\n 600: '#3949ab',\n 700: '#303f9f',\n 800: '#283593',\n 900: '#1a237e',\n A100: '#8c9eff',\n A200: '#536dfe',\n A400: '#3d5afe',\n A700: '#304ffe',\n };\n }\n\n private getBlue(): ColorScale {\n return {\n 50: '#e3f2fd',\n 100: '#bbdefb',\n 200: '#90caf9',\n 300: '#64b5f6',\n 400: '#42a5f5',\n 500: '#2196f3',\n 600: '#1e88e5',\n 700: '#1976d2',\n 800: '#1565c0',\n 900: '#0d47a1',\n A100: '#82b1ff',\n A200: '#448aff',\n A400: '#2979ff',\n A700: '#2962ff',\n };\n }\n\n private getLightBlue(): ColorScale {\n return {\n 50: '#e1f5fe',\n 100: '#b3e5fc',\n 200: '#81d4fa',\n 300: '#4fc3f7',\n 400: '#29b6f6',\n 500: '#03a9f4',\n 600: '#039be5',\n 700: '#0288d1',\n 800: '#0277bd',\n 900: '#01579b',\n A100: '#80d8ff',\n A200: '#40c4ff',\n A400: '#00b0ff',\n A700: '#0091ea',\n };\n }\n\n private getCyan(): ColorScale {\n return {\n 50: '#e0f7fa',\n 100: '#b2ebf2',\n 200: '#80deea',\n 300: '#4dd0e1',\n 400: '#26c6da',\n 500: '#00bcd4',\n 600: '#00acc1',\n 700: '#0097a7',\n 800: '#00838f',\n 900: '#006064',\n A100: '#84ffff',\n A200: '#18ffff',\n A400: '#00e5ff',\n A700: '#00b8d4',\n };\n }\n\n private getTeal(): ColorScale {\n return {\n 50: '#e0f2f1',\n 100: '#b2dfdb',\n 200: '#80cbc4',\n 300: '#4db6ac',\n 400: '#26a69a',\n 500: '#009688',\n 600: '#00897b',\n 700: '#00796b',\n 800: '#00695c',\n 900: '#004d40',\n A100: '#a7ffeb',\n A200: '#64ffda',\n A400: '#1de9b6',\n A700: '#00bfa5',\n };\n }\n\n private getGreen(): ColorScale {\n return {\n 50: '#e8f5e9',\n 100: '#c8e6c9',\n 200: '#a5d6a7',\n 300: '#81c784',\n 400: '#66bb6a',\n 500: '#4caf50',\n 600: '#43a047',\n 700: '#388e3c',\n 800: '#2e7d32',\n 900: '#1b5e20',\n A100: '#b9f6ca',\n A200: '#69f0ae',\n A400: '#00e676',\n A700: '#00c853',\n };\n }\n\n private getLightGreen(): ColorScale {\n return {\n 50: '#f1f8e9',\n 100: '#dcedc8',\n 200: '#c5e1a5',\n 300: '#aed581',\n 400: '#9ccc65',\n 500: '#8bc34a',\n 600: '#7cb342',\n 700: '#689f38',\n 800: '#558b2f',\n 900: '#33691e',\n A100: '#ccff90',\n A200: '#b2ff59',\n A400: '#76ff03',\n A700: '#64dd17',\n };\n }\n\n private getLime(): ColorScale {\n return {\n 50: '#f9fbe7',\n 100: '#f0f4c3',\n 200: '#e6ee9c',\n 300: '#dce775',\n 400: '#d4e157',\n 500: '#cddc39',\n 600: '#c0ca33',\n 700: '#afb42b',\n 800: '#9fa827',\n 900: '#827717',\n A100: '#f4ff81',\n A200: '#eeff41',\n A400: '#c6ff00',\n A700: '#aeea00',\n };\n }\n\n private getYellow(): ColorScale {\n return {\n 50: '#fffde7',\n 100: '#fff9c4',\n 200: '#fff59d',\n 300: '#fff176',\n 400: '#ffee58',\n 500: '#ffeb3b',\n 600: '#fdd835',\n 700: '#fbc02d',\n 800: '#f9a825',\n 900: '#f57f17',\n A100: '#ffff8d',\n A200: '#ffff00',\n A400: '#ffea00',\n A700: '#ffd600',\n };\n }\n\n private getAmber(): ColorScale {\n return {\n 50: '#fff8e1',\n 100: '#ffecb3',\n 200: '#ffe082',\n 300: '#ffd54f',\n 400: '#ffca28',\n 500: '#ffc107',\n 600: '#ffb300',\n 700: '#ffa000',\n 800: '#ff8f00',\n 900: '#ff6f00',\n A100: '#ffe57f',\n A200: '#ffd740',\n A400: '#ffc400',\n A700: '#ffab00',\n };\n }\n\n private getOrange(): ColorScale {\n return {\n 50: '#fff3e0',\n 100: '#ffe0b2',\n 200: '#ffcc80',\n 300: '#ffb74d',\n 400: '#ffa726',\n 500: '#ff9800',\n 600: '#fb8c00',\n 700: '#f57c00',\n 800: '#ef6c00',\n 900: '#e65100',\n A100: '#ffd180',\n A200: '#ffab40',\n A400: '#ff9100',\n A700: '#ff6d00',\n };\n }\n\n private getDeepOrange(): ColorScale {\n return {\n 50: '#fbe9e7',\n 100: '#ffccbc',\n 200: '#ffab91',\n 300: '#ff8a65',\n 400: '#ff7043',\n 500: '#ff5722',\n 600: '#f4511e',\n 700: '#e64a19',\n 800: '#d84315',\n 900: '#bf360c',\n A100: '#ff9e80',\n A200: '#ff6e40',\n A400: '#ff3d00',\n A700: '#dd2c00',\n };\n }\n\n private getBrown(): BrownScale {\n return {\n 50: '#efebe9',\n 100: '#d7ccc8',\n 200: '#bcaaa4',\n 300: '#a1887f',\n 400: '#8d6e63',\n 500: '#795548',\n 600: '#6d4c41',\n 700: '#5d4037',\n 800: '#4e342e',\n 900: '#3e2723',\n };\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n// Handles toast components throughout the app\n\nexport interface ToastItem {\n id: number;\n message: string;\n type: string;\n exiting?: boolean;\n}\n\n// Define the shape of the listener function\nexport type ToastListener = (toasts: ToastItem[]) => void;\n\nexport class Toaster {\n private listeners: ToastListener[] = [];\n\n private toasts: ToastItem[] = [];\n\n // React component will subscribe to this\n subscribe(listener: ToastListener): () => void {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter((l) => l !== listener);\n };\n }\n\n notify(): void {\n this.listeners.forEach((listener) => listener(this.toasts));\n }\n\n requestClose(id: number): void {\n this.toasts = this.toasts.map((t) => {\n if (t.id === id) {\n return { ...t, exiting: true };\n }\n return t;\n });\n this.notify();\n }\n\n add(message: string, type = 'info'): void {\n const id = Date.now();\n this.toasts = [...this.toasts, { id, message, type }];\n this.notify();\n\n // Auto-remove\n setTimeout(() => {\n this.requestClose(id);\n }, 4000);\n }\n\n remove(id: number): void {\n this.toasts = this.toasts.filter((t) => t.id !== id);\n this.notify();\n }\n}\n\nexport const toaster: Toaster = new Toaster();\n\nexport const toast: {\n info: (msg: string) => void;\n error: (msg: string) => void;\n success: (msg: string) => void;\n} = {\n info: (msg: string) => toaster.add(msg, 'info'),\n error: (msg: string) => toaster.add(msg, 'error'),\n success: (msg: string) => toaster.add(msg, 'success'),\n};\n", "/* eslint-disable no-bitwise */\n/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n\n/**\n * Generate UUIDv7\n */\nclass UuidService {\n private lastTimestamp = -1;\n private seqCounter = 0;\n\n private getRandomBytes(size: number): Uint8Array {\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n const bytes = new Uint8Array(size);\n globalThis.crypto.getRandomValues(bytes);\n return bytes;\n }\n\n throw new Error('Secure crypto functionality is not available in this environment.');\n }\n\n public generateUUIDv7Bytes(): Uint8Array {\n let now = Date.now();\n\n if (now === this.lastTimestamp) {\n this.seqCounter++;\n\n // 12-bit counter overflow (> 4095 IDs in 1ms): advance timestamp artificially\n if (this.seqCounter > 0x0fff) {\n this.lastTimestamp++;\n now = this.lastTimestamp;\n this.seqCounter = 0;\n }\n } else if (now < this.lastTimestamp) {\n // Clock drift / NTP rollback: hold timestamp and increment counter to maintain monotonicity\n this.seqCounter++;\n if (this.seqCounter > 0x0fff) {\n this.lastTimestamp++;\n this.seqCounter = 0;\n }\n now = this.lastTimestamp;\n } else {\n // New millisecond: update state and reset sequence counter\n this.lastTimestamp = now;\n this.seqCounter = 0;\n }\n\n // Allocate 16 random bytes for remaining entropy (rand_b)\n const buf = this.getRandomBytes(16);\n\n // 1. Write 48-bit Unix timestamp into bytes 0..5\n buf[0] = Math.floor(now / 0x10000000000) & 0xff;\n buf[1] = Math.floor(now / 0x100000000) & 0xff;\n buf[2] = (now >>> 24) & 0xff;\n buf[3] = (now >>> 16) & 0xff;\n buf[4] = (now >>> 8) & 0xff;\n buf[5] = now & 0xff;\n\n // 2. Byte 6: Version 7 (0x70) + upper 4 bits of 12-bit counter\n buf[6] = 0x70 | ((this.seqCounter >> 8) & 0x0f);\n\n // 3. Byte 7: Lower 8 bits of 12-bit counter\n buf[7] = this.seqCounter & 0xff;\n\n // 4. Byte 8: Set Variant RFC 4122 (0x80) on remaining random bits\n buf[8] = (buf[8] & 0x3f) | 0x80;\n\n return buf;\n }\n\n /**\n * Convert a UUID string to binary Uint8Array\n */\n public static uuidToBin(uuid: string): Uint8Array {\n const hex = uuid.replaceAll('-', '');\n const bytes = new Uint8Array(16);\n\n for (let i = 0; i < 16; i++) {\n bytes[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);\n }\n\n return bytes;\n }\n\n /**\n * Convert binary Uint8Array/Buffer to formatted UUID string\n */\n public static binToUuid(buffer: Uint8Array): string {\n let hex = '';\n for (let i = 0; i < buffer.length; i++) {\n hex += buffer[i].toString(16).padStart(2, '0');\n }\n\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n}\n// export as a singleton\nexport const uuidService = new UuidService();\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nexport class Arithmetic {\n public static clamp(number: number, min: number, max: number): number {\n return Math.max(min, Math.min(number, max));\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nexport class Arrayifier {\n // constructor() {\n // }\n\n\n /**\n * Shuffle / ranomize elements in an array\n * @param {array} array The array to shuffle\n * @return array\n */\n public static shuffle<T>(array: T[]): T[] {\n let currentIndex: number = array.length;\n let randomIndex: number;\n\n // While there remain elements to shuffle.\n while (currentIndex !== 0) {\n // Pick a remaining element.\n randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex--;\n\n // And swap it with the current element.\n // eslint-disable-next-line no-param-reassign\n [array[currentIndex], array[randomIndex]] = [\n array[randomIndex], array[currentIndex]];\n }\n\n return array;\n }\n\n /**\n * Recursively generates all combinations of size `r` from an array of `n` elements.\n *\n * @param {T[]} arr - The source array to generate combinations from\n * @param {number} n - The total number of elements in `arr` (i.e. arr.length)\n * @param {number} r - The size of each combination to generate\n * @param {number} index - Current position being filled in the combination (increments toward r)\n * @param {T[]} data - Temporary buffer holding the current combination being built\n * @param {number} i - Current index in `arr` being considered for inclusion\n * @param {T[][]} results - Accumulator array that collects each completed combination\n * @returns {T[][]} The accumulated list of all combinations once recursion completes\n *\n * @example\n * combination([1, 2, 3], 3, 2, 0, [], 0, [])\n * // returns [[1, 2], [1, 3], [2, 3]]\n */\n public static combination<T>(\n arr: T[],\n n: number,\n r: number,\n index: number,\n data: T[],\n i: number,\n results: T[][],\n ): T[][] {\n if (index === r) {\n results.push(data.slice(0, r));\n return results;\n }\n\n if (i >= n) {\n return results;\n }\n\n // eslint-disable-next-line no-param-reassign\n data[index] = arr[i];\n this.combination(arr, n, r, index + 1, data, i + 1, results);\n this.combination(arr, n, r, index, data, i + 1, results);\n\n return results;\n }\n\n /**\n * Get all combinations of every value in the provided array for a specified number\n * @param {Array} arr\n * @param {number} n\n * @param {number} r\n * @returns Array\n */\n public static getCombinations<T>(arr: T[], n: number, r: number): T[][] {\n const data: T[] = new Array(r);\n\n let results: T[][] = [];\n results = this.combination(arr, n, r, 0, data, 0, results);\n return results;\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/**\n * Everything to help with CSV generation\n */\nexport class CSV {\n /**\n * Convert an object to a CSV file and then download it\n */\n public static download(data: Record<string, Record<string, unknown>>): void {\n const rows: string[] = [];\n\n let setHeaders = false;\n let headers: string[] = [];\n for (const id in data) {\n const row = data[id];\n\n if (!setHeaders) {\n headers = Object.keys(row);\n rows.push(headers.join(','));\n setHeaders = true;\n }\n\n const values = headers.map((header) => JSON.stringify(row[header] || ''));\n rows.push(values.join(','));\n }\n\n const content = rows.join('\\n');\n\n // Create a Blob and trigger download\n const blob = new Blob([content], { type: 'text/csv' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'srating-data.csv';\n\n // Trigger download and clean up\n document.body.appendChild(a);\n a.click();\n URL.revokeObjectURL(url);\n a.remove();\n }\n}\n", "/* eslint-disable no-param-reassign */\n/* eslint-disable default-case */\n/* eslint-disable no-multi-assign */\n/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/* eslint-disable no-mixed-operators */\n/* eslint-disable no-bitwise */\n\n\nexport class Color {\n // constructor() {\n // }\n\n\n /**\n * A linear interpolator for hexadecimal colors\n * @param {string} a\n * @param {string} b\n * @param {number} amount\n * @example\n * // returns #7F7F7F\n * lerpColor('#000000', '#ffffff', 0.5)\n * @return {string}\n */\n public static lerpColor(a: string, b: string, amount: number): string {\n const ah = +a.replace('#', '0x');\n const ar = ah >> 16;\n const ag = ah >> 8 & 0xff;\n const ab = ah & 0xff;\n\n const bh = +b.replace('#', '0x');\n const br = bh >> 16;\n const bg = bh >> 8 & 0xff;\n const bb = bh & 0xff;\n\n const rr = ar + amount * (br - ar);\n const rg = ag + amount * (bg - ag);\n const rb = ab + amount * (bb - ab);\n\n return `#${((1 << 24) + (rr << 16) + (rg << 8) + rb | 0).toString(16).slice(1)}`;\n }\n\n /**\n * Get a color that will look readable based on a background color\n */\n public static getTextColor(color: string, backgroundColor: string, debug = false): string {\n // Convert hex colors to RGB\n /*\n let [r1, g1, b1] = Color.hexToRgb(color);\n const [r2, g2, b2] = Color.hexToRgb(backgroundColor);\n\n const brightnessBg = Color.calculateBrightness(r2, g2, b2);\n\n const targetBrightness = brightnessBg > 128 ? 50 : 150; // target brightness threshold for contrast\n\n while (true) {\n const brightnessColor = Color.calculateBrightness(r1, g1, b1);\n\n if (\n (brightnessBg > 128 && brightnessColor < targetBrightness) ||\n (brightnessBg <= 128 && brightnessColor > targetBrightness)\n ) {\n break;\n }\n\n if (brightnessBg > 128) {\n r1 = Math.max(0, r1 - 25);\n g1 = Math.max(0, g1 - 25);\n b1 = Math.max(0, b1 - 25);\n } else {\n r1 = Math.min(255, r1 + 25);\n g1 = Math.min(255, g1 + 25);\n b1 = Math.min(255, b1 + 25);\n }\n\n if ((r1 === 0 && g1 === 0 && b1 === 0) || (r1 === 255 && g1 === 255 && b1 === 255)) {\n break; // avoid infinite loop\n }\n }\n\n // Convert back to hex\n return Color.rgbToHex(r1, g1, b1);\n */\n let [r, g, b] = Color.hexToRgb(color);\n const [br, bg, bb] = Color.hexToRgb(backgroundColor);\n const contrastTarget = 4.5;\n\n if (debug) {\n console.log('Color.getContrastRatio([r, g, b], [br, bg, bb])', Color.getContrastRatio([r, g, b], [br, bg, bb]));\n }\n\n if (Color.getContrastRatio([r, g, b], [br, bg, bb]) >= contrastTarget) {\n return Color.rgbToHex(r, g, b);\n }\n\n const contrastToBlack = Color.getContrastRatio([0, 0, 0], [br, bg, bb]);\n const contrastToWhite = Color.getContrastRatio([255, 255, 255], [br, bg, bb]);\n\n const direction: 'lighter' | 'darker' =\n contrastToWhite > contrastToBlack ? 'lighter' : 'darker';\n\n\n if (debug) {\n console.log('contrastToBlack', contrastToBlack);\n console.log('contrastToWhite', contrastToWhite);\n console.log('direction', direction);\n }\n\n const adjust = (c: number, lighter: boolean) => {\n return lighter ? Math.min(255, c + 10) : Math.max(0, c - 10);\n };\n\n for (let i = 0; i < 25; i++) {\n r = adjust(r, direction === 'lighter');\n g = adjust(g, direction === 'lighter');\n b = adjust(b, direction === 'lighter');\n\n if (debug) {\n console.log('Color.getContrastRatio([r, g, b], [br, bg, bb]) 2', Color.getContrastRatio([r, g, b], [br, bg, bb]));\n }\n\n if (Color.getContrastRatio([r, g, b], [br, bg, bb]) >= contrastTarget) {\n break;\n }\n }\n\n return Color.rgbToHex(r, g, b);\n }\n\n public static getContrastRatio(rgb1: [number, number, number], rgb2: [number, number, number]): number {\n const luminance = (r: number, g: number, b: number): number => {\n const a = [r, g, b].map((v) => {\n v /= 255;\n return v <= 0.03928\n ? v / 12.92\n : Math.pow((v + 0.055) / 1.055, 2.4);\n });\n return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;\n };\n\n const lum1 = luminance(...rgb1) + 0.05;\n const lum2 = luminance(...rgb2) + 0.05;\n\n return lum1 > lum2 ? lum1 / lum2 : lum2 / lum1;\n }\n\n /**\n * Take a hex (#fff) and an amount and darken the color, return a hex\n * @param {string} hex\n * @param {number} amount\n * @return {string} hex\n */\n // public static darken(hex: string, amount: number = 0.02): string {\n // const [r, g, b] = this.hexToRgb(hex);\n // const [h, s, l] = this.rgbToHsl(r, g, b);\n\n // const newL = Math.max(0, (l / 100) - amount) * 100;\n // const [r2, g2, b2] = this.hslToRgb(h, s, newL);\n\n // return this.rgbToHex(r2, g2, b2);\n // }\n\n /**\n * Take a hex (#fff) and an amount and lighten the color, return a hex\n * @param {string} hex\n * @param {number} amount\n * @return {string} hex\n */\n // public static lighten(hex: string, amount: number = 0.02): string {\n // const [r, g, b] = this.hexToRgb(hex);\n // const [h, s, l] = this.rgbToHsl(r, g, b);\n\n // const newL = Math.min(1, (l / 100) + amount) * 100;\n // const [r2, g2, b2] = this.hslToRgb(h, s, newL);\n\n // return this.rgbToHex(r2, g2, b2);\n // }\n\n /**\n * Mixes the color with black to create a Shade.\n * Prevents the \"muddy/brown\" look of HSL darkening.\n * @param {string} hex - The color to darken\n * @param {number} amount - 0 to 1 (e.g. 0.1 is 10% darker)\n * @return {string} hex\n */\n public static darken(hex: string, amount: number = 0.1): string {\n const [r, g, b] = this.hexToRgb(hex);\n\n // Calculate new color by mixing with black (0)\n // Formula: Current * (1 - amount)\n const remaining = 1 - amount;\n const r2 = Math.round(r * remaining);\n const g2 = Math.round(g * remaining);\n const b2 = Math.round(b * remaining);\n\n return this.rgbToHex(r2, g2, b2);\n }\n\n /**\n * Mixes the color with white to create a Tint.\n * cleaner and less \"washed out\" than HSL lightness adjustment.\n * @param {string} hex - The color to lighten\n * @param {number} amount - 0 to 1 (e.g. 0.1 is 10% lighter)\n * @return {string} hex\n */\n public static lighten(hex: string, amount: number = 0.1): string {\n const [r, g, b] = this.hexToRgb(hex);\n\n // Calculate new color by mixing with white (255)\n // Formula: Current + ((Target - Current) * amount)\n const r2 = Math.round(r + (255 - r) * amount);\n const g2 = Math.round(g + (255 - g) * amount);\n const b2 = Math.round(b + (255 - b) * amount);\n\n return this.rgbToHex(r2, g2, b2);\n }\n\n\n public static shadeColor(hex: string, percent: number): string {\n let [r, g, b] = Color.hexToRgb(hex);\n\n r = Math.min(255, Math.max(0, Math.round(r + (r * (percent / 100)))));\n g = Math.min(255, Math.max(0, Math.round(g + (g * (percent / 100)))));\n b = Math.min(255, Math.max(0, Math.round(b + (b * (percent / 100)))));\n\n return Color.rgbToHex(r, g, b);\n }\n\n\n /**\n * Are 2 colors similar to each other?\n * @param {string} color1\n * @param {string} color2\n * @param {number} threshold\n * @return {boolean}\n */\n public static areColorsSimilar(color1: string, color2: string, threshold = 50): boolean {\n const distance = Color.colorDistance(color1, color2);\n return distance < threshold;\n }\n\n\n /**\n * Inverts a hex color\n * @param {string} hex\n * @return {string} hex\n */\n public static invertColor(hex: string): string {\n const [r, g, b] = Color.hexToRgb(hex);\n\n // Invert each color component\n const invertedR = 255 - r;\n const invertedG = 255 - g;\n const invertedB = 255 - b;\n\n return Color.rgbToHex(invertedR, invertedG, invertedB);\n }\n\n\n /**\n * Takes a hex (#fff) and returns an rgba with the provided alpha\n * @param {string} hex\n * @param {number} alpha\n * @return {string} rgba()\n */\n public static alphaColor(hex: string, alpha: number): string {\n const [r, g, b] = this.hexToRgb(hex);\n\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n }\n\n\n /**\n * Gets analogous colors\n * @param {string} hex\n * @return {Array<string>}\n */\n public static getAnalogousColors(hex: string): string[] {\n const [r, g, b] = Color.hexToRgb(hex);\n const [h, s, l] = Color.rgbToHsl(r, g, b);\n\n const analogousColors: string[] = [];\n const offset = 30; // Offset for analogous colors, usually 30 degrees\n\n for (let i = -1; i <= 1; i++) {\n if (i !== 0) {\n const newHue = (h + i * offset + 360) % 360;\n const [newR, newG, newB] = Color.hslToRgb(newHue, s, l);\n analogousColors.push(Color.rgbToHex(newR, newG, newB));\n }\n }\n\n return analogousColors;\n }\n\n\n /**\n * Convert hex to rgb\n * @param {string} hex\n * @return {Array} rgb\n */\n public static hexToRgb(hex: string): Array<number> {\n // Remove the hash at the start if it's there\n let h = hex.replace(/^#/, '');\n\n // Handle 3-character hex codes by expanding them to 6-character\n if (h.length === 3) {\n h = h.split('').map((char) => { return char + char; }).join('');\n }\n\n // Ensure it's a valid 6-character hex code\n if (h.length !== 6) {\n throw new Error(`Invalid hex color format: ${hex}`);\n }\n\n // Parse r, g, b values\n const bigint = parseInt(h, 16);\n const r = (bigint >> 16) & 255;\n const g = (bigint >> 8) & 255;\n const b = bigint & 255;\n\n return [r, g, b];\n }\n\n\n /**\n * Convert rgb to hex\n * @param {number} r\n * @param {number} g\n * @param {number} b\n * @return {string}\n */\n private static rgbToHex(r: number, g: number, b: number): string {\n return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()}`;\n }\n\n private static rgbToHsl(r: number, g: number, b: number) {\n r /= 255;\n g /= 255;\n b /= 255;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n let h = 0;\n let s = 0;\n const l = (max + min) / 2;\n\n if (max === min) {\n h = s = 0; // achromatic\n } else {\n const d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n case g: h = (b - r) / d + 2; break;\n case b: h = (r - g) / d + 4; break;\n }\n h /= 6;\n }\n return [h * 360, s * 100, l * 100];\n }\n\n private static hslToRgb(h: number, s: number, l: number) {\n let r;\n let g;\n let b;\n h /= 360;\n s /= 100;\n l /= 100;\n\n if (s === 0) {\n r = g = b = l; // achromatic\n } else {\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 3) return q;\n if (t < 1 / 2) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n r = hue2rgb(p, q, h + 1 / 3);\n g = hue2rgb(p, q, h);\n b = hue2rgb(p, q, h - 1 / 3);\n }\n\n return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];\n }\n\n private static calculateBrightness(r: number, g: number, b: number): number {\n // Calculate the brightness of the color\n return (r * 299 + g * 587 + b * 114) / 1000;\n }\n\n private static colorDistance(color1: string, color2: string): number {\n const [r1, g1, b1] = Color.hexToRgb(color1);\n const [r2, g2, b2] = Color.hexToRgb(color2);\n\n const dr = r1 - r2;\n const dg = g1 - g2;\n const db = b1 - b2;\n\n return Math.sqrt(dr * dr + dg * dg + db * db);\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/* eslint-disable one-var-declaration-per-line */\n/* eslint-disable one-var */\n\nimport { IANATimeZone } from './Timezones.js';\n\n\nexport class Dates {\n // constructor() {\n // }\n\n /*\n * Robust Date Parsing\n * Handles:\n * - Date Objects / Numbers (Timestamps)\n * - ISO Strings (2025-01-01) -> Forces Local Midnight\n * - US Formats (01/05/2026)\n * - Mixed Time Formats (23:00 pm, 5:00pm, 14:30:00)\n */\n public static parse(\n str?: Date | string | number | undefined | null,\n utc = false,\n ): Date {\n // 1. Handle Null / Undefined -> Return Now\n if (!str) {\n return new Date();\n }\n\n // 2. Handle Existing Date Objects -> Return Copy\n if (str instanceof Date) {\n return new Date(str.getTime());\n }\n\n // 3. Handle Timestamps (Numbers)\n if (typeof str === 'number') {\n return new Date(str);\n }\n\n // 4. Handle Strings\n if (typeof str === 'string') {\n const input = str.trim();\n\n // CASE A: Strict ISO Date \"YYYY-MM-DD\"\n // Native JS parses this as UTC Midnight, which often shows as\n // previous day 7pm EST. We force \"T00:00:00\" to make it Local Midnight.\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) {\n return utc ? new Date(`${input}T00:00:00Z`) : new Date(`${input}T00:00:00`);\n }\n\n // CASE B: Manual Parsing for Complex Strings\n // This handles \"2026-01-05 23:03:19 pm\", \"01/05/2026\", etc.\n\n // Step 1: Extract Date Part (YYYY-MM-DD or MM/DD/YYYY)\n // Regex looks for: (Group 1: Year/Month) -or/ (Group 2: Month/Day) -or/ (Group 3: Day/Year)\n let year, month, day, timePart = '';\n\n // Match YYYY-MM-DD or YYYY/MM/DD\n const isoMatch = input.match(/^(\\d{4})[-/](\\d{1,2})[-/](\\d{1,2})(.*)$/);\n\n // Match MM/DD/YYYY or MM-DD-YYYY\n const usMatch = input.match(/^(\\d{1,2})[-/](\\d{1,2})[-/](\\d{4})(.*)$/);\n\n if (isoMatch) {\n year = parseInt(isoMatch[1], 10);\n month = parseInt(isoMatch[2], 10) - 1; // JS Months are 0-11\n day = parseInt(isoMatch[3], 10);\n timePart = isoMatch[4];\n } else if (usMatch) {\n year = parseInt(usMatch[3], 10);\n month = parseInt(usMatch[1], 10) - 1;\n day = parseInt(usMatch[2], 10);\n timePart = usMatch[4];\n } else {\n // Fallback: Let the browser try its best if our regex fails\n const d = new Date(input);\n return isNaN(d.getTime()) ? new Date() : d;\n }\n\n // Step 2: Extract Time Part\n let hours = 0;\n let minutes = 0;\n let seconds = 0;\n\n // Look for HH:MM(:SS) and optional AM/PM in the remaining string\n if (timePart && timePart.trim().length > 0) {\n // Matches: 23:03, 23:03:19, 5:00pm, 5:00 pm\n const timeMatch = timePart.match(/(\\d{1,2}):(\\d{1,2})(?::(\\d{1,2}))?\\s*(am|pm|AM|PM)?/);\n\n if (timeMatch) {\n hours = parseInt(timeMatch[1], 10);\n minutes = parseInt(timeMatch[2], 10);\n seconds = timeMatch[3] ? parseInt(timeMatch[3], 10) : 0;\n const meridiem = timeMatch[4] ? timeMatch[4].toLowerCase() : null;\n\n // Step 3: Normalize Hours (12h to 24h)\n if (meridiem === 'pm' && hours < 12) {\n hours += 12;\n }\n if (meridiem === 'am' && hours === 12) {\n hours = 0;\n }\n // Note: If input is \"23:00 pm\", we ignore the 'pm' because 23 > 12.\n }\n }\n\n if (utc) {\n return new Date(Date.UTC(year, month, day, hours, minutes, seconds));\n }\n\n // Step 4: Construct Date in Local Time\n return new Date(year, month, day, hours, minutes, seconds);\n }\n\n return new Date();\n }\n\n public static getMonthsShort(): string[] {\n return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n }\n\n public static getMonths(): string[] {\n return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\n }\n\n public static getDaysShort(): string[] {\n return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n }\n\n public static getDays(): string[] {\n return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n }\n\n /**\n * Format a date using php syntax\n *\n | Token | Meaning | Example |\n | ----- | ------------------------- | ------- |\n | `Y` | 4-digit year | 2025 |\n | `y` | 2-digit year | 25 |\n | `m` | 2-digit month | 03 |\n | `n` | month (no leading zero) | 3 |\n | `d` | day (2-digit) | 09 |\n | `j` | day (no leading zero) | 9 |\n | `S` | Ordinal suffix | th |\n | `H` | 24-hour | 14 |\n | `G` | 24-hour (no leading zero) | 14 |\n | `h` | 12-hour | 02 |\n | `g` | 12-hour (no leading zero) | 2 |\n | `i` | minutes | 05 |\n | `s` | seconds | 09 |\n | `A` | AM/PM | PM |\n | `a` | am/pm | pm |\n | `w` | day of week (0\u20136) | 1 |\n | `N` | day of week (1\u20137) | 2 |\n | `M` | short month name | Mar |\n | `F` | full month name | March |\n | `D` | short weekday | Mon |\n | `l` | full weekday | Monday |\n | `T` | Timezone abbreviation | EST |\n | `e` | Timezone identifier | America/New_York |\n */\n public static format(dateInput: Date | string, format: string, utc = false): string {\n const date = this.parse(dateInput);\n const pad = (n: number) => String(n).padStart(2, '0');\n\n const monthsShort = this.getMonthsShort();\n const monthsLong = this.getMonths();\n const daysShort = this.getDaysShort();\n const daysLong = this.getDays();\n\n const Y = utc ? date.getUTCFullYear() : date.getFullYear();\n const y = String(Y).slice(-2);\n const month = utc ? date.getUTCMonth() : date.getMonth();\n const dateNum = utc ? date.getUTCDate() : date.getDate();\n const day = utc ? date.getUTCDay() : date.getDay();\n const hours = utc ? date.getUTCHours() : date.getHours();\n const minutes = utc ? date.getUTCMinutes() : date.getMinutes();\n const seconds = utc ? date.getUTCSeconds() : date.getSeconds();\n\n // Dynamically look up current runtime/system timezone strings\n const tzAbbr = utc\n ? 'UTC'\n : new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' })\n .format(date)\n .split(', ')\n .pop() || '';\n\n const tzIdentifier = utc\n ? 'UTC'\n : new Intl.DateTimeFormat('en-US', { timeZoneName: 'long' })\n .resolvedOptions().timeZone || '';\n\n // Logic for ordinal suffix (st, nd, rd, th)\n const getOrdinalSuffix = (n: number) => {\n const v = n % 100;\n // 11th, 12th, 13th are exceptions to the 1st, 2nd, 3rd rule\n if (v >= 11 && v <= 13) {\n return 'th';\n }\n\n switch (n % 10) {\n case 1: {\n return 'st';\n }\n case 2: {\n return 'nd';\n }\n case 3: {\n return 'rd';\n }\n default: {\n return 'th';\n }\n }\n };\n\n const tokens: Record<string, string> = {\n /// Year\n Y: String(Y),\n y,\n\n // Month\n m: pad(month + 1),\n n: String(month + 1),\n M: monthsShort[month],\n F: monthsLong[month],\n\n // Day\n d: pad(dateNum),\n j: String(dateNum),\n D: daysShort[day],\n l: daysLong[day],\n w: String(day), // 0 (Sun) - 6\n N: String(day === 0 ? 7 : day), // 1 (Mon) - 7 (Sun)\n S: getOrdinalSuffix(dateNum),\n\n // Time\n H: pad(hours),\n G: String(hours),\n h: pad(((hours + 11) % 12) + 1),\n g: String(((hours + 11) % 12) + 1),\n i: pad(minutes),\n s: pad(seconds),\n\n // AM/PM\n A: hours < 12 ? 'AM' : 'PM',\n a: hours < 12 ? 'am' : 'pm',\n\n // Timezone\n T: tzAbbr,\n e: tzIdentifier,\n };\n\n // Replace tokens using regex\n return format.replace(/\\\\(.)|([a-zA-Z])/g, (_, esc, token) => {\n if (esc) {\n // literal escaped char like \\H or \\Y \u2192 return the raw letter\n return esc;\n }\n return tokens[token] ?? token;\n });\n }\n\n public static add(date: Date | string, amount: number, unit: 'years' | 'months' | 'days' | 'hours' | 'minutes'): Date {\n const d = this.parse(date);\n\n if (unit === 'years') {\n const originalDay = d.getDate();\n d.setFullYear(d.getFullYear() + amount);\n // Handle Leap Year Rollover:\n // Feb 29, 2024 + 1 year -> Mar 1, 2025 (Standard JS behavior)\n // If strict \"same day or last day of month\" logic is desired (turning it into Feb 28):\n if (d.getDate() !== originalDay) {\n d.setDate(0); // Set to last day of previous month (Feb 28)\n }\n } else if (unit === 'months') {\n const originalDay = d.getDate();\n d.setMonth(d.getMonth() + amount);\n // Handle rollover: Jan 31 + 1 month -> Feb 28/29\n if (d.getDate() !== originalDay) {\n d.setDate(0); // Set to last day of previous month\n }\n } else if (unit === 'days') {\n // Use setDate to be DST safe (24h addition via ms is unsafe across DST)\n d.setDate(d.getDate() + amount);\n } else {\n const map: Record<'hours' | 'minutes', number> = {\n hours: amount * 60 * 60 * 1000,\n minutes: amount * 60 * 1000,\n };\n // Use getTime() for day/hour/minute units for simple millisecond addition\n d.setTime(d.getTime() + map[unit]);\n }\n\n return d;\n }\n\n public static subtract(\n date: Date | string,\n amount: number,\n unit: 'years' | 'months' | 'days' | 'hours' | 'minutes',\n ): Date {\n return this.add(date, -amount, unit);\n }\n\n public static fromNow(date: Date | string): string {\n const d = this.parse(date);\n const diff = Date.now() - d.getTime();\n const mins = Math.floor(diff / 60000);\n\n if (Math.abs(mins) < 1) {\n return 'just now';\n }\n\n // Handle future dates roughly\n if (mins < 0) {\n return 'in the future';\n }\n\n if (mins < 60) {\n return `${mins}m ago`;\n }\n\n const hours = Math.floor(mins / 60);\n\n if (hours < 24) {\n return `${hours}h ago`;\n }\n\n const days = Math.floor(hours / 24);\n\n return `${days}d ago`;\n }\n\n /**\n * Find the closest date in an array of dates\n */\n public static getClosestDate(dateToMatch: string | Date, datesArray: string[]): string | null {\n if (!datesArray.length) {\n return null;\n }\n\n const matchDate = this.parse(dateToMatch).getTime();\n\n let closestDate: string | null = null;\n let closestDist = Infinity;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const dateStr of datesArray) {\n const currDate = this.parse(dateStr).getTime();\n const dist = Math.abs(currDate - matchDate);\n\n if (dist < closestDist) {\n closestDist = dist;\n closestDate = dateStr;\n } else if (dist === closestDist) {\n // Tie-breaker: Prefer the date that is in the future relative to the matchDate\n // Or if both are same direction, just keep the current one (or implementation defined)\n // Requirement: \"Both 17th and 19th have same dist. It should pick 19th\"\n if (currDate > matchDate) {\n closestDate = dateStr;\n }\n }\n }\n\n return closestDate;\n }\n\n public static getTodayEST(): string {\n return this.format(new Date().toLocaleString('en-US', { timeZone: 'America/New_York' }), 'Y-m-d');\n }\n\n public static getStartOfDay(date: Date | string): Date {\n const d = this.parse(date);\n d.setHours(0, 0, 0, 0);\n return d;\n }\n\n public static getStartOfMonth(date: Date | string): Date {\n const d = this.parse(date);\n d.setDate(1);\n d.setHours(0, 0, 0, 0);\n return d;\n }\n\n public static getStartOfGrid(date: Date | string): Date {\n const d = this.getStartOfMonth(date);\n const dayOfWeek = d.getDay(); // 0 (Sunday) is the start in standard JS\n\n // Move back to the beginning of the week\n const result = this.parse(d);\n // Subtract days to get to the start of the week (Sunday)\n result.setDate(d.getDate() - dayOfWeek);\n return result;\n }\n\n public static isSameDay(date1: Date | string, date2: Date | string): boolean {\n if (!date1 || !date2) {\n return false;\n }\n const d1 = this.parse(date1);\n const d2 = this.parse(date2);\n\n return (\n d1.getFullYear() === d2.getFullYear() &&\n d1.getMonth() === d2.getMonth() &&\n d1.getDate() === d2.getDate()\n );\n }\n\n // Helper to check if one date is before another (ignoring time)\n public static isBeforeDay(date1: Date | string, date2: Date | string): boolean {\n if (!date1 || !date2) {\n return false;\n }\n return this.getStartOfDay(date1).getTime() < this.getStartOfDay(date2).getTime();\n }\n\n // Helper to check if one date is after another (ignoring time)\n public static isAfterDay(date1: Date | string, date2: Date | string): boolean {\n if (!date1 || !date2) {\n return false;\n }\n return this.getStartOfDay(date1).getTime() > this.getStartOfDay(date2).getTime();\n }\n\n /**\n * Determines if a given date is observing Daylight Saving Time (DST)\n * relative to the runtime's local timezone.\n */\n public static isDST(dateInput?: Date | string | number | null): boolean {\n const d = this.parse(dateInput);\n const year = d.getFullYear();\n\n // Get the timezone offset for January 1st and July 1st of the same year\n const janOffset = new Date(year, 0, 1).getTimezoneOffset();\n const julOffset = new Date(year, 6, 1).getTimezoneOffset();\n\n // The standard time offset is always the maximum of the two.\n // Example (New York): EST is 300 mins behind UTC, EDT is 240 mins. Max is 300.\n // Example (Sydney): AEST is -600 mins, AEDT is -660 mins. Max is -600.\n const standardTimezoneOffset = Math.max(janOffset, julOffset);\n\n // If the date's offset is less than the standard offset, it is in DST\n return d.getTimezoneOffset() < standardTimezoneOffset;\n }\n\n /**\n * Extracts the exact wall-clock date and time components for a specific timezone.\n * @param dateInput The date to evaluate (defaults to now)\n * @param timeZone The target IANA timezone (e.g., 'America/New_York')\n * @returns An object containing numeric date components (month is 1-12)\n */\n public static getPartsInZone(\n dateInput?: Date | string | number | null,\n timeZone: IANATimeZone = 'America/New_York',\n ): {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n second: number;\n weekday: string;\n } {\n const d = this.parse(dateInput);\n\n const allTimeZones = Intl.supportedValuesOf('timeZone');\n\n if (!allTimeZones.includes(timeZone)) {\n throw new Error('Unsupported timeZone.');\n }\n\n const formatter = new Intl.DateTimeFormat('en-US', {\n timeZone,\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n weekday: 'long', // Adds \"Monday\", \"Tuesday\", etc. to the output\n hourCycle: 'h23',\n });\n\n const parts = formatter.formatToParts(d);\n\n const getPart = (type: Intl.DateTimeFormatPartTypes) => parseInt(parts.find((p) => p.type === type)?.value || '0', 10);\n\n const weekday = parts.find((p) => p.type === 'weekday')?.value || '';\n\n return {\n year: getPart('year'),\n month: getPart('month'), // 1-12 format\n day: getPart('day'),\n hour: getPart('hour'), // 0-23 format\n minute: getPart('minute'),\n second: getPart('second'),\n weekday,\n };\n }\n\n /**\n * Calculates the difference between two dates (`date1 - date2`).\n *\n * @param date1 Primary date\n * @param date2 Comparison date (defaults to current time)\n * @param utc Whether to parse strings as UTC\n */\n public static diff(\n date1: Date | string | number,\n date2: Date | string | number = new Date(),\n utc = false,\n ): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\n weeks: number;\n months: number;\n years: number;\n abs: {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\n weeks: number;\n months: number;\n years: number;\n }\n } {\n const d1 = this.parse(date1, utc);\n const d2 = this.parse(date2, utc);\n\n const ms = d1.getTime() - d2.getTime();\n\n // Calendar-based month and year differences\n const y1 = utc ? d1.getUTCFullYear() : d1.getFullYear();\n const y2 = utc ? d2.getUTCFullYear() : d2.getFullYear();\n const m1 = utc ? d1.getUTCMonth() : d1.getMonth();\n const m2 = utc ? d2.getUTCMonth() : d2.getMonth();\n\n const months = (y1 - y2) * 12 + (m1 - m2);\n const years = y1 - y2;\n\n const seconds = Math.trunc(ms / 1000);\n const minutes = Math.trunc(ms / (1000 * 60));\n const hours = Math.trunc(ms / (1000 * 60 * 60));\n const days = Math.trunc(ms / (1000 * 60 * 60 * 24));\n const weeks = Math.trunc(ms / (1000 * 60 * 60 * 24 * 7));\n\n return {\n milliseconds: ms,\n seconds,\n minutes,\n hours,\n days,\n weeks,\n months,\n years,\n // Helper containing absolute (positive) values\n abs: {\n milliseconds: Math.abs(ms),\n seconds: Math.abs(seconds),\n minutes: Math.abs(minutes),\n hours: Math.abs(hours),\n days: Math.abs(days),\n weeks: Math.abs(weeks),\n months: Math.abs(months),\n years: Math.abs(years),\n },\n };\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n// \u30B3\u30F3\u30C8\u30ED\u30FC\u30EB\n\ntype Listeners = Array<(...args: unknown[]) => void>;\n\nexport class Kontororu extends EventTarget {\n constructor() {\n super();\n this.listeners = {};\n }\n\n private listeners: {\n [type: string]: Listeners;\n };\n\n addEventListener(type: string, listener: (...args: unknown[]) => void): this {\n super.addEventListener(type, listener);\n\n if (!this.listeners[type]) {\n this.listeners[type] = [];\n }\n this.listeners[type].push(listener);\n\n return this;\n }\n\n removeEventListener(type: string, listener: (...args: unknown[]) => void): this {\n super.removeEventListener(type, listener);\n\n if (this.listeners[type]) {\n this.listeners[type] = this.listeners[type].filter((l) => l !== listener);\n }\n\n return this;\n }\n\n removeAllEventListeners() {\n for (const type in this.listeners) {\n for (let i = this.listeners[type].length; i >= 0; i--) {\n this.removeEventListener(type, this.listeners[type][i]);\n }\n }\n }\n\n getListeners(type: string): Listeners | [] {\n return this.listeners[type] || [];\n }\n}\n\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nimport { Kontororu } from '../Kontororu.js';\n\n\ninterface SocketConfig {\n hostname: string;\n port?: string | number;\n path: string;\n}\n\ntype ConnectionState = 'connected' | 'stale' | 'disconnected' | 'reconnected';\n\ntype SocketMessage = {\n type: 'subscribe' | 'unsubscribe' | 'data' | 'heartbeat';\n table: string;\n id: string;\n}\n\ntype SocketResponseMessage = {\n table: string;\n id: string;\n data: object;\n}\n\nconst debug = false;\n\nclass Socket extends Kontororu {\n private config?: SocketConfig;\n\n private ws?: WebSocket;\n\n private connection_state: ConnectionState = 'connected';\n\n private session_id?: string;\n\n private message_queue: SocketMessage[] = [];\n\n // Reconnection logic\n private reconnect_attempts: number = 0;\n private should_reconnect = true;\n private reconnect_timeout?: NodeJS.Timeout;\n\n // Heartbeat / Sleep Detection Logic\n private last_heartbeat_timestamp: number = Date.now();\n // How often the server pings THIS specific client (5 seconds)\n private readonly HEARTBEAT_INTERVAL_MS = 5000;\n // Calculate threshold: 2 missed beats + 1 second of network jitter buffer\n private readonly SUSPENSION_THRESHOLD_MS = (this.HEARTBEAT_INTERVAL_MS * 2) + 1000;\n // 3 Heartbeats + 1s buffer = 16 seconds\n private readonly DISCONNECT_THRESHOLD_MS = (this.HEARTBEAT_INTERVAL_MS * 3) + 1000;\n\n constructor() {\n super();\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', (event) => {\n if (document.visibilityState === 'visible') {\n this.check_staleness('tab_switch');\n }\n });\n }\n\n if (typeof window !== 'undefined') {\n const offlineChecker = () => {\n const check = 3;\n let checked = 1;\n\n const checker = () => {\n if (checked > check) {\n return;\n }\n setTimeout(\n () => {\n this.check_staleness('offline');\n checked++;\n checker();\n },\n (this.HEARTBEAT_INTERVAL_MS) + 500,\n );\n };\n\n checker();\n };\n\n window.addEventListener('online', () => {\n window.removeEventListener('offline', offlineChecker);\n });\n window.addEventListener('offline', offlineChecker);\n }\n }\n\n private get_url() {\n if (!this.config) {\n throw new Error('Socket not configured');\n }\n\n const { hostname, port, path } = this.config;\n\n const protocol = (typeof window !== 'undefined' && window.location && window.location.protocol && window.location.protocol === 'https:' ? 'wss:' : 'ws:');\n\n return `${protocol}//${hostname}${port ? `:${port}` : ''}/${path}`;\n }\n\n public connect(session_id: string, config?: SocketConfig) {\n if (config) {\n this.config = config;\n }\n\n if (!session_id) {\n console.warn('session_id required to open ws');\n return;\n }\n\n if (\n this.ws &&\n (\n this.ws.readyState === WebSocket.OPEN ||\n this.ws.readyState === WebSocket.CONNECTING\n )\n ) {\n return;\n }\n\n this.ws = new WebSocket(this.get_url());\n\n if (debug) console.log('new websocket');\n\n this.session_id = session_id;\n\n // Reset heartbeat timer on new connection\n this.last_heartbeat_timestamp = Date.now();\n\n this.ws.addEventListener('open', (event) => this.handle_open(event));\n this.ws.addEventListener('message', (event) => this.handle_message(event));\n this.ws.addEventListener('close', (event) => this.handle_close(event));\n this.ws.addEventListener('error', (event) => this.handle_error(event));\n }\n\n /**\n * Send message if the websocket is open,\n * otherwise add it to the message queue\n */\n public message({ type, table, id }: SocketMessage) {\n const payload = { type, table, id };\n\n if (\n this.ws &&\n this.ws.readyState === WebSocket.OPEN\n ) {\n this.ws.send(JSON.stringify(payload));\n } else {\n this.message_queue.push(payload);\n }\n }\n\n public disconnect() {\n if (debug) console.log('websocket disconnect()');\n this.update_connection_state('disconnected');\n // if we are manually disconnecting we do not want an auto reconnect\n this.should_reconnect = false;\n this.ws?.close();\n this.ws = undefined;\n if (this.reconnect_timeout) {\n clearTimeout(this.reconnect_timeout);\n }\n }\n\n /**\n * Update the connection state, dispatch an event if it actually changed.\n */\n private update_connection_state(new_connection_state: ConnectionState) {\n const old_connection_state = this.connection_state;\n if (this.connection_state !== new_connection_state) {\n if (debug) console.log('update_connection_state', new_connection_state);\n this.connection_state = new_connection_state;\n\n if (debug) console.warn(`[Socket] State changed to: ${this.connection_state}`);\n this.dispatchEvent(new CustomEvent('connection_state', { detail: this.connection_state }));\n\n if (\n (new_connection_state === 'connected' || new_connection_state === 'reconnected') &&\n (old_connection_state === 'stale' || old_connection_state === 'disconnected')\n ) {\n this.dispatchEvent(new CustomEvent('refresh', { bubbles: true }));\n }\n }\n }\n\n\n /**\n * Helper to determine if we need to fetch missing data\n */\n private check_staleness(source: string) {\n const now = Date.now();\n const time_since_last = now - this.last_heartbeat_timestamp;\n\n if (debug) console.log('websocket check_staleness()', source, time_since_last);\n\n if (\n !this.ws ||\n this.ws.readyState === this.ws.CLOSED ||\n time_since_last > this.DISCONNECT_THRESHOLD_MS\n ) {\n this.update_connection_state('disconnected');\n return;\n }\n\n // If gap is larger than threshold, we missed messages\n if (time_since_last > this.SUSPENSION_THRESHOLD_MS) {\n this.update_connection_state('stale');\n } else {\n this.update_connection_state('connected');\n }\n }\n\n private handle_open(event: Event) {\n if (debug) console.log('websocket handle open()');\n\n if (\n this.ws &&\n this.ws.readyState === this.ws.OPEN\n ) {\n this.update_connection_state('connected');\n }\n // clear reconnect timeout if we connected\n if (this.reconnect_timeout) {\n clearTimeout(this.reconnect_timeout);\n }\n\n // If we are reconnecting (attempts > 0), we definitely missed data.\n if (this.reconnect_attempts > 0) {\n if (debug) console.log('[Socket] Reconnected. Triggering refresh.');\n this.dispatchEvent(new CustomEvent('refresh', { bubbles: true }));\n }\n\n // reset the reconnect attempts\n this.reconnect_attempts = 0;\n\n this.ws?.send(JSON.stringify({ type: 'session', table: 'session', id: this.session_id }));\n\n while (this.message_queue.length > 0) {\n const queuedMsg = this.message_queue.shift();\n this.ws?.send(JSON.stringify(queuedMsg));\n }\n }\n\n private handle_message(event: MessageEvent) {\n if (debug) console.log('websocket handle message()');\n\n try {\n const data = JSON.parse(event.data);\n\n if (debug) console.log('data', data);\n\n // HEARTBEAT CHECK: Intercept heartbeat messages\n if (data.type === 'heartbeat') {\n this.check_staleness('heartbeat');\n this.last_heartbeat_timestamp = Date.now();\n return; // Do not bubble 'heartbeat' to the UI\n }\n\n // todo not sure I like this\n const messageEvent = new CustomEvent('message', {\n detail: JSON.parse(event.data) as SocketResponseMessage,\n bubbles: true,\n });\n\n this.dispatchEvent(messageEvent);\n } catch (e) {\n const messageEvent = new CustomEvent('message', {\n detail: event.data as SocketResponseMessage,\n bubbles: true,\n });\n this.dispatchEvent(messageEvent);\n }\n }\n\n private handle_close(event: CloseEvent) {\n if (debug) console.log('websocket handle close()');\n this.update_connection_state('disconnected');\n if (this.should_reconnect) {\n const delay = Math.min(1000 * Math.pow(2, this.reconnect_attempts), 30000);\n if (debug) console.log(`Connection lost. Retrying in ${delay}ms... (Attempt ${this.reconnect_attempts + 1})`);\n\n this.reconnect_timeout = setTimeout(() => {\n this.reconnect_attempts++;\n if (this.session_id) {\n this.connect(this.session_id);\n }\n }, delay);\n }\n\n this.ws = undefined;\n }\n\n private handle_error(event: Event) {\n if (debug) console.log('websocket handle error()');\n this.update_connection_state('disconnected');\n console.error('WebSocket Error:', event);\n this.ws?.close();\n }\n}\n\nexport const socket: Socket = new Socket();\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/* eslint-disable no-restricted-syntax */\n\ntype Merge<T, U> = Omit<T, keyof U> & U;\n\ntype MergeAll<T extends object[]> =\n T extends [infer First extends object, ...infer Rest extends object[]]\n ? Rest extends []\n ? First // Base case: If there are no more items, just return the object\n : Merge<First, MergeAll<Rest>> // Otherwise, keep merging\n : unknown;\n\n/**\n * Class to manipulate objects\n */\nexport class Objector {\n // constructor() {\n // }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public static deepClone<T>(obj: T, memo: WeakMap<any, any> = new WeakMap<any, any>()): T {\n // Check if the input is null or not an object/array\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n // Check if the object is already in the memo\n if (memo.has(obj)) {\n return memo.get(obj);\n }\n\n // Handle built-in types\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as unknown as T;\n }\n if (obj instanceof RegExp) {\n return new RegExp(obj.source, obj.flags) as unknown as T;\n }\n if (obj instanceof Map) {\n const clonedMap = new Map();\n memo.set(obj, clonedMap);\n obj.forEach((value, key) => clonedMap.set(key, Objector.deepClone(value, memo)));\n return clonedMap as unknown as T;\n }\n if (obj instanceof Set) {\n const newSet = new Set();\n for (const item of obj) {\n newSet.add(Objector.deepClone(item));\n }\n return newSet as unknown as T;\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n const clonedArray = obj.map((item) => Objector.deepClone(item, memo)) as unknown as T;\n memo.set(obj, clonedArray);\n return clonedArray;\n }\n\n // Handle objects\n const clonedObj = Object.create(Object.getPrototypeOf(obj)) as Record<string | symbol, unknown>;\n memo.set(obj, clonedObj);\n\n // Cast the source 'obj' to a record so we can read its keys dynamically\n const sourceObj = obj as Record<string | symbol, unknown>;\n\n // per Gemini\n /**\n * While it appears to be two steps, the first step (Object.keys()) is a native C++ function in the JavaScript engine.\n * It's highly optimized for this specific task and is often faster than the JIT compiler can make the for...in loop with its conditional checks.\n */\n Object.keys(sourceObj).forEach((key) => {\n clonedObj[key] = Objector.deepClone(sourceObj[key], memo);\n });\n /*\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n clonedObj[key] = Objector.deepClone(obj[key], memo);\n }\n }\n */\n\n // Symbol keys\n Object.getOwnPropertySymbols(sourceObj).forEach((sym) => {\n if (Object.prototype.propertyIsEnumerable.call(sourceObj, sym)) {\n clonedObj[sym] = Objector.deepClone(sourceObj[sym], memo);\n }\n });\n\n return clonedObj as unknown as T;\n }\n\n /**\n * Deeply merges one or more source objects into a target object.\n *\n * - Each property from the sources is deep-cloned before being assigned.\n * - Existing properties in the target are overwritten by matching keys in later sources.\n * - Does not use spread or Object.assign.\n * - Mutates and returns the target object.\n *\n * @template T - The type of the target object.\n * @param {T} target - The object to extend.\n * @param {...U[]} sources - One or more source objects whose properties will be copied to the target.\n * @returns {T & U} The mutated target object containing all deep-cloned properties from the sources.\n *\n * @throws {TypeError} If the target is null or undefined.\n *\n * @example\n * const target = { a: 1 };\n * const source = { b: { nested: 2 } };\n * Objector.extender(target, source);\n * // target is now { a: 1, b: { nested: 2 } }\n */\n public static extender<T extends object, U extends object[]>(\n target: T,\n ...sources: U\n ): MergeAll<[T, ...U]> {\n if (target == null) {\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n const to = Object(target) as Record<string | symbol, unknown>;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const source of sources) {\n if (source != null) {\n // Cast the source to an indexable record\n const s = source as Record<string | symbol, unknown>;\n // String keys\n // eslint-disable-next-line no-restricted-syntax\n for (const key of Object.keys(s)) {\n to[key] = Objector.deepClone(s[key]);\n }\n\n // Symbol keys\n const symbols = Object.getOwnPropertySymbols(s);\n // eslint-disable-next-line no-restricted-syntax\n for (const sym of symbols) {\n if (Object.prototype.propertyIsEnumerable.call(s, sym)) {\n to[sym] = Objector.deepClone(s[sym]);\n }\n }\n }\n }\n\n return to as MergeAll<[T, ...U]>;\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nimport { Kontororu } from '../Kontororu.js';\nimport { Objector } from '../Objector.js';\n\n\nexport type StoreData = Record<string, Record<string, unknown>>;\n\nexport class Store<TStore extends StoreData = StoreData> extends Kontororu {\n private store: TStore = {} as TStore;\n\n /**\n * Load an object into the store\n */\n load(data: TStore) {\n this.store = data;\n }\n\n /**\n * Get the first result\n */\n get<K extends keyof TStore>(table: K, args: Record<string, unknown> = {}): TStore[K][string] | null {\n const results = this.read(table, args);\n const firstId = Object.keys(results)[0];\n return firstId ? (results[firstId] as TStore[K][string]) : null;\n }\n\n /**\n * Read the results\n */\n read<K extends keyof TStore>(table: K, args: Record<string, unknown> = {}): Record<string, TStore[K][string]> {\n const data = this.store[table];\n if (!data) {\n return {};\n }\n\n const primaryKey = `${String(table)}_id`;\n\n // Fast path: Direct primary key lookup\n if (primaryKey in args) {\n const id = args[primaryKey] as string;\n if (data[id]) {\n return { [id]: Objector.deepClone(data[id]) as TStore[K][string] };\n }\n return {};\n }\n\n // If no arguments are provided, return a deep clone of the entire table\n if (Object.keys(args).length === 0) {\n return Objector.deepClone(data) as Record<string, TStore[K][string]>;\n }\n\n const matches: Record<string, TStore[K][string]> = {};\n const mismatches: Record<string, boolean> = {};\n\n for (const id in data) {\n if (id in mismatches) {\n continue;\n }\n\n const row = data[id];\n if (!row || typeof row !== 'object' || Array.isArray(row)) {\n continue;\n }\n\n for (const column in args) {\n let match = false;\n const argVal = args[column];\n const rowVal = (row as Record<string, unknown>)[column];\n\n if (rowVal === argVal) {\n match = true;\n } else if (Array.isArray(argVal) && argVal.includes(rowVal)) {\n match = true;\n }\n\n if (match) {\n matches[id] = Objector.deepClone(row) as TStore[K][string];\n } else {\n mismatches[id] = true;\n delete matches[id];\n break;\n }\n }\n }\n\n return matches;\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/**\n * Table sorting helper utility\n */\nexport class Sorter {\n public static descendingComparator(a: Record<string, string | number>, b: Record<string, string | number>, orderBy: string, direction_?: string): number {\n if ((orderBy in a) && b[orderBy] === null) {\n return 1;\n }\n if (a[orderBy] === null && (orderBy in b)) {\n return -1;\n }\n\n const a_value = a[orderBy];\n const b_value = b[orderBy];\n\n const direction = direction_ || 'lower';\n\n if (b_value < a_value) {\n return direction === 'higher' ? 1 : -1;\n }\n if (b_value > a_value) {\n return direction === 'higher' ? -1 : 1;\n }\n return 0;\n }\n\n public static getComparator(order: string, orderBy: string, direction?: string): (a: Record<string, string | number>, b: Record<string, string | number>) => number {\n return order === 'desc'\n ? (a, b) => this.descendingComparator(a, b, orderBy, direction)\n : (a, b) => -this.descendingComparator(a, b, orderBy, direction);\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n/* eslint-disable no-restricted-syntax */\n/* eslint-disable no-bitwise */\n\n\n\n\ntype CSSMap = Map<string, string>;\n\ninterface ZIndexConfig {\n appBar: number;\n drawer: number;\n fab: number;\n calendar: number;\n mobileStepper: number;\n modal: number;\n toast: number;\n speedDial: number;\n tooltip: number;\n}\n\ninterface StyleConfig {\n zIndex: ZIndexConfig;\n}\n\ninterface NavBarStyle {\n width: string;\n display: string;\n justifyContent: string;\n zIndex: number;\n position: string;\n overflowX: string;\n overflowY: string;\n scrollbarWidth: string;\n}\n\n/**\n * CSS in JS processor and other random style functions\n */\nexport class Style {\n public static getStyle(): StyleConfig {\n return {\n zIndex: Style.getZIndex(),\n };\n }\n\n public static getZIndex(): ZIndexConfig {\n return {\n appBar: 1100,\n drawer: 1200,\n fab: 1050,\n calendar: 1000,\n mobileStepper: 1000,\n modal: 1300,\n toast: 1400,\n speedDial: 1050,\n tooltip: 1500,\n };\n }\n\n public static getNavBar(): NavBarStyle {\n return {\n width: '100%',\n display: 'flex',\n justifyContent: 'center',\n zIndex: Style.getZIndex().appBar,\n position: 'fixed',\n overflowX: 'scroll',\n overflowY: 'hidden',\n scrollbarWidth: 'none',\n };\n }\n\n public static getShadow(depth: number): string {\n const shadows = [\n 'none',\n '0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)',\n '0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)',\n '0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.14),0px 1px 8px 0px rgba(0,0,0,0.12)',\n '0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)',\n '0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.14),0px 1px 14px 0px rgba(0,0,0,0.12)',\n '0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)',\n '0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)',\n '0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)',\n '0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)',\n '0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)',\n '0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)',\n '0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)',\n '0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)',\n '0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)',\n '0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)',\n '0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)',\n '0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)',\n '0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)',\n '0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)',\n '0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)',\n '0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)',\n '0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)',\n '0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.14),0px 9px 44px 8px rgba(0,0,0,0.12)',\n '0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.14),0px 9px 46px 8px rgba(0,0,0,0.12)',\n ];\n\n if (depth > shadows.length || depth < 0) {\n throw new Error(`min depth is 0, max depth is ${shadows.length}. Sent ${depth}`);\n }\n\n return shadows[depth];\n }\n\n /**\n *\n *\n *\n *\n * Below is all the CSS injection from js\n *\n *\n *\n */\n\n /**\n * Call this to add css as a style-sheet, so you can do css selectors like hover td {} etc\n */\n public static getStyleClassName(cssString: string | object, debug = false): string {\n if (debug) {\n console.log('getStyleClassName', cssString);\n }\n // console.time('getStyleClassName')\n const className = `css-${this.hashCSS(cssString, debug)}`;\n\n this.injectStyle(className, cssString, debug);\n // console.timeEnd('getStyleClassName')\n return className;\n }\n\n public static getMap(): CSSMap {\n return this.cssMap;\n }\n\n // SSR helper to get all collected styles\n public static getCSS(): string {\n console.warn('this does not work yet, in root layout need to add a context thing so it attaches css to style when streamed from server');\n return Array.from(this.cssMap.values()).join('\\n');\n }\n\n // Call after SSR render to clean up for next render\n public static flush(): void {\n this.styleCache.clear();\n this.cssMap.clear();\n }\n\n private static styleCache: Set<string> = new Set();\n\n private static cssMap: CSSMap = new Map(); // key: className, value: finalCSS\n\n private static hashCSS(css: string | object, debug = false): string {\n const canonicalize = (obj: object | string | number): object | string | number => {\n if (typeof obj !== 'object' || obj === null) {\n // Return primitives as is\n return obj;\n }\n\n if (Array.isArray(obj)) {\n // Recursively canonicalize array elements\n return obj.map(canonicalize);\n }\n\n // 1. Get and sort the keys of the current object level\n const sortedKeys = Object.keys(obj).sort();\n const canonical: { [key: string]: unknown } = {};\n\n // cast object to record\n const sourceObj = obj as Record<string, string | number>;\n\n // 2. Build a new object using the sorted keys, and recursively process values\n for (const key of sortedKeys) {\n canonical[key] = canonicalize(sourceObj[key]);\n }\n\n return canonical;\n };\n\n const normalize = (val: string | object): string => {\n if (typeof val === 'string') {\n return val;\n }\n if (typeof val === 'object' && val !== null) {\n const canonicalObject = canonicalize(val);\n // Step B: Stringify the canonical object without a replacer\n return JSON.stringify(canonicalObject);\n }\n return String(val);\n };\n\n const normalizedInput = normalize(css);\n\n if (debug) {\n console.log('normalizedInput', normalizedInput);\n }\n\n // Example hash using a simple DJB2 hash (or use a stronger hash like SHA-1/MD5 if needed)\n let hash = 5381;\n for (let i = 0; i < normalizedInput.length; i++) {\n hash = (hash * 33) ^ normalizedInput.charCodeAt(i);\n }\n return (hash >>> 0).toString(36); // base36 for short string\n }\n\n private static injectStyle(className: string, css: string | object, debug = false): void {\n if (\n this.styleCache.has(className)\n ) {\n return;\n }\n\n const finalCSS = this.processCSS(className, css, false, debug);\n\n // If on server, store it only\n if (typeof window === 'undefined') {\n this.cssMap.set(className, finalCSS);\n } else {\n const styleEl = document.createElement('style');\n styleEl.textContent = finalCSS;\n document.head.appendChild(styleEl);\n }\n\n this.styleCache.add(className);\n this.cssMap.set(className, finalCSS);\n }\n\n private static processCSS(className: string, css: string | object, isRecursive = false, debug = false): string {\n // Helper: remove trailing colon from selectors (e.g. 'td:' -> 'td')\n const cleanSelector = (sel:string): string => {\n return sel.replace(/:$/g, '');\n };\n\n // Convert camelCase to kebab-case for property names\n const toKebabCase = (str: string): string => {\n return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n };\n\n // Helper: Remove the specific '}' that closed the block from the accumulated lines\n // so we don't duplicate it when wrapping the result in new braces.\n const removeLastBrace = (lines: string[]) => {\n if (lines.length === 0) return;\n const lastIdx = lines.length - 1;\n const lastLine = lines[lastIdx];\n\n const braceIdx = lastLine.lastIndexOf('}');\n if (braceIdx !== -1) {\n // Remove the brace\n const newLine = lastLine.substring(0, braceIdx) + lastLine.substring(braceIdx + 1);\n\n // If the line is now empty (or just whitespace), remove it entirely\n if (!newLine.trim()) {\n lines.pop();\n } else {\n // eslint-disable-next-line no-param-reassign\n lines[lastIdx] = newLine;\n }\n }\n };\n\n const requiresQuotes = new Set([\n 'content',\n 'quotes',\n 'cue',\n 'cue-before',\n 'cue-after',\n 'src',\n ]);\n\n // List of properties that should have units if the value is a number\n const lengthProps = new Set([\n 'width', 'height', 'top', 'left', 'right', 'bottom',\n 'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',\n 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',\n 'font-size', 'border-width', 'border-radius', 'gap', 'column-gap', 'row-gap',\n 'min-width', 'min-height', 'max-width', 'max-height',\n ]);\n\n const non_recursive_at_rules = [\n '@keyframes',\n '@-webkit-keyframes',\n '@font-face',\n '@counter-style',\n ];\n\n const isNonRecursiveRule = (ruleName: string) => {\n return non_recursive_at_rules.some((prefix) => ruleName.startsWith(prefix));\n };\n\n const normalizeValue = (property: string, value: string | number): string | number => {\n if (!lengthProps.has(property)) {\n return value;\n }\n\n // If it's a number, add px\n if (typeof value === 'number') {\n return `${value}px`;\n }\n\n // If it's a numeric string with no unit, add px\n if (typeof value === 'string') {\n const trimmed = value.trim();\n\n // Match numeric string (integer or decimal), no unit\n if (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n return `${trimmed}px`;\n }\n\n // If it ends in known units or keywords, leave it alone\n return trimmed;\n }\n\n return value;\n };\n\n // Convert a line like \"backgroundColor: red;\" to \"background-color: red;\"\n const normalizeCSSLine = (line: string): string => {\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n return line; // Not a CSS property line\n }\n\n const rawProperty = line.slice(0, colonIndex).trim();\n let value: string | number = line.slice(colonIndex + 1).trim();\n\n const property = toKebabCase(rawProperty);\n\n // Remove trailing comma\n if (value.endsWith(',')) {\n value = value.slice(0, -1).trim();\n }\n\n // Only strip quotes if it's NOT a property like 'content'\n if (!requiresQuotes.has(property)) {\n value = value\n .split(',')\n .map((part) => {\n const trimmed = part.trim();\n // Check if the part is wrapped in quotes\n const match = trimmed.match(/^[\"'](.*)[\"']$/);\n\n if (match) {\n const innerValue = match[1];\n // If there's a space, keep the quotes (e.g., \"Segoe UI\")\n // If no space, strip them (e.g., \"Arial\" -> Arial)\n return innerValue.includes(' ') ? trimmed : innerValue;\n }\n return trimmed;\n })\n .join(', ');\n }\n\n value = normalizeValue(property, value);\n\n let cssLine = `${property}: ${value}`;\n if (!cssLine.endsWith(';')) {\n cssLine += ';';\n }\n\n return cssLine;\n };\n\n // Convert CSS object into flat lines\n const objectToLines = (obj: object): string[] => {\n const lines: string[] = [];\n\n const sourceObj = obj as Record<string, unknown>;\n\n for (const key in sourceObj) {\n const value = sourceObj[key];\n\n if (typeof value === 'object' && value !== null) {\n lines.push(`${key} {`);\n const nested = objectToLines(value);\n lines.push(...nested);\n lines.push('}');\n } else {\n // Note:\n // - We add a comma here to support object syntax, normalizeCSSLine will handle removing it and adding semicolons later.\n // - Don't stringify strings, to avoid double-escaping quotes (e.g. content: '\"*\"')\n const finalValue = typeof value === 'string' ? value : String(value);\n lines.push(`${key}: ${finalValue},`);\n }\n }\n\n return lines;\n };\n\n // Prepare raw lines\n const lines = typeof css === 'string'\n ? css.trim().split('\\n').map((line) => line.trim()).filter(Boolean)\n : objectToLines(css);\n\n\n const topLevelRules: string[] = [];\n const nestedRules: string[] = [];\n const atRules: string[] = [];\n\n let currentNestedSelector: string | null = null;\n let currentAtRule: string | null = null;\n let atRuleLines: string[] = [];\n let atRuleBraceCount = 0;\n let nestedLines: string[] = [];\n let nestedBraceCount = 0;\n\n for (const line of lines) {\n // 1. AT-RULE HANDLING (@media, @keyframes)\n if (line.startsWith('@') || currentAtRule) {\n if (!currentAtRule) currentAtRule = line.split('{')[0].trim();\n atRuleLines.push(line);\n atRuleBraceCount += (line.match(/{/g) || []).length;\n atRuleBraceCount -= (line.match(/}/g) || []).length;\n\n if (atRuleBraceCount === 0) {\n const rawBlock = atRuleLines.join('\\n');\n const contentOnly = rawBlock.substring(rawBlock.indexOf('{') + 1, rawBlock.lastIndexOf('}')).trim();\n\n if (currentAtRule.startsWith('@keyframes')) {\n // Keyframes: Process units/semicolons but DO NOT wrap in class\n const processed = contentOnly.split('\\n').map((l) => {\n if (l.includes('{') || l.includes('}')) return l;\n return normalizeCSSLine(l);\n }).join(' ');\n atRules.push(`${currentAtRule} { ${processed} }`);\n } else {\n // Media Queries: Recursive call to wrap in class\n const processed = this.processCSS(className, contentOnly, false, debug);\n atRules.push(`${currentAtRule} { ${processed} }`);\n }\n currentAtRule = null;\n atRuleLines = [];\n }\n continue;\n }\n\n // 2. NESTED SELECTOR HANDLING (&:hover, ::before)\n if (line.includes('{') || currentNestedSelector) {\n if (!currentNestedSelector) {\n currentNestedSelector = line.split('{')[0].trim();\n\n // Identify \"Highlight Pseudo-elements\" that need global scoping for Safari/WebKit compatibility\n const isHighlightPseudo = /::(selection|target-text|highlight|spelling-error|grammar-error)/.test(currentNestedSelector);\n\n // Standard behavior: auto-prefix with '&' if it starts with ':'\n // Special behavior: If it's a Highlight Pseudo, we leave it alone so it stays global\n if (\n currentNestedSelector.startsWith(':') &&\n !currentNestedSelector.startsWith('&') &&\n !isHighlightPseudo\n ) {\n currentNestedSelector = `&${currentNestedSelector}`;\n }\n } else if (!line.includes('}')) {\n nestedLines.push(normalizeCSSLine(line));\n }\n\n nestedBraceCount += (line.match(/{/g) || []).length;\n nestedBraceCount -= (line.match(/}/g) || []).length;\n\n if (nestedBraceCount === 0) {\n const isHighlightPseudo = /::(selection|target-text|highlight|spelling-error|grammar-error)/.test(currentNestedSelector);\n\n // If it's a Highlight Pseudo, we DON'T prefix with the .className.\n // This makes it global, which is required for Safari to render it correctly.\n const selector = isHighlightPseudo\n ? currentNestedSelector\n : currentNestedSelector.replace(/&/g, `.${className}`);\n\n nestedRules.push(`${selector} { ${nestedLines.join(' ')} }`);\n currentNestedSelector = null;\n nestedLines = [];\n }\n continue;\n }\n\n // 3. TOP LEVEL PROPERTIES\n topLevelRules.push(normalizeCSSLine(line));\n }\n\n const topLevelCSS = (!isRecursive && topLevelRules.length > 0)\n ? `.${className} { ${topLevelRules.join(' ')} }`\n : topLevelRules.join(' ');\n\n return `${topLevelCSS} ${nestedRules.join(' ')} ${atRules.join(' ')}`.replace(/\\s\\s+/g, ' ').trim();\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nexport class Textor {\n public static levenshtein(a: string, b: string): number {\n const matrix: number[][] = [];\n\n if (!a || !b) {\n return 0;\n }\n\n // Initialize the matrix with base case values\n for (let i = 0; i <= a.length; i++) {\n matrix[i] = [i];\n }\n for (let j = 0; j <= b.length; j++) {\n matrix[0][j] = j;\n }\n\n // Populate the matrix with distances\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n\n matrix[i][j] = Math.min(\n matrix[i - 1][j] + 1, // Deletion\n matrix[i][j - 1] + 1, // Insertion\n matrix[i - 1][j - 1] + cost, // Substitution\n );\n }\n }\n\n // The final value is the Levenshtein distance\n return matrix[a.length][b.length];\n }\n\n public static toSentenceCase(str: string): string {\n if (!str) {\n return '';\n }\n\n // Trim the string to remove extra whitespace\n const trimmed = str.trim();\n\n // Convert the first letter to uppercase and the rest to lowercase\n return trimmed.charAt(0).toUpperCase() + trimmed.slice(1).toLowerCase();\n }\n\n /**\n * Generates pseudo-Latin Lorem Ipsum placeholder text.\n */\n public static generateLoremIpsum(\n paragraphs = 3,\n sentencesPerParagraph = 5,\n startWithLorem = true,\n ): string {\n const words = [\n 'lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit',\n 'sed', 'do', 'eiusmod', 'tempor', 'incididunt', 'ut', 'labore', 'et', 'dolore',\n 'magna', 'aliqua', 'ut', 'enim', 'ad', 'minim', 'veniam', 'quis', 'nostrud',\n 'exercitation', 'ullamco', 'laboris', 'nisi', 'ut', 'aliquip', 'ex', 'ea',\n 'commodo', 'consequat', 'duis', 'aute', 'irure', 'dolor', 'in', 'reprehenderit',\n 'in', 'voluptate', 'velit', 'esse', 'cillum', 'dolore', 'eu', 'fugiat', 'nulla',\n 'pariatur', 'excepteur', 'sint', 'occaecat', 'cupidatat', 'non', 'proident',\n 'sunt', 'in', 'culpa', 'qui', 'officia', 'deserunt', 'mollit', 'anim', 'id',\n 'est', 'laborum',\n ];\n\n // Helper to get a random word from the pool\n const getRandomWord = () => words[Math.floor(Math.random() * words.length)];\n\n // Helper to generate a single sentence\n const generateSentence = (isFirstSentence = false) => {\n if (isFirstSentence && startWithLorem) {\n return 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';\n }\n\n // Sentences typically range from 5 to 15 words\n const sentenceLength = Math.floor(Math.random() * 11) + 5;\n const sentenceWords = [];\n\n for (let i = 0; i < sentenceLength; i++) {\n sentenceWords.push(getRandomWord());\n }\n\n // Capitalize the first letter of the sentence\n let sentence = sentenceWords.join(' ');\n sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1);\n\n // Occasionally add commas for realistic phrasing (approx. 20% chance if long enough)\n if (sentenceLength > 8 && Math.random() > 0.8) {\n const commaIndex = Math.floor(sentenceLength / 2);\n const splitSentence = sentence.split(' ');\n splitSentence[commaIndex] += ',';\n sentence = splitSentence.join(' ');\n }\n\n return `${sentence}.`;\n };\n\n const paragraphList = [];\n\n for (let p = 0; p < paragraphs; p++) {\n const sentenceCount = Math.max(3, Math.round(sentencesPerParagraph + (Math.random() * 4 - 2))); // slight variance\n const sentences = [];\n\n for (let s = 0; s < sentenceCount; s++) {\n // Only the absolute first sentence of the entire text gets the classic intro\n const isAbsoluteFirst = p === 0 && s === 0;\n sentences.push(generateSentence(isAbsoluteFirst));\n }\n\n paragraphList.push(sentences.join(' '));\n }\n\n // Join paragraphs with double line breaks\n return paragraphList.join('\\n\\n');\n }\n}\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\nexport type ThemeType = ReturnType<Theme['getTheme']>;\n\n// all these types are for jsr / deno because it cant use the dynamic one above >.>\n\ninterface ColorScale {\n 50: string;\n 100: string;\n 200: string;\n 300: string;\n 400: string;\n 500: string;\n 600: string;\n 700: string;\n 800: string;\n 900: string;\n A100: string;\n A200: string;\n A400: string;\n A700: string;\n}\n\ninterface BrownScale {\n 50: string;\n 100: string;\n 200: string;\n 300: string;\n 400: string;\n 500: string;\n 600: string;\n 700: string;\n 800: string;\n 900: string;\n}\n\ninterface ColorGroup {\n main: string;\n light: string;\n dark: string;\n}\n\ninterface ColorGroupWithContrast extends ColorGroup {\n contrastText: string;\n}\n\ninterface ActionConfig {\n active: string;\n disabled: string;\n disabledBackground: string;\n disabledOpacity: number;\n focus: string;\n focusOpacity: number;\n hover: string;\n hoverOpacity: number;\n selected: string;\n selectedOpacity: number;\n}\n\ninterface ColorPalette {\n grey: ColorScale;\n red: ColorScale;\n pink: ColorScale;\n purple: ColorScale;\n deepPurple: ColorScale;\n indigo: ColorScale;\n blue: ColorScale;\n lightBlue: ColorScale;\n cyan: ColorScale;\n teal: ColorScale;\n green: ColorScale;\n lightGreen: ColorScale;\n lime: ColorScale;\n yellow: ColorScale;\n amber: ColorScale;\n orange: ColorScale;\n deepOrange: ColorScale;\n brown: BrownScale;\n}\n\ninterface DarkTheme extends ColorPalette {\n mode: 'dark';\n background: { main: string };\n header: { main: string };\n primary: ColorGroup;\n secondary: ColorGroup;\n warning: ColorGroup;\n success: ColorGroup;\n error: ColorGroup;\n info: ColorGroup;\n text: { primary: string; secondary: string; disabled: string; icon: string };\n link: { primary: string };\n action: ActionConfig;\n}\n\ninterface LightTheme extends ColorPalette {\n mode: 'light';\n background: { main: string; light: string };\n header: { main: string };\n primary: ColorGroupWithContrast;\n secondary: ColorGroupWithContrast;\n warning: ColorGroupWithContrast;\n success: ColorGroupWithContrast;\n error: ColorGroupWithContrast;\n info: ColorGroupWithContrast;\n text: { primary: string; secondary: string; disabled: string };\n link: { primary: string };\n action: ActionConfig;\n}\n\n/**\n * Class to get the theme\n */\nexport class Theme {\n public constructor(mode: string) {\n this.mode = mode;\n\n if (mode !== 'light' && mode !== 'dark') {\n throw new Error(`Unknown theme: ${mode}`);\n }\n }\n\n private mode: string;\n\n public getTheme(): DarkTheme | LightTheme {\n if (this.mode === 'light') {\n return this.getLightTheme();\n }\n\n return this.getDarkTheme();\n }\n\n public getDarkTheme(): DarkTheme {\n return {\n mode: 'dark',\n background: {\n main: '#121212',\n },\n header: {\n main: this.getGrey()[900],\n },\n primary: {\n main: '#90caf9',\n light: '#e3f2fd',\n dark: '#42a5f5',\n },\n secondary: {\n main: '#ce93d8',\n light: '#f3e5f5',\n dark: '#ab47bc',\n },\n warning: {\n main: '#ffa726',\n light: '#ffb74d',\n dark: '#f57c00',\n },\n success: {\n main: '#66bb6a',\n light: '#81c784',\n dark: '#388e3c',\n },\n error: {\n main: '#f44336',\n dark: '#d32f2f',\n light: '#e57373',\n },\n info: {\n main: '#29b6f6',\n dark: '#0288d1',\n light: '#4fc3f7',\n },\n text: {\n primary: '#fff',\n secondary: '#B3B3B3',\n disabled: '#808080',\n icon: '#808080',\n },\n link: {\n primary: '#90caf9',\n },\n action: {\n active: '#fff',\n disabled: 'rgba(255, 255, 255, 0.3)',\n disabledBackground: 'rgba(255, 255, 255, 0.12)',\n disabledOpacity: 0.38,\n focus: 'rgba(255, 255, 255, 0.12)',\n focusOpacity: 0.12,\n hover: 'rgba(255, 255, 255, 0.08)',\n hoverOpacity: 0.08,\n selected: 'rgba(255, 255, 255, 0.16)',\n selectedOpacity: 0.16,\n },\n grey: this.getGrey(),\n red: this.getRed(),\n pink: this.getPink(),\n purple: this.getPurple(),\n deepPurple: this.getDeepPurple(),\n indigo: this.getIndigo(),\n blue: this.getBlue(),\n lightBlue: this.getLightBlue(),\n cyan: this.getCyan(),\n teal: this.getTeal(),\n green: this.getGreen(),\n lightGreen: this.getLightGreen(),\n lime: this.getLime(),\n yellow: this.getYellow(),\n amber: this.getAmber(),\n orange: this.getOrange(),\n deepOrange: this.getDeepOrange(),\n brown: this.getBrown(),\n };\n }\n\n public getLightTheme(): LightTheme {\n return {\n mode: 'light',\n background: {\n main: '#efefef',\n light: '#fff',\n },\n header: {\n main: this.getBlue()[700],\n },\n primary: {\n main: '#1976d2',\n light: '#42a5f5',\n dark: '#1565c0',\n contrastText: '#fff',\n },\n secondary: {\n main: '#9c27b0',\n light: '#ba68c8',\n dark: '#7b1fa2',\n contrastText: '#fff',\n },\n error: {\n main: '#d32f2f',\n light: '#ef5350',\n dark: '#c62828',\n contrastText: '#fff',\n },\n warning: {\n main: '#ed6c02',\n light: '#ff9800',\n dark: '#e65100',\n contrastText: '#fff',\n },\n info: {\n main: '#0288d1',\n light: '#03a9f4',\n dark: '#01579b',\n contrastText: '#fff',\n },\n success: {\n main: '#2e7d32',\n light: '#4caf50',\n dark: '#1b5e20',\n contrastText: '#fff',\n },\n text: {\n primary: '#222222',\n secondary: '#666666',\n disabled: '#9E9E9E',\n },\n link: {\n primary: '#1976d2',\n },\n action: {\n active: 'rgba(0, 0, 0, 0.54)',\n disabled: 'rgba(0, 0, 0, 0.26)',\n disabledBackground: 'rgba(0, 0, 0, 0.12)',\n disabledOpacity: 0.38,\n focus: 'rgba(0, 0, 0, 0.12)',\n focusOpacity: 0.12,\n hover: 'rgba(0, 0, 0, 0.04)',\n hoverOpacity: 0.04,\n selected: 'rgba(0, 0, 0, 0.08)',\n selectedOpacity: 0.08,\n },\n grey: this.getGrey(),\n red: this.getRed(),\n pink: this.getPink(),\n purple: this.getPurple(),\n deepPurple: this.getDeepPurple(),\n indigo: this.getIndigo(),\n blue: this.getBlue(),\n lightBlue: this.getLightBlue(),\n cyan: this.getCyan(),\n teal: this.getTeal(),\n green: this.getGreen(),\n lightGreen: this.getLightGreen(),\n lime: this.getLime(),\n yellow: this.getYellow(),\n amber: this.getAmber(),\n orange: this.getOrange(),\n deepOrange: this.getDeepOrange(),\n brown: this.getBrown(),\n };\n }\n\n private getGrey(): ColorScale {\n return {\n 50: '#fafafa',\n 100: '#f5f5f5',\n 200: '#eeeeee',\n 300: '#e0e0e0',\n 400: '#bdbdbd',\n 500: '#9e9e9e',\n 600: '#757575',\n 700: '#616161',\n 800: '#424242',\n 900: '#212121',\n A100: '#f5f5f5',\n A200: '#eeeeee',\n A400: '#bdbdbd',\n A700: '#616161',\n };\n }\n\n private getRed(): ColorScale {\n return {\n 50: '#ffebee',\n 100: '#ffcdd2',\n 200: '#ef9a9a',\n 300: '#e57373',\n 400: '#ef5350',\n 500: '#f44336',\n 600: '#e53935',\n 700: '#d32f2f',\n 800: '#c62828',\n 900: '#b71c1c',\n A100: '#ff8a80',\n A200: '#ff5252',\n A400: '#ff1744',\n A700: '#d50000',\n };\n }\n\n private getPink(): ColorScale {\n return {\n 50: '#fce4ec',\n 100: '#f8bbd0',\n 200: '#f48fb1',\n 300: '#f06292',\n 400: '#ec407a',\n 500: '#e91e63',\n 600: '#d81b60',\n 700: '#c2185b',\n 800: '#ad1457',\n 900: '#880e4f',\n A100: '#ff80ab',\n A200: '#ff4081',\n A400: '#f50057',\n A700: '#c51162',\n };\n }\n\n private getPurple(): ColorScale {\n return {\n 50: '#f3e5f5',\n 100: '#e1bee7',\n 200: '#ce93d8',\n 300: '#ba68c8',\n 400: '#ab47bc',\n 500: '#9c27b0',\n 600: '#8e24aa',\n 700: '#7b1fa2',\n 800: '#6a1b9a',\n 900: '#4a148c',\n A100: '#ea80fc',\n A200: '#e040fb',\n A400: '#d500f8',\n A700: '#aa00ff',\n };\n }\n\n private getDeepPurple(): ColorScale {\n return {\n 50: '#ede7f6',\n 100: '#d1c4e9',\n 200: '#b39ddb',\n 300: '#9575cd',\n 400: '#7e57c2',\n 500: '#673ab7',\n 600: '#5e35b1',\n 700: '#512da8',\n 800: '#4527a0',\n 900: '#311b92',\n A100: '#b388ff',\n A200: '#7c4dff',\n A400: '#651fff',\n A700: '#6200ea',\n };\n }\n\n private getIndigo(): ColorScale {\n return {\n 50: '#e8eaf6',\n 100: '#c5cae9',\n 200: '#9fa8da',\n 300: '#7986cb',\n 400: '#5c6bc0',\n 500: '#3f51b5',\n 600: '#3949ab',\n 700: '#303f9f',\n 800: '#283593',\n 900: '#1a237e',\n A100: '#8c9eff',\n A200: '#536dfe',\n A400: '#3d5afe',\n A700: '#304ffe',\n };\n }\n\n private getBlue(): ColorScale {\n return {\n 50: '#e3f2fd',\n 100: '#bbdefb',\n 200: '#90caf9',\n 300: '#64b5f6',\n 400: '#42a5f5',\n 500: '#2196f3',\n 600: '#1e88e5',\n 700: '#1976d2',\n 800: '#1565c0',\n 900: '#0d47a1',\n A100: '#82b1ff',\n A200: '#448aff',\n A400: '#2979ff',\n A700: '#2962ff',\n };\n }\n\n private getLightBlue(): ColorScale {\n return {\n 50: '#e1f5fe',\n 100: '#b3e5fc',\n 200: '#81d4fa',\n 300: '#4fc3f7',\n 400: '#29b6f6',\n 500: '#03a9f4',\n 600: '#039be5',\n 700: '#0288d1',\n 800: '#0277bd',\n 900: '#01579b',\n A100: '#80d8ff',\n A200: '#40c4ff',\n A400: '#00b0ff',\n A700: '#0091ea',\n };\n }\n\n private getCyan(): ColorScale {\n return {\n 50: '#e0f7fa',\n 100: '#b2ebf2',\n 200: '#80deea',\n 300: '#4dd0e1',\n 400: '#26c6da',\n 500: '#00bcd4',\n 600: '#00acc1',\n 700: '#0097a7',\n 800: '#00838f',\n 900: '#006064',\n A100: '#84ffff',\n A200: '#18ffff',\n A400: '#00e5ff',\n A700: '#00b8d4',\n };\n }\n\n private getTeal(): ColorScale {\n return {\n 50: '#e0f2f1',\n 100: '#b2dfdb',\n 200: '#80cbc4',\n 300: '#4db6ac',\n 400: '#26a69a',\n 500: '#009688',\n 600: '#00897b',\n 700: '#00796b',\n 800: '#00695c',\n 900: '#004d40',\n A100: '#a7ffeb',\n A200: '#64ffda',\n A400: '#1de9b6',\n A700: '#00bfa5',\n };\n }\n\n private getGreen(): ColorScale {\n return {\n 50: '#e8f5e9',\n 100: '#c8e6c9',\n 200: '#a5d6a7',\n 300: '#81c784',\n 400: '#66bb6a',\n 500: '#4caf50',\n 600: '#43a047',\n 700: '#388e3c',\n 800: '#2e7d32',\n 900: '#1b5e20',\n A100: '#b9f6ca',\n A200: '#69f0ae',\n A400: '#00e676',\n A700: '#00c853',\n };\n }\n\n private getLightGreen(): ColorScale {\n return {\n 50: '#f1f8e9',\n 100: '#dcedc8',\n 200: '#c5e1a5',\n 300: '#aed581',\n 400: '#9ccc65',\n 500: '#8bc34a',\n 600: '#7cb342',\n 700: '#689f38',\n 800: '#558b2f',\n 900: '#33691e',\n A100: '#ccff90',\n A200: '#b2ff59',\n A400: '#76ff03',\n A700: '#64dd17',\n };\n }\n\n private getLime(): ColorScale {\n return {\n 50: '#f9fbe7',\n 100: '#f0f4c3',\n 200: '#e6ee9c',\n 300: '#dce775',\n 400: '#d4e157',\n 500: '#cddc39',\n 600: '#c0ca33',\n 700: '#afb42b',\n 800: '#9fa827',\n 900: '#827717',\n A100: '#f4ff81',\n A200: '#eeff41',\n A400: '#c6ff00',\n A700: '#aeea00',\n };\n }\n\n private getYellow(): ColorScale {\n return {\n 50: '#fffde7',\n 100: '#fff9c4',\n 200: '#fff59d',\n 300: '#fff176',\n 400: '#ffee58',\n 500: '#ffeb3b',\n 600: '#fdd835',\n 700: '#fbc02d',\n 800: '#f9a825',\n 900: '#f57f17',\n A100: '#ffff8d',\n A200: '#ffff00',\n A400: '#ffea00',\n A700: '#ffd600',\n };\n }\n\n private getAmber(): ColorScale {\n return {\n 50: '#fff8e1',\n 100: '#ffecb3',\n 200: '#ffe082',\n 300: '#ffd54f',\n 400: '#ffca28',\n 500: '#ffc107',\n 600: '#ffb300',\n 700: '#ffa000',\n 800: '#ff8f00',\n 900: '#ff6f00',\n A100: '#ffe57f',\n A200: '#ffd740',\n A400: '#ffc400',\n A700: '#ffab00',\n };\n }\n\n private getOrange(): ColorScale {\n return {\n 50: '#fff3e0',\n 100: '#ffe0b2',\n 200: '#ffcc80',\n 300: '#ffb74d',\n 400: '#ffa726',\n 500: '#ff9800',\n 600: '#fb8c00',\n 700: '#f57c00',\n 800: '#ef6c00',\n 900: '#e65100',\n A100: '#ffd180',\n A200: '#ffab40',\n A400: '#ff9100',\n A700: '#ff6d00',\n };\n }\n\n private getDeepOrange(): ColorScale {\n return {\n 50: '#fbe9e7',\n 100: '#ffccbc',\n 200: '#ffab91',\n 300: '#ff8a65',\n 400: '#ff7043',\n 500: '#ff5722',\n 600: '#f4511e',\n 700: '#e64a19',\n 800: '#d84315',\n 900: '#bf360c',\n A100: '#ff9e80',\n A200: '#ff6e40',\n A400: '#ff3d00',\n A700: '#dd2c00',\n };\n }\n\n private getBrown(): BrownScale {\n return {\n 50: '#efebe9',\n 100: '#d7ccc8',\n 200: '#bcaaa4',\n 300: '#a1887f',\n 400: '#8d6e63',\n 500: '#795548',\n 600: '#6d4c41',\n 700: '#5d4037',\n 800: '#4e342e',\n 900: '#3e2723',\n };\n }\n}\n\n", "/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n// Handles toast components throughout the app\n\nexport interface ToastItem {\n id: number;\n message: string;\n type: string;\n exiting?: boolean;\n}\n\n// Define the shape of the listener function\nexport type ToastListener = (toasts: ToastItem[]) => void;\n\nexport class Toaster {\n private listeners: ToastListener[] = [];\n\n private toasts: ToastItem[] = [];\n\n // React component will subscribe to this\n subscribe(listener: ToastListener): () => void {\n this.listeners.push(listener);\n return () => {\n this.listeners = this.listeners.filter((l) => l !== listener);\n };\n }\n\n notify(): void {\n this.listeners.forEach((listener) => listener(this.toasts));\n }\n\n requestClose(id: number): void {\n this.toasts = this.toasts.map((t) => {\n if (t.id === id) {\n return { ...t, exiting: true };\n }\n return t;\n });\n this.notify();\n }\n\n add(message: string, type = 'info'): void {\n const id = Date.now();\n this.toasts = [...this.toasts, { id, message, type }];\n this.notify();\n\n // Auto-remove\n setTimeout(() => {\n this.requestClose(id);\n }, 4000);\n }\n\n remove(id: number): void {\n this.toasts = this.toasts.filter((t) => t.id !== id);\n this.notify();\n }\n}\n\nexport const toaster: Toaster = new Toaster();\n\nexport const toast: {\n info: (msg: string) => void;\n error: (msg: string) => void;\n success: (msg: string) => void;\n} = {\n info: (msg: string) => toaster.add(msg, 'info'),\n error: (msg: string) => toaster.add(msg, 'error'),\n success: (msg: string) => toaster.add(msg, 'success'),\n};\n", "/* eslint-disable no-bitwise */\n/*\n * Copyright 2026 Evan Smalley.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n */\n\n\n/**\n * Generate UUIDv7\n */\nclass UuidService {\n private lastTimestamp = -1;\n private seqCounter = 0;\n\n private getRandomBytes(size: number): Uint8Array {\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n const bytes = new Uint8Array(size);\n globalThis.crypto.getRandomValues(bytes);\n return bytes;\n }\n\n throw new Error('Secure crypto functionality is not available in this environment.');\n }\n\n public generateUUIDv7Bytes(): Uint8Array {\n let now = Date.now();\n\n if (now === this.lastTimestamp) {\n this.seqCounter++;\n\n // 12-bit counter overflow (> 4095 IDs in 1ms): advance timestamp artificially\n if (this.seqCounter > 0x0fff) {\n this.lastTimestamp++;\n now = this.lastTimestamp;\n this.seqCounter = 0;\n }\n } else if (now < this.lastTimestamp) {\n // Clock drift / NTP rollback: hold timestamp and increment counter to maintain monotonicity\n this.seqCounter++;\n if (this.seqCounter > 0x0fff) {\n this.lastTimestamp++;\n this.seqCounter = 0;\n }\n now = this.lastTimestamp;\n } else {\n // New millisecond: update state and reset sequence counter\n this.lastTimestamp = now;\n this.seqCounter = 0;\n }\n\n // Allocate 16 random bytes for remaining entropy (rand_b)\n const buf = this.getRandomBytes(16);\n\n // 1. Write 48-bit Unix timestamp into bytes 0..5\n buf[0] = Math.floor(now / 0x10000000000) & 0xff;\n buf[1] = Math.floor(now / 0x100000000) & 0xff;\n buf[2] = (now >>> 24) & 0xff;\n buf[3] = (now >>> 16) & 0xff;\n buf[4] = (now >>> 8) & 0xff;\n buf[5] = now & 0xff;\n\n // 2. Byte 6: Version 7 (0x70) + upper 4 bits of 12-bit counter\n buf[6] = 0x70 | ((this.seqCounter >> 8) & 0x0f);\n\n // 3. Byte 7: Lower 8 bits of 12-bit counter\n buf[7] = this.seqCounter & 0xff;\n\n // 4. Byte 8: Set Variant RFC 4122 (0x80) on remaining random bits\n buf[8] = (buf[8] & 0x3f) | 0x80;\n\n return buf;\n }\n\n /**\n * Convert a UUID string to binary Uint8Array\n */\n public uuidToBin(uuid: string): Uint8Array {\n const hex = uuid.replaceAll('-', '');\n\n if (!/^[0-9a-fA-F]{32}$/.test(hex)) {\n throw new Error(`Invalid UUID: ${uuid}`);\n }\n\n const bytes = new Uint8Array(16);\n\n for (let i = 0; i < 16; i++) {\n bytes[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);\n }\n\n return bytes;\n }\n\n /**\n * Convert binary Uint8Array/Buffer to formatted UUID string\n */\n public binToUuid(buffer: Uint8Array): string {\n if (buffer.length !== 16) {\n throw new Error('UUID buffer must contain exactly 16 bytes.');\n }\n let hex = '';\n for (let i = 0; i < buffer.length; i++) {\n hex += buffer[i].toString(16).padStart(2, '0');\n }\n\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n }\n}\n// export as a singleton\nexport const uuidService = new UuidService();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Arithmetic", "number", "min", "max", "Arrayifier", "array", "currentIndex", "randomIndex", "arr", "n", "r", "index", "data", "i", "results", "CSV", "data", "rows", "setHeaders", "headers", "id", "row", "values", "header", "content", "blob", "url", "Color", "_Color", "a", "b", "amount", "ah", "ar", "ag", "ab", "bh", "br", "bg", "bb", "rr", "rg", "rb", "color", "backgroundColor", "debug", "g", "contrastTarget", "contrastToBlack", "contrastToWhite", "direction", "adjust", "c", "lighter", "i", "rgb1", "rgb2", "luminance", "r", "v", "lum1", "lum2", "hex", "remaining", "r2", "g2", "b2", "percent", "color1", "color2", "threshold", "invertedR", "invertedG", "invertedB", "alpha", "h", "s", "l", "analogousColors", "offset", "newHue", "newR", "newG", "newB", "char", "bigint", "max", "min", "d", "hue2rgb", "p", "q", "t", "r1", "g1", "b1", "dr", "dg", "db", "Dates", "str", "utc", "input", "year", "month", "day", "timePart", "isoMatch", "usMatch", "d", "hours", "minutes", "seconds", "timeMatch", "meridiem", "dateInput", "format", "date", "pad", "n", "monthsShort", "monthsLong", "daysShort", "daysLong", "Y", "y", "dateNum", "tzAbbr", "tzIdentifier", "getOrdinalSuffix", "v", "tokens", "_", "esc", "token", "amount", "unit", "originalDay", "map", "diff", "mins", "dateToMatch", "datesArray", "matchDate", "closestDate", "closestDist", "dateStr", "currDate", "dist", "dayOfWeek", "result", "date1", "date2", "d1", "d2", "janOffset", "julOffset", "standardTimezoneOffset", "timeZone", "parts", "getPart", "type", "p", "weekday", "ms", "y1", "y2", "m1", "m2", "months", "years", "days", "weeks", "Kontororu", "__publicField", "type", "listener", "l", "i", "debug", "Socket", "Kontororu", "__publicField", "event", "offlineChecker", "checked", "checker", "hostname", "port", "path", "session_id", "config", "type", "table", "id", "payload", "new_connection_state", "old_connection_state", "source", "time_since_last", "queuedMsg", "data", "messageEvent", "delay", "socket", "Objector", "_Objector", "obj", "memo", "clonedMap", "value", "key", "newSet", "item", "clonedArray", "clonedObj", "sourceObj", "sym", "target", "sources", "to", "source", "symbols", "Store", "Kontororu", "__publicField", "data", "table", "args", "results", "firstId", "primaryKey", "id", "Objector", "matches", "mismatches", "row", "column", "match", "argVal", "rowVal", "Sorter", "a", "b", "orderBy", "direction_", "a_value", "b_value", "direction", "order", "_Style", "depth", "shadows", "cssString", "debug", "className", "css", "canonicalize", "obj", "sortedKeys", "canonical", "sourceObj", "key", "normalizedInput", "val", "canonicalObject", "hash", "finalCSS", "styleEl", "isRecursive", "cleanSelector", "sel", "toKebabCase", "str", "removeLastBrace", "lines", "lastIdx", "lastLine", "braceIdx", "newLine", "requiresQuotes", "lengthProps", "non_recursive_at_rules", "isNonRecursiveRule", "ruleName", "prefix", "normalizeValue", "property", "value", "trimmed", "normalizeCSSLine", "line", "colonIndex", "rawProperty", "part", "match", "innerValue", "cssLine", "objectToLines", "nested", "finalValue", "topLevelRules", "nestedRules", "atRules", "currentNestedSelector", "currentAtRule", "atRuleLines", "atRuleBraceCount", "nestedLines", "nestedBraceCount", "rawBlock", "contentOnly", "processed", "l", "isHighlightPseudo", "selector", "__publicField", "Style", "Textor", "a", "b", "matrix", "i", "j", "cost", "str", "trimmed", "paragraphs", "sentencesPerParagraph", "startWithLorem", "words", "getRandomWord", "generateSentence", "isFirstSentence", "sentenceLength", "sentenceWords", "sentence", "commaIndex", "splitSentence", "paragraphList", "p", "sentenceCount", "sentences", "s", "isAbsoluteFirst", "Theme", "mode", "__publicField", "Toaster", "__publicField", "listener", "l", "id", "t", "message", "type", "toaster", "toast", "msg", "UuidService", "__publicField", "size", "bytes", "now", "buf", "uuid", "hex", "i", "buffer", "uuidService"]
|
|
7
7
|
}
|