{"version":3,"file":"nanoid.mjs","names":["pool: Uint8Array | undefined","id","randomBytes: Uint8Array | undefined","mask","bytes: Uint8Array","nanoid: Nanoid"],"sources":["../../src/nanoid/nanoid.ts"],"sourcesContent":["import { InvalidInputError } from '../errors'\n\n/** Default URL-safe alphabet (64 characters): A-Z, a-z, 0-9, underscore, hyphen */\nexport const URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'\n\nconst DEFAULT_SIZE = 21\nconst MAX_SIZE = 2048\nconst NANOID_REGEX = /^[A-Za-z0-9_-]+$/\n\n// Simple random pool for ultra-fast path (npm nanoid style - no thread-safety overhead)\nconst POOL_SIZE_MULTIPLIER = 128\nlet pool: Uint8Array | undefined\nlet poolOffset = 0\n\nfunction fillPool(bytes: number): void {\n  const size = bytes * POOL_SIZE_MULTIPLIER\n  if (!pool || pool.length < size) {\n    pool = new Uint8Array(size)\n    crypto.getRandomValues(pool)\n    poolOffset = 0\n  } else if (poolOffset + bytes > pool.length) {\n    crypto.getRandomValues(pool)\n    poolOffset = 0\n  }\n  poolOffset += bytes\n}\n\nexport type NanoidOptions = {\n  /**\n   * Random bytes for deterministic output (testing).\n   * For power-of-2 alphabets (2, 4, 8, 16, 32, 64, 128, 256): exactly `size` bytes needed.\n   * For other alphabets: ~size * 2 bytes needed (rejection sampling).\n   */\n  random?: Uint8Array\n  /**\n   * Custom alphabet to use. Default: URL-safe A-Za-z0-9_-\n   * Must be 2-256 printable ASCII characters (32-126) with no duplicates.\n   */\n  alphabet?: string\n  /**\n   * Length of generated ID. Default: 21. Maximum: 2048.\n   */\n  size?: number\n}\n\nexport type Nanoid = {\n  /** Generate nanoid with default settings */\n  (): string\n  /** Generate nanoid with custom size */\n  (size: number): string\n  /** Generate nanoid with options */\n  (options: NanoidOptions): string\n  /**\n   * Validate a nanoid string against the default URL-safe alphabet.\n   * Note: Does not validate IDs generated with custom alphabets.\n   */\n  isValid(id: unknown): id is string\n}\n\n/**\n * Validate alphabet: 2-256 printable ASCII chars, no duplicates\n */\nfunction validateAlphabet(alphabet: string): void {\n  if (alphabet.length < 2) {\n    throw new InvalidInputError('NANOID_ALPHABET_TOO_SHORT', 'Alphabet must contain at least 2 characters')\n  }\n  if (alphabet.length > 256) {\n    throw new InvalidInputError('NANOID_ALPHABET_TOO_LONG', 'Alphabet must not exceed 256 characters')\n  }\n  const seen = new Set<string>()\n  for (const char of alphabet) {\n    const code = char.charCodeAt(0)\n    if (code < 32 || code > 126) {\n      throw new InvalidInputError(\n        'NANOID_ALPHABET_INVALID_CHAR',\n        'Alphabet must contain only printable ASCII characters (32-126)',\n      )\n    }\n    if (seen.has(char)) {\n      throw new InvalidInputError('NANOID_ALPHABET_DUPLICATE', `Duplicate character in alphabet: \"${char}\"`)\n    }\n    seen.add(char)\n  }\n}\n\n/**\n * Validate size parameter\n */\nfunction validateSize(size: number): void {\n  if (!Number.isInteger(size) || size < 0) {\n    throw new InvalidInputError('NANOID_SIZE_INVALID', 'Size must be a non-negative integer')\n  }\n  if (size > MAX_SIZE) {\n    throw new InvalidInputError('NANOID_SIZE_TOO_LARGE', `Size must not exceed ${MAX_SIZE}`)\n  }\n}\n\n// Overloads\nfunction nanoidFn(): string\nfunction nanoidFn(size: number): string\nfunction nanoidFn(options: NanoidOptions): string\nfunction nanoidFn(sizeOrOptions?: number | NanoidOptions): string {\n  // ULTRA-FAST PATH: No arguments = default nanoid\n  // Uses simple pooled random bytes (npm nanoid style) for best performance\n  if (sizeOrOptions === undefined) {\n    fillPool(DEFAULT_SIZE)\n    let id = ''\n    for (let i = poolOffset - DEFAULT_SIZE; i < poolOffset; i++) {\n      id += URL_ALPHABET[pool![i] & 63]\n    }\n    return id\n  }\n\n  let size = DEFAULT_SIZE\n  let alphabet = URL_ALPHABET\n  let randomBytes: Uint8Array | undefined\n\n  if (typeof sizeOrOptions === 'number') {\n    size = sizeOrOptions\n  } else {\n    size = sizeOrOptions.size ?? DEFAULT_SIZE\n    alphabet = sizeOrOptions.alphabet ?? URL_ALPHABET\n    randomBytes = sizeOrOptions.random\n    if (sizeOrOptions.alphabet !== undefined) {\n      validateAlphabet(alphabet)\n    }\n  }\n\n  validateSize(size)\n\n  if (size === 0) return ''\n\n  const alphabetLen = alphabet.length\n\n  // FAST PATH: Power-of-2 alphabet (includes default 64-char)\n  // No rejection needed - each byte maps directly to a character\n  if ((alphabetLen & (alphabetLen - 1)) === 0) {\n    const mask = alphabetLen - 1\n    if (randomBytes && randomBytes.length < size) {\n      throw new InvalidInputError(\n        'NANOID_RANDOM_BYTES_INSUFFICIENT',\n        `Insufficient random bytes: need ${size}, have ${randomBytes.length}`,\n      )\n    }\n    const bytes = randomBytes?.subarray(0, size) ?? globalThis.crypto.getRandomValues(new Uint8Array(size))\n    let id = ''\n    for (let i = 0; i < size; i++) {\n      id += alphabet[bytes[i] & mask]\n    }\n    return id\n  }\n\n  // SLOW PATH: Rejection sampling for non-power-of-2 alphabets\n  // Calculate mask: smallest power-of-2 minus 1 that covers alphabet size\n  const mask = (2 << (31 - Math.clz32((alphabetLen - 1) | 1))) - 1\n  // Calculate step: random bytes per batch (1.6x accounts for rejection)\n  const step = Math.ceil((1.6 * mask * size) / alphabetLen)\n\n  let id = ''\n  let randomOffset = 0\n\n  while (id.length < size) {\n    let bytes: Uint8Array\n    if (randomBytes) {\n      if (randomBytes.length - randomOffset < step) {\n        throw new InvalidInputError(\n          'NANOID_RANDOM_BYTES_INSUFFICIENT',\n          `Insufficient random bytes: need at least ${step} more, have ${randomBytes.length - randomOffset}`,\n        )\n      }\n      bytes = randomBytes.subarray(randomOffset, randomOffset + step)\n      randomOffset += step\n    } else {\n      bytes = globalThis.crypto.getRandomValues(new Uint8Array(step))\n    }\n\n    for (let i = 0; i < bytes.length && id.length < size; i++) {\n      const index = bytes[i] & mask\n      if (index < alphabetLen) {\n        id += alphabet[index]\n      }\n      // Otherwise reject and continue (no modulo bias)\n    }\n  }\n\n  return id\n}\n\n/**\n * Validate a nanoid string against the default URL-safe alphabet.\n * Note: Does not validate IDs generated with custom alphabets.\n */\nfunction isValid(id: unknown): id is string {\n  return typeof id === 'string' && id.length > 0 && NANOID_REGEX.test(id)\n}\n\n/**\n * Generate a URL-friendly unique string ID.\n *\n * Nanoid is a tiny, secure, URL-friendly unique string ID generator.\n * It uses a URL-safe alphabet (A-Za-z0-9_-) and generates 21-character\n * IDs by default with 126 bits of entropy.\n *\n * Unlike UUID v7 or ULID, nanoid is NOT time-ordered. Use it for:\n * - URL shorteners\n * - Session tokens\n * - Invite codes\n * - Any case where you need short, random IDs\n *\n * @example Basic usage\n * ```ts\n * import { nanoid } from 'uniku/nanoid'\n *\n * const id = nanoid()\n * // => \"V1StGXR8_Z5jdHi6B-myT\"\n * ```\n *\n * @example Custom size\n * ```ts\n * const shortId = nanoid(10)\n * // => \"IRFa-VaY2b\"\n * ```\n *\n * @example Custom alphabet (hex)\n * ```ts\n * const hexId = nanoid({ alphabet: '0123456789abcdef', size: 12 })\n * // => \"4f90d13a42bc\"\n * ```\n *\n * @example Validation\n * ```ts\n * const maybeId: unknown = getUserInput()\n * if (nanoid.isValid(maybeId)) {\n *   // TypeScript knows maybeId is string\n *   console.log(maybeId.length)\n * }\n * ```\n *\n * @throws {InvalidInputError} Size must be between 0 and 2048\n * @throws {InvalidInputError} Alphabet must contain 2-256 unique printable ASCII characters\n * @throws {InvalidInputError} Insufficient random bytes for requested size\n */\nexport const nanoid: Nanoid = Object.assign(nanoidFn, {\n  isValid,\n})\n\nexport { InvalidInputError, UniqueIdError } from '../errors'\n"],"mappings":"qEAGA,MAAa,EAAe,mEAGtB,EAAW,KACX,EAAe,mBAIrB,IAAIA,EACA,EAAa,EAEjB,SAAS,EAAS,EAAqB,CACrC,IAAM,EAAO,EAAQ,IACjB,CAAC,GAAQ,EAAK,OAAS,GACzB,EAAO,IAAI,WAAW,EAAK,CAC3B,OAAO,gBAAgB,EAAK,CAC5B,EAAa,GACJ,EAAa,EAAQ,EAAK,SACnC,OAAO,gBAAgB,EAAK,CAC5B,EAAa,GAEf,GAAc,EAsChB,SAAS,EAAiB,EAAwB,CAChD,GAAI,EAAS,OAAS,EACpB,MAAM,IAAI,EAAkB,4BAA6B,8CAA8C,CAEzG,GAAI,EAAS,OAAS,IACpB,MAAM,IAAI,EAAkB,2BAA4B,0CAA0C,CAEpG,IAAM,EAAO,IAAI,IACjB,IAAK,IAAM,KAAQ,EAAU,CAC3B,IAAM,EAAO,EAAK,WAAW,EAAE,CAC/B,GAAI,EAAO,IAAM,EAAO,IACtB,MAAM,IAAI,EACR,+BACA,iEACD,CAEH,GAAI,EAAK,IAAI,EAAK,CAChB,MAAM,IAAI,EAAkB,4BAA6B,qCAAqC,EAAK,GAAG,CAExG,EAAK,IAAI,EAAK,EAOlB,SAAS,EAAa,EAAoB,CACxC,GAAI,CAAC,OAAO,UAAU,EAAK,EAAI,EAAO,EACpC,MAAM,IAAI,EAAkB,sBAAuB,sCAAsC,CAE3F,GAAI,EAAO,EACT,MAAM,IAAI,EAAkB,wBAAyB,wBAAwB,IAAW,CAQ5F,SAAS,EAAS,EAAgD,CAGhE,GAAI,IAAkB,IAAA,GAAW,CAC/B,EAAS,GAAa,CACtB,IAAIC,EAAK,GACT,IAAK,IAAI,EAAI,EAAa,GAAc,EAAI,EAAY,IACtD,GAAM,EAAa,EAAM,GAAK,IAEhC,OAAOA,EAGT,IAAI,EAAO,GACP,EAAW,EACXC,EAeJ,GAbI,OAAO,GAAkB,SAC3B,EAAO,GAEP,EAAO,EAAc,MAAQ,GAC7B,EAAW,EAAc,UAAY,EACrC,EAAc,EAAc,OACxB,EAAc,WAAa,IAAA,IAC7B,EAAiB,EAAS,EAI9B,EAAa,EAAK,CAEd,IAAS,EAAG,MAAO,GAEvB,IAAM,EAAc,EAAS,OAI7B,GAAA,EAAK,EAAe,EAAc,GAAW,CAC3C,IAAMC,EAAO,EAAc,EAC3B,GAAI,GAAe,EAAY,OAAS,EACtC,MAAM,IAAI,EACR,mCACA,mCAAmC,EAAK,SAAS,EAAY,SAC9D,CAEH,IAAM,EAAQ,GAAa,SAAS,EAAG,EAAK,EAAI,WAAW,OAAO,gBAAgB,IAAI,WAAW,EAAK,CAAC,CACnGF,EAAK,GACT,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,IACxB,GAAM,EAAS,EAAM,GAAKE,GAE5B,OAAOF,EAKT,IAAM,GAAQ,GAAM,GAAK,KAAK,MAAO,EAAc,EAAK,EAAE,EAAK,EAEzD,EAAO,KAAK,KAAM,IAAM,EAAO,EAAQ,EAAY,CAErD,EAAK,GACL,EAAe,EAEnB,KAAO,EAAG,OAAS,GAAM,CACvB,IAAIG,EACJ,GAAI,EAAa,CACf,GAAI,EAAY,OAAS,EAAe,EACtC,MAAM,IAAI,EACR,mCACA,4CAA4C,EAAK,cAAc,EAAY,OAAS,IACrF,CAEH,EAAQ,EAAY,SAAS,EAAc,EAAe,EAAK,CAC/D,GAAgB,OAEhB,EAAQ,WAAW,OAAO,gBAAgB,IAAI,WAAW,EAAK,CAAC,CAGjE,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,QAAU,EAAG,OAAS,EAAM,IAAK,CACzD,IAAM,EAAQ,EAAM,GAAK,EACrB,EAAQ,IACV,GAAM,EAAS,KAMrB,OAAO,EAOT,SAAS,EAAQ,EAA2B,CAC1C,OAAO,OAAO,GAAO,UAAY,EAAG,OAAS,GAAK,EAAa,KAAK,EAAG,CAiDzE,MAAaC,EAAiB,OAAO,OAAO,EAAU,CACpD,UACD,CAAC"}