UNPKG

@usex/key-fleur

Version:

Generate beautiful, memorable, and poetic API keys and unique identifiers for your applications.

613 lines (607 loc) 11.8 kB
'use strict'; const THEMES = { haiku: [ "nyrae", "soliv", "virel", "ethae", "omura", "lyr", "aeli", "sirune", "nuvia", "evara", "halen", "ilari", "tyrel", "elune", "kairi", "syrel", "narun", "velia", "orune", "faeli" ], nocturnal: [ "luna", "night", "star", "owl", "dusk", "twilight", "midnight", "shade", "echo", "eclipse", "gloom", "moth", "raven", "void", "mist", "sleep", "howl", "nova", "quiet", "shiver", "dark", "silence", "phantom", "crescent", "hollow", "dream", "veil", "crypt", "umbra", "noir" ], sunny: [ "sol", "sun", "ray", "bright", "day", "dawn", "shine", "gold", "beam", "sky", "flare", "light", "summer", "glow", "warmth", "clear", "zenith", "haze", "amber", "bliss", "gleam", "glint", "sunrise", "radiant", "beam", "halo", "lucid", "fire", "flare", "glory" ], floreal: [ "rose", "lily", "petal", "bloom", "ivy", "orchid", "daisy", "violet", "primrose", "stem", "pollen", "sprout", "bud", "blossom", "flora", "camellia", "garden", "leaf", "nectar", "thistle", "lavender", "tulip", "clover", "hyacinth", "marigold", "chrysant", "wisteria", "magnolia", "peony", "fern" ], oceanic: [ "wave", "coral", "foam", "drift", "deep", "pearl", "tide", "gull", "salt", "whale", "kelp", "abyss", "current", "surf", "ocean", "marina", "shoal", "siren", "lagoon", "shell", "reef", "seastar", "nautilus", "spray", "undertow", "isle", "brine", "anchor", "swell", "ripple" ], crystalline: [ "crystal", "gem", "shard", "opal", "quartz", "glint", "ice", "snow", "frost", "facet", "prism", "glass", "clear", "gleam", "diamond", "shine", "mirror", "spark", "flake", "glow", "glacier", "amethyst", "glisten", "translucent", "silica", "bismuth", "halo", "chime", "lucent", "citrine" ], mythic: [ "aether", "wyrm", "oracle", "sigil", "blade", "fable", "mythos", "grimoire", "phoenix", "echo", "titan", "nymph", "elysium", "lore", "rune", "arcane", "wyrd", "hero", "legend", "shade", "sphinx", "hydra", "oblivion", "divine", "hex", "omen", "ritual", "saga", "daemon", "prophecy" ], forest: [ "moss", "bark", "deer", "grove", "tree", "fern", "owl", "leaf", "fox", "thicket", "pine", "birch", "root", "sap", "fungus", "log", "trail", "wild", "branch", "meadow", "cedar", "acorn", "willow", "glade", "lichen", "bluff", "elm", "spruce", "hedge", "nest" ], desert: [ "sand", "dune", "mirage", "sun", "dry", "camel", "cactus", "arid", "scorch", "salt", "wind", "dust", "stone", "haze", "burn", "sol", "flame", "crack", "barren", "sizzle", "ember", "serpent", "blister", "parch", "ash", "glare", "mesa", "quartz", "sirocco", "ridge" ], celestial: [ "nova", "orbit", "comet", "moon", "star", "sol", "galaxy", "void", "pulse", "flare", "venus", "eclipse", "plasma", "space", "light", "sphere", "sky", "drift", "saturn", "zero", "nebula", "equinox", "zenith", "meteor", "lunar", "solstice", "mercury", "aster", "axis", "horizon" ], library: [ "scroll", "ink", "book", "page", "shelf", "quiet", "dust", "study", "read", "verse", "prose", "codex", "folio", "scribe", "script", "glyph", "letter", "note", "pen", "volume", "archive", "index", "library", "margin", "annotation", "spine", "binding", "tome", "quill", "text" ], decay: [ "rot", "rust", "moss", "mold", "crack", "fade", "peel", "dust", "crumble", "ash", "time", "void", "wilt", "droop", "filth", "wear", "flaw", "scratch", "stain", "dull", "brittle", "smudge", "erode", "fracture", "debris", "decay", "fester", "grime", "soot", "relic" ], steampunk: [ "gear", "steam", "cog", "brass", "pipe", "gauge", "valve", "weld", "bolt", "clock", "spark", "smoke", "engine", "vane", "dial", "joint", "helm", "rivets", "boiler", "coil", "piston", "frame", "rotor", "socket", "vent", "torque", "copper", "chrono", "lever", "mech" ] }; const SOFT_CONS = "flmnrschv"; const VOWELS = "aeiouy"; function syllable() { return getRandomChar(SOFT_CONS) + getRandomChar(VOWELS); } function getRandomChar(chars) { return chars.charAt(Math.floor(Math.random() * chars.length)); } function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; } function getRandomElement(array) { return array[Math.floor(Math.random() * array.length)]; } function estimateSyllables(word) { if (!word || typeof word !== "string") { return 0; } word = word.toLowerCase(); const vowels = "aeiouy"; let count = 0; let prevChar = ""; for (const char of word) { if (vowels.includes(char) && !vowels.includes(prevChar)) { count++; } prevChar = char; } if (word.endsWith("e") && count > 1) { count--; } return Math.max(1, count); } const RUNES = ["now+1d", "now-2h", "dawn", "midnight", "solstice", "infinite", "epoch"]; function haiku(theme) { const allWords = Object.values(THEMES[theme]).flat().filter((word) => word); const shuffledWords = [...allWords].sort(() => Math.random() - 0.5); const usedWords = /* @__PURE__ */ new Set(); function findWords(targetSyllables) { const result = []; let total = 0; for (const word of shuffledWords) { if (!word || usedWords.has(word)) { continue; } const syll = estimateSyllables(word); if (syll === 0) { continue; } if (total + syll <= targetSyllables) { result.push(word.charAt(0).toUpperCase() + word.slice(1)); usedWords.add(word); total += syll; if (total === targetSyllables) { break; } } } return total === targetSyllables ? result : []; } const line1 = findWords(5); const line2 = findWords(7); const line3 = findWords(5); if (!line1.length || !line2.length || !line3.length) { return "incomplete-haiku"; } return [line1.join(""), line2.join(""), line3.join("")].join("-"); } function lace(theme) { const roots = THEMES[theme] || THEMES["haiku"]; const word = getRandomElement(roots); const mid = syllable(); return `${word}${mid}-${mid.split("").reverse().join("")}${word.split("").reverse().join("")}`; } function mirrora(_) { const s = syllable(); return `${s.split("").reverse().join("")}-${s}`; } function runeKey(theme) { const base = haiku(theme).charAt(0).toUpperCase() + haiku(theme).slice(1); const rune = getRandomElement(RUNES); return `${base}_${rune}`; } function sonnet(theme) { const roots = THEMES[theme] || THEMES["haiku"]; const firstWord = getRandomElement(roots); const secondWord = getRandomElement(roots); const firstSyll = syllable().slice(0, 2); const secondSyll = syllable().slice(0, 2); return `${firstWord.charAt(0).toUpperCase() + firstWord.slice(1)}${firstSyll}-${secondWord.charAt(0).toUpperCase() + secondWord.slice(1)}${secondSyll}`; } function sigil(theme) { const roots = THEMES[theme] || THEMES["haiku"]; const firstWord = getRandomElement(roots); const secondWord = getRandomElement(roots); return `${firstWord.charAt(0).toUpperCase() + firstWord.slice(1)}-${getRandomInt(100, 999)}-${secondWord.charAt(0).toUpperCase() + secondWord.slice(1)}`; } function seed(theme) { const roots = THEMES[theme] || THEMES["haiku"]; const word = getRandomElement(roots); const wordPrefix = word.slice(0, 4); const randomHex = getRandomInt(4096, 39321).toString(16); return `${wordPrefix.charAt(0).toUpperCase() + wordPrefix.slice(1)}-${randomHex}`; } function mantra(theme) { const roots = THEMES[theme] || THEMES["haiku"]; const word = getRandomElement(roots); const secondWord = getRandomElement(roots); return `${word.charAt(0).toUpperCase() + word.slice(1)}-${word.charAt(0).toUpperCase() + word.slice(1)}-${secondWord.charAt(0).toUpperCase() + secondWord.slice(1)}`; } function quartz(theme) { const roots = THEMES[theme] || THEMES["haiku"]; const root = getRandomElement(roots); const capitalized = root.charAt(0).toUpperCase() + root.slice(1); const rev = capitalized.split("").reverse().join("").slice(0, 4); const num = getRandomInt(10, 99).toString(); return `${capitalized}${num}.${num}${rev}`; } const MODES = { haiku, lace, mirrora, rune: runeKey, sonnet, sigil, seed, mantra, quartz }; function poeticKey(mode = "haiku", theme = "haiku") { const func = MODES[mode] || MODES["haiku"]; return func(theme); } function generateKeyFleur(options = {}) { const { mode = "haiku", theme = "haiku", count = 1 } = options; if (!MODES[mode]) { throw new Error(`Invalid mode: ${mode}. Available modes: ${Object.keys(MODES).join(", ")}`); } if (!THEMES[theme]) { throw new Error(`Invalid theme: ${theme}. Available themes: ${Object.keys(THEMES).join(", ")}`); } if (count < 1 || count > 100) { throw new Error("Count must be between 1 and 100"); } if (count === 1) { return poeticKey(mode, theme); } return Array.from({ length: count }, () => poeticKey(mode, theme)); } function isValidKeyFleur(key, mode) { if (!key || typeof key !== "string") { return { valid: false, reason: "Key must be a non-empty string" }; } const patterns = { haiku: /^[A-Z][a-z]+-[A-Z][a-z]+-[A-Z][a-z]+$/, lace: /^[a-z]+[a-z]{2}-[a-z]{2}[a-z]+$/, mirrora: /^[a-z]{2}-[a-z]{2}$/, rune: /^[A-Z][a-z]+-[A-Z][a-z]+-[A-Z][a-z]+_(now\+1d|now-2h|dawn|midnight|solstice|infinite|epoch)$/, sonnet: /^[A-Z][a-z]+[a-z]{2}-[A-Z][a-z]+[a-z]{2}$/, sigil: /^[A-Z][a-z]+-\d{3}-[A-Z][a-z]+$/, seed: /^[A-Z][a-z]{1,3}-[a-f0-9]{4}$/, mantra: /^[A-Z][a-z]+-[A-Z][a-z]+-[A-Z][a-z]+$/, quartz: /^[A-Z][a-z]+\d{2}\.\d{2}[A-Z][a-z]*$/ }; if (mode) { const pattern = patterns[mode]; if (!pattern) { return { valid: false, reason: `Unknown mode: ${mode}` }; } const valid = pattern.test(key); return { valid, mode: valid ? mode : void 0, reason: valid ? void 0 : `Key does not match ${mode} pattern`, parts: valid ? key.split(/[-_.]/) : void 0 }; } for (const [modeName, pattern] of Object.entries(patterns)) { if (pattern.test(key)) { return { valid: true, mode: modeName, parts: key.split(/[-_.]/) }; } } return { valid: false, reason: "Key does not match any known KeyFleur pattern" }; } exports.MODES = MODES; exports.THEMES = THEMES; exports.generateKeyFleur = generateKeyFleur; exports.isValidKeyFleur = isValidKeyFleur; exports.poeticKey = poeticKey;