| function e(e){for(let t=e.length-1;t>=0;--t){if(e[t]<255)return e[t]+=1,!0;e[t]=0}return!1}function t(e,t,n){e[t]=n/1099511627776&255,e[t+1]=n/4294967296&255,e[t+2]=n/16777216&255,e[t+3]=n/65536&255,e[t+4]=n/256&255,e[t+5]=n&255}function n(e,t,n){e[t]=n>>>24&255,e[t+1]=n>>>16&255,e[t+2]=n>>>8&255,e[t+3]=n&255}export{n,t as r,e as t}; | ||
| //# sourceMappingURL=bytes-DzcOKIx1.mjs.map |
| {"version":3,"file":"bytes-DzcOKIx1.mjs","names":[],"sources":["../src/common/bytes.ts"],"sourcesContent":["/**\n * Common byte manipulation utilities shared across ID generators.\n */\n\n/**\n * Increment a byte array by 1 in-place, propagating carry from LSB to MSB.\n * Mutates the input array directly - no allocation.\n *\n * Used by ULID and KSUID for monotonic ordering within the same time unit.\n *\n * @returns true if increment succeeded, false if all bytes overflowed to 0\n */\nexport function incrementBytesInPlace(bytes: Uint8Array): boolean {\n for (let i = bytes.length - 1; i >= 0; i -= 1) {\n if (bytes[i] < 255) {\n bytes[i] += 1\n return true\n }\n bytes[i] = 0\n }\n\n // All bytes overflowed to 0 - astronomically unlikely (1 in 2^80 for ULID, 1 in 2^128 for KSUID)\n return false\n}\n\n/**\n * Write a 48-bit timestamp as big-endian bytes.\n * Used by UUID v7 and ULID for millisecond-precision timestamps.\n *\n * @param buf - Target buffer\n * @param offset - Starting byte offset\n * @param msecs - Milliseconds since Unix epoch (must fit in 48 bits)\n */\nexport function writeTimestamp48(buf: Uint8Array, offset: number, msecs: number): void {\n buf[offset] = (msecs / 0x10000000000) & 0xff\n buf[offset + 1] = (msecs / 0x100000000) & 0xff\n buf[offset + 2] = (msecs / 0x1000000) & 0xff\n buf[offset + 3] = (msecs / 0x10000) & 0xff\n buf[offset + 4] = (msecs / 0x100) & 0xff\n buf[offset + 5] = msecs & 0xff\n}\n\n/**\n * Write a 32-bit timestamp as big-endian bytes.\n * Used by KSUID for second-precision timestamps.\n *\n * `writeTimestamp32(buf, offset, timestamp)` is equivalent to `new DataView(buf.buffer, offset, 4).setUint32(offset, timestamp, false)`,\n * but it's faster because it doesn't require creating a DataView object.\n *\n * @param buf - Target buffer\n * @param offset - Starting byte offset\n * @param secs - Seconds (must fit in 32 bits)\n */\nexport function writeTimestamp32(buf: Uint8Array, offset: number, secs: number): void {\n buf[offset] = (secs >>> 24) & 0xff\n buf[offset + 1] = (secs >>> 16) & 0xff\n buf[offset + 2] = (secs >>> 8) & 0xff\n buf[offset + 3] = secs & 0xff\n}\n"],"mappings":"AAYA,SAAgB,EAAsB,EAA4B,CAChE,IAAK,IAAI,EAAI,EAAM,OAAS,EAAG,GAAK,EAAG,IAAQ,CAC7C,GAAI,EAAM,GAAK,IAEb,MADA,GAAM,IAAM,EACL,GAET,EAAM,GAAK,EAIb,MAAO,GAWT,SAAgB,EAAiB,EAAiB,EAAgB,EAAqB,CACrF,EAAI,GAAW,EAAQ,cAAiB,IACxC,EAAI,EAAS,GAAM,EAAQ,WAAe,IAC1C,EAAI,EAAS,GAAM,EAAQ,SAAa,IACxC,EAAI,EAAS,GAAM,EAAQ,MAAW,IACtC,EAAI,EAAS,GAAM,EAAQ,IAAS,IACpC,EAAI,EAAS,GAAK,EAAQ,IAc5B,SAAgB,EAAiB,EAAiB,EAAgB,EAAoB,CACpF,EAAI,GAAW,IAAS,GAAM,IAC9B,EAAI,EAAS,GAAM,IAAS,GAAM,IAClC,EAAI,EAAS,GAAM,IAAS,EAAK,IACjC,EAAI,EAAS,GAAK,EAAO"} |
| const e=globalThis.crypto.getRandomValues.bind(globalThis.crypto),t=new Uint8Array(256);let n=256;function r(){e(t),n=0}function i(){n>252&&r();let e=t[n]*16777216+t[n+1]*65536+t[n+2]*256+t[n+3]>>>0;return n+=4,e}function a(){n>240&&r();let e=n;return n+=16,t.subarray(e,n)}export{a as n,i as t}; | ||
| //# sourceMappingURL=random-CGMm8owG.mjs.map |
| {"version":3,"file":"random-CGMm8owG.mjs","names":[],"sources":["../src/common/random.ts"],"sourcesContent":["const randomFill = /*@__PURE__*/ globalThis.crypto.getRandomValues.bind(globalThis.crypto)\n\n/**\n * Simple random byte pool for ID generation.\n *\n * Module-level state is per JavaScript isolate, so SharedArrayBuffer and Atomics\n * only add overhead here. Returned views are consumed synchronously by callers.\n */\n\nconst POOL_SIZE = 256\nconst pool = new Uint8Array(POOL_SIZE)\nlet poolOffset = POOL_SIZE\n\nfunction refillPool(): void {\n randomFill(pool)\n poolOffset = 0\n}\n\n/**\n * Return a view of `count` random bytes from the pool.\n */\nexport function randomBytes(count: number): Uint8Array {\n if (count > POOL_SIZE) {\n return randomFill(new Uint8Array(count))\n }\n\n if (poolOffset + count > POOL_SIZE) {\n refillPool()\n }\n\n const start = poolOffset\n poolOffset += count\n return pool.subarray(start, poolOffset)\n}\n\n/**\n * Generate a random unsigned 32-bit integer from the shared pool.\n */\nexport function randomUint32(): number {\n if (poolOffset > POOL_SIZE - 4) {\n refillPool()\n }\n\n const value =\n (pool[poolOffset] * 0x1000000 +\n pool[poolOffset + 1] * 0x10000 +\n pool[poolOffset + 2] * 0x100 +\n pool[poolOffset + 3]) >>>\n 0\n poolOffset += 4\n return value\n}\n\n/**\n * Generate 16 bytes of cryptographically strong random data.\n * Uses a pre-filled pool to minimize crypto API calls.\n */\nexport function rng(): Uint8Array {\n if (poolOffset > POOL_SIZE - 16) {\n refillPool()\n }\n\n const start = poolOffset\n poolOffset += 16\n return pool.subarray(start, poolOffset)\n}\n"],"mappings":"AAAA,MAAM,EAA2B,WAAW,OAAO,gBAAgB,KAAK,WAAW,OAAO,CAUpF,EAAO,IAAI,WAAW,IAAU,CACtC,IAAI,EAAa,IAEjB,SAAS,GAAmB,CAC1B,EAAW,EAAK,CAChB,EAAa,EAuBf,SAAgB,GAAuB,CACjC,EAAa,KACf,GAAY,CAGd,IAAM,EACH,EAAK,GAAc,SAClB,EAAK,EAAa,GAAK,MACvB,EAAK,EAAa,GAAK,IACvB,EAAK,EAAa,KACpB,EAEF,MADA,IAAc,EACP,EAOT,SAAgB,GAAkB,CAC5B,EAAa,KACf,GAAY,CAGd,IAAM,EAAQ,EAEd,MADA,IAAc,GACP,EAAK,SAAS,EAAO,EAAW"} |
Sorry, the diff of this file is not supported yet
| import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs"; | ||
| import { UuidV7Options } from "../uuid/v7.mjs"; | ||
| //#region src/typeid/typeid.d.ts | ||
| type TypeidOptions = UuidV7Options; | ||
| type Typeid = { | ||
| (prefix: string, options?: TypeidOptions): string; | ||
| toBytes(id: string): Uint8Array; | ||
| fromBytes(prefix: string, bytes: Uint8Array): string; | ||
| toUuid(id: string): string; | ||
| fromUuid(prefix: string, uuid: string): string; | ||
| timestamp(id: string): number; | ||
| prefix(id: string): string; | ||
| suffix(id: string): string; | ||
| isValid(id: unknown): id is string; | ||
| }; | ||
| /** | ||
| * Generate a TypeID string backed by UUID v7. | ||
| * | ||
| * TypeID combines a lowercase snake_case type prefix with a 26-character | ||
| * modified base32 encoding of a UUID v7, producing sortable domain identifiers | ||
| * such as `user_01h2xcejqtf2nbrexx3vqjhp41`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { typeid } from 'uniku/typeid' | ||
| * | ||
| * const id = typeid('user') | ||
| * // => "user_01h2xcejqtf2nbrexx3vqjhp41" | ||
| * | ||
| * const uuid = typeid.toUuid(id) | ||
| * const restored = typeid.fromUuid('user', uuid) | ||
| * ``` | ||
| */ | ||
| declare const typeid: Typeid; | ||
| //#endregion | ||
| export { BufferError, InvalidInputError, ParseError, Typeid, TypeidOptions, UniqueIdError, typeid }; | ||
| //# sourceMappingURL=typeid.d.mts.map |
| {"version":3,"file":"typeid.d.mts","names":["typeid: Typeid"],"sources":["../../src/typeid/typeid.ts"],"sourcesContent":[],"mappings":";;;;KAIY,aAAA,GAAgB;KAEhB,MAAA;6BACiB;EAH7B,OAAY,CAAA,EAAA,EAAA,MAAA,CAAA,EAIW,UAJK;EAE5B,SAAY,CAAA,MAAA,EAAA,MAAA,EAAA,KAAA,EAGuB,UAHvB,CAAA,EAAA,MAAA;EACiB,MAAA,CAAA,EAAA,EAAA,MAAA,CAAA,EAAA,MAAA;EACN,QAAA,CAAA,MAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;EACY,SAAA,CAAA,EAAA,EAAA,MAAA,CAAA,EAAA,MAAA;EAAA,MAAA,CAAA,EAAA,EAAA,MAAA,CAAA,EAAA,MAAA;EAsQnC,MAAaA,CAAAA,EAAAA,EAAAA,MAAQ,CAAA,EAAA,MAAA;;;;;;;;;;;;;;;;;;;;;cAARA,QAAQ"} |
| import{BufferError as e,InvalidInputError as t,ParseError as n,UniqueIdError as r}from"../errors.mjs";import{uuidv7 as i}from"../uuid/v7.mjs";const a=`0123456789abcdefghjkmnpqrstvwxyz`,o=Array.from({length:128},()=>-1);for(let e=0;e<32;e+=1)o[a.charCodeAt(e)]=e;function s(e){if(e.length!==0){if(e.length>63)throw new t(`TYPEID_PREFIX_TOO_LONG`,`TypeID prefix must be at most 63 characters`);for(let n=0;n<e.length;n+=1){let r=e.charCodeAt(n),i=r>=97&&r<=122;if(!i&&r!==95)throw new t(`TYPEID_PREFIX_INVALID_CHARACTER`,`TypeID prefix must contain only lowercase ASCII letters and underscores`);if((n===0||n===e.length-1)&&!i)throw new t(`TYPEID_PREFIX_INVALID_BOUNDARY`,`TypeID prefix must start and end with a-z`)}}}function c(e,t){let r=e.charCodeAt(t),i=r<o.length?o[r]:-1;if(i===-1)throw new n(`TYPEID_SUFFIX_INVALID_CHARACTER`,`TypeID suffix contains invalid character at position ${t}`);return i}function l(e){if(e.length!==26)throw new n(`TYPEID_SUFFIX_INVALID_LENGTH`,`TypeID suffix must be 26 characters, got ${e.length}`);if(e[0]>`7`)throw new n(`TYPEID_SUFFIX_OVERFLOW`,`TypeID suffix must encode a 128-bit value`)}function u(e){if(e.length!==16)throw new t(`TYPEID_UUID_BYTES_INVALID_LENGTH`,`UUID bytes must be 16 bytes, got ${e.length}`);return a[(e[0]&224)>>5]+a[e[0]&31]+a[(e[1]&248)>>3]+a[(e[1]&7)<<2|(e[2]&192)>>6]+a[(e[2]&62)>>1]+a[(e[2]&1)<<4|(e[3]&240)>>4]+a[(e[3]&15)<<1|(e[4]&128)>>7]+a[(e[4]&124)>>2]+a[(e[4]&3)<<3|(e[5]&224)>>5]+a[e[5]&31]+a[(e[6]&248)>>3]+a[(e[6]&7)<<2|(e[7]&192)>>6]+a[(e[7]&62)>>1]+a[(e[7]&1)<<4|(e[8]&240)>>4]+a[(e[8]&15)<<1|(e[9]&128)>>7]+a[(e[9]&124)>>2]+a[(e[9]&3)<<3|(e[10]&224)>>5]+a[e[10]&31]+a[(e[11]&248)>>3]+a[(e[11]&7)<<2|(e[12]&192)>>6]+a[(e[12]&62)>>1]+a[(e[12]&1)<<4|(e[13]&240)>>4]+a[(e[13]&15)<<1|(e[14]&128)>>7]+a[(e[14]&124)>>2]+a[(e[14]&3)<<3|(e[15]&224)>>5]+a[e[15]&31]}function d(e){l(e);let t=Array(26);for(let n=0;n<26;n+=1)t[n]=c(e,n);let n=new Uint8Array(16);return n[0]=t[0]<<5|t[1],n[1]=t[2]<<3|t[3]>>2,n[2]=(t[3]&3)<<6|t[4]<<1|t[5]>>4,n[3]=(t[5]&15)<<4|t[6]>>1,n[4]=(t[6]&1)<<7|t[7]<<2|t[8]>>3,n[5]=(t[8]&7)<<5|t[9],n[6]=t[10]<<3|t[11]>>2,n[7]=(t[11]&3)<<6|t[12]<<1|t[13]>>4,n[8]=(t[13]&15)<<4|t[14]>>1,n[9]=(t[14]&1)<<7|t[15]<<2|t[16]>>3,n[10]=(t[16]&7)<<5|t[17],n[11]=t[18]<<3|t[19]>>2,n[12]=(t[19]&3)<<6|t[20]<<1|t[21]>>4,n[13]=(t[21]&15)<<4|t[22]>>1,n[14]=(t[22]&1)<<7|t[23]<<2|t[24]>>3,n[15]=(t[24]&7)<<5|t[25],n}function f(e){if(e.length!==16)throw new t(`TYPEID_UUID_BYTES_INVALID_LENGTH`,`UUID bytes must be 16 bytes, got ${e.length}`);if(e[6]>>4!=7||(e[8]&192)!=128)throw new t(`TYPEID_UUID_NOT_V7`,`TypeID UUID bytes must encode a UUID v7 value`)}function p(e){let t=d(e);return f(t),t}function m(e){if(!i.isValid(e))throw new t(`TYPEID_UUID_NOT_V7`,`TypeID can only wrap UUID v7 values`);return i.toBytes(e)}function h(e){let t=e.lastIndexOf(`_`);if(t===0)throw new n(`TYPEID_INVALID_FORMAT`,`TypeID must not start with "_"`);let r=t===-1?``:e.slice(0,t),i=t===-1?e:e.slice(t+1);return s(r),{prefix:r,suffix:i,bytes:p(i)}}function g(e,t){return e===``?t:`${e}_${t}`}function _(e,t){return s(e),f(t),g(e,u(t))}function v(e){let t=0;for(let n=0;n<6;n+=1)t=t*256+e[n];return t}function y(e,t){return _(e,i(t,new Uint8Array(16)))}function b(e){return h(e).bytes}function x(e,t){return _(e,t)}function S(e){return i.fromBytes(b(e))}function C(e,t){return _(e,m(t))}function w(e){return v(h(e).bytes)}function T(e){return h(e).prefix}function E(e){return h(e).suffix}function D(e){if(typeof e!=`string`)return!1;try{h(e)}catch{return!1}return!0}const O=Object.assign(y,{toBytes:b,fromBytes:x,toUuid:S,fromUuid:C,timestamp:w,prefix:T,suffix:E,isValid:D});export{e as BufferError,t as InvalidInputError,n as ParseError,r as UniqueIdError,O as typeid}; | ||
| //# sourceMappingURL=typeid.mjs.map |
| {"version":3,"file":"typeid.mjs","names":["BASE32_DECODE: number[]","prefix","suffix","typeid: Typeid"],"sources":["../../src/typeid/typeid.ts"],"sourcesContent":["import { InvalidInputError, ParseError } from '../errors'\nimport type { UuidV7Options } from '../uuid/v7'\nimport { uuidv7 } from '../uuid/v7'\n\nexport type TypeidOptions = UuidV7Options\n\nexport type Typeid = {\n (prefix: string, options?: TypeidOptions): string\n toBytes(id: string): Uint8Array\n fromBytes(prefix: string, bytes: Uint8Array): string\n toUuid(id: string): string\n fromUuid(prefix: string, uuid: string): string\n timestamp(id: string): number\n prefix(id: string): string\n suffix(id: string): string\n isValid(id: unknown): id is string\n}\n\nconst TYPEID_SUFFIX_LENGTH = 26\nconst TYPEID_UUID_BYTE_LENGTH = 16\nconst TYPEID_ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz'\n\nconst BASE32_DECODE: number[] = Array.from({ length: 128 }, () => -1)\nfor (let i = 0; i < TYPEID_ALPHABET.length; i += 1) {\n BASE32_DECODE[TYPEID_ALPHABET.charCodeAt(i)] = i\n}\n\ntype ParsedTypeid = {\n prefix: string\n suffix: string\n bytes: Uint8Array\n}\n\nfunction assertValidPrefix(prefix: string): void {\n if (prefix.length === 0) {\n return\n }\n\n if (prefix.length > 63) {\n throw new InvalidInputError('TYPEID_PREFIX_TOO_LONG', 'TypeID prefix must be at most 63 characters')\n }\n\n for (let i = 0; i < prefix.length; i += 1) {\n const code = prefix.charCodeAt(i)\n const isLowercaseLetter = code >= 97 && code <= 122\n const isUnderscore = code === 95\n\n if (!isLowercaseLetter && !isUnderscore) {\n throw new InvalidInputError(\n 'TYPEID_PREFIX_INVALID_CHARACTER',\n 'TypeID prefix must contain only lowercase ASCII letters and underscores',\n )\n }\n\n if ((i === 0 || i === prefix.length - 1) && !isLowercaseLetter) {\n throw new InvalidInputError('TYPEID_PREFIX_INVALID_BOUNDARY', 'TypeID prefix must start and end with a-z')\n }\n }\n}\n\nfunction decodeSuffixValue(suffix: string, index: number): number {\n const code = suffix.charCodeAt(index)\n const value = code < BASE32_DECODE.length ? BASE32_DECODE[code] : -1\n\n if (value === -1) {\n throw new ParseError(\n 'TYPEID_SUFFIX_INVALID_CHARACTER',\n `TypeID suffix contains invalid character at position ${index}`,\n )\n }\n\n return value\n}\n\nfunction assertValidSuffixShape(suffix: string): void {\n if (suffix.length !== TYPEID_SUFFIX_LENGTH) {\n throw new ParseError('TYPEID_SUFFIX_INVALID_LENGTH', `TypeID suffix must be 26 characters, got ${suffix.length}`)\n }\n\n if (suffix[0] > '7') {\n throw new ParseError('TYPEID_SUFFIX_OVERFLOW', 'TypeID suffix must encode a 128-bit value')\n }\n}\n\nfunction encodeBytesToSuffix(bytes: Uint8Array): string {\n if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('TYPEID_UUID_BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`)\n }\n\n return (\n TYPEID_ALPHABET[(bytes[0] & 0xe0) >> 5] +\n TYPEID_ALPHABET[bytes[0] & 0x1f] +\n TYPEID_ALPHABET[(bytes[1] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[1] & 0x07) << 2) | ((bytes[2] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[2] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[2] & 0x01) << 4) | ((bytes[3] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[3] & 0x0f) << 1) | ((bytes[4] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[4] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[4] & 0x03) << 3) | ((bytes[5] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[5] & 0x1f] +\n TYPEID_ALPHABET[(bytes[6] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[6] & 0x07) << 2) | ((bytes[7] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[7] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[7] & 0x01) << 4) | ((bytes[8] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[8] & 0x0f) << 1) | ((bytes[9] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[9] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[9] & 0x03) << 3) | ((bytes[10] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[10] & 0x1f] +\n TYPEID_ALPHABET[(bytes[11] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[11] & 0x07) << 2) | ((bytes[12] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[12] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[12] & 0x01) << 4) | ((bytes[13] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[13] & 0x0f) << 1) | ((bytes[14] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[14] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[14] & 0x03) << 3) | ((bytes[15] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[15] & 0x1f]\n )\n}\n\nfunction decodeSuffixToBytes(suffix: string): Uint8Array {\n assertValidSuffixShape(suffix)\n\n const values = new Array<number>(TYPEID_SUFFIX_LENGTH)\n for (let i = 0; i < TYPEID_SUFFIX_LENGTH; i += 1) {\n values[i] = decodeSuffixValue(suffix, i)\n }\n\n const bytes = new Uint8Array(TYPEID_UUID_BYTE_LENGTH)\n bytes[0] = (values[0] << 5) | values[1]\n bytes[1] = (values[2] << 3) | (values[3] >> 2)\n bytes[2] = ((values[3] & 0x03) << 6) | (values[4] << 1) | (values[5] >> 4)\n bytes[3] = ((values[5] & 0x0f) << 4) | (values[6] >> 1)\n bytes[4] = ((values[6] & 0x01) << 7) | (values[7] << 2) | (values[8] >> 3)\n bytes[5] = ((values[8] & 0x07) << 5) | values[9]\n bytes[6] = (values[10] << 3) | (values[11] >> 2)\n bytes[7] = ((values[11] & 0x03) << 6) | (values[12] << 1) | (values[13] >> 4)\n bytes[8] = ((values[13] & 0x0f) << 4) | (values[14] >> 1)\n bytes[9] = ((values[14] & 0x01) << 7) | (values[15] << 2) | (values[16] >> 3)\n bytes[10] = ((values[16] & 0x07) << 5) | values[17]\n bytes[11] = (values[18] << 3) | (values[19] >> 2)\n bytes[12] = ((values[19] & 0x03) << 6) | (values[20] << 1) | (values[21] >> 4)\n bytes[13] = ((values[21] & 0x0f) << 4) | (values[22] >> 1)\n bytes[14] = ((values[22] & 0x01) << 7) | (values[23] << 2) | (values[24] >> 3)\n bytes[15] = ((values[24] & 0x07) << 5) | values[25]\n\n return bytes\n}\n\nfunction assertUuidV7Bytes(bytes: Uint8Array): void {\n if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('TYPEID_UUID_BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`)\n }\n\n if (bytes[6] >> 4 !== 7 || (bytes[8] & 0xc0) !== 0x80) {\n throw new InvalidInputError('TYPEID_UUID_NOT_V7', 'TypeID UUID bytes must encode a UUID v7 value')\n }\n}\n\nfunction uuidV7BytesFromSuffix(suffix: string): Uint8Array {\n const bytes = decodeSuffixToBytes(suffix)\n assertUuidV7Bytes(bytes)\n return bytes\n}\n\nfunction uuidV7BytesFromUuid(uuid: string): Uint8Array {\n if (!uuidv7.isValid(uuid)) {\n throw new InvalidInputError('TYPEID_UUID_NOT_V7', 'TypeID can only wrap UUID v7 values')\n }\n\n return uuidv7.toBytes(uuid)\n}\n\nfunction parseTypeid(id: string): ParsedTypeid {\n const separatorIndex = id.lastIndexOf('_')\n\n if (separatorIndex === 0) {\n throw new ParseError('TYPEID_INVALID_FORMAT', 'TypeID must not start with \"_\"')\n }\n\n const prefix = separatorIndex === -1 ? '' : id.slice(0, separatorIndex)\n const suffix = separatorIndex === -1 ? id : id.slice(separatorIndex + 1)\n\n assertValidPrefix(prefix)\n const bytes = uuidV7BytesFromSuffix(suffix)\n\n return { prefix, suffix, bytes }\n}\n\nfunction joinPrefixAndSuffix(prefix: string, suffix: string): string {\n return prefix === '' ? suffix : `${prefix}_${suffix}`\n}\n\nfunction formatTypeidFromUuidV7Bytes(prefix: string, bytes: Uint8Array): string {\n assertValidPrefix(prefix)\n assertUuidV7Bytes(bytes)\n return joinPrefixAndSuffix(prefix, encodeBytesToSuffix(bytes))\n}\n\nfunction timestampFromUuidV7Bytes(bytes: Uint8Array): number {\n let msecs = 0\n for (let i = 0; i < 6; i += 1) {\n msecs = msecs * 256 + bytes[i]\n }\n return msecs\n}\n\nfunction typeidFn(prefix: string, options?: TypeidOptions): string {\n const bytes = uuidv7(options, new Uint8Array(TYPEID_UUID_BYTE_LENGTH))\n return formatTypeidFromUuidV7Bytes(prefix, bytes)\n}\n\nfunction typeidToBytes(id: string): Uint8Array {\n return parseTypeid(id).bytes\n}\n\nfunction typeidFromBytes(prefix: string, bytes: Uint8Array): string {\n return formatTypeidFromUuidV7Bytes(prefix, bytes)\n}\n\nfunction typeidToUuid(id: string): string {\n return uuidv7.fromBytes(typeidToBytes(id))\n}\n\nfunction typeidFromUuid(prefix: string, uuid: string): string {\n return formatTypeidFromUuidV7Bytes(prefix, uuidV7BytesFromUuid(uuid))\n}\n\nfunction timestamp(id: string): number {\n return timestampFromUuidV7Bytes(parseTypeid(id).bytes)\n}\n\nfunction prefix(id: string): string {\n return parseTypeid(id).prefix\n}\n\nfunction suffix(id: string): string {\n return parseTypeid(id).suffix\n}\n\nfunction isValid(id: unknown): id is string {\n if (typeof id !== 'string') {\n return false\n }\n\n try {\n parseTypeid(id)\n } catch {\n return false\n }\n\n return true\n}\n\n/**\n * Generate a TypeID string backed by UUID v7.\n *\n * TypeID combines a lowercase snake_case type prefix with a 26-character\n * modified base32 encoding of a UUID v7, producing sortable domain identifiers\n * such as `user_01h2xcejqtf2nbrexx3vqjhp41`.\n *\n * @example\n * ```ts\n * import { typeid } from 'uniku/typeid'\n *\n * const id = typeid('user')\n * // => \"user_01h2xcejqtf2nbrexx3vqjhp41\"\n *\n * const uuid = typeid.toUuid(id)\n * const restored = typeid.fromUuid('user', uuid)\n * ```\n */\nexport const typeid: Typeid = Object.assign(typeidFn, {\n toBytes: typeidToBytes,\n fromBytes: typeidFromBytes,\n toUuid: typeidToUuid,\n fromUuid: typeidFromUuid,\n timestamp,\n prefix,\n suffix,\n isValid,\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"8IAkBA,MAEM,EAAkB,mCAElBA,EAA0B,MAAM,KAAK,CAAE,OAAQ,IAAK,KAAQ,GAAG,CACrE,IAAK,IAAI,EAAI,EAAG,EAAI,GAAwB,GAAK,EAC/C,EAAc,EAAgB,WAAW,EAAE,EAAI,EASjD,SAAS,EAAkB,EAAsB,CAC3CC,KAAO,SAAW,EAItB,IAAIA,EAAO,OAAS,GAClB,MAAM,IAAI,EAAkB,yBAA0B,8CAA8C,CAGtG,IAAK,IAAI,EAAI,EAAG,EAAIA,EAAO,OAAQ,GAAK,EAAG,CACzC,IAAM,EAAOA,EAAO,WAAW,EAAE,CAC3B,EAAoB,GAAQ,IAAM,GAAQ,IAGhD,GAAI,CAAC,GAFgB,IAAS,GAG5B,MAAM,IAAI,EACR,kCACA,0EACD,CAGH,IAAK,IAAM,GAAK,IAAMA,EAAO,OAAS,IAAM,CAAC,EAC3C,MAAM,IAAI,EAAkB,iCAAkC,4CAA4C,GAKhH,SAAS,EAAkB,EAAgB,EAAuB,CAChE,IAAM,EAAOC,EAAO,WAAW,EAAM,CAC/B,EAAQ,EAAO,EAAc,OAAS,EAAc,GAAQ,GAElE,GAAI,IAAU,GACZ,MAAM,IAAI,EACR,kCACA,wDAAwD,IACzD,CAGH,OAAO,EAGT,SAAS,EAAuB,EAAsB,CACpD,GAAIA,EAAO,SAAW,GACpB,MAAM,IAAI,EAAW,+BAAgC,4CAA4CA,EAAO,SAAS,CAGnH,GAAIA,EAAO,GAAK,IACd,MAAM,IAAI,EAAW,yBAA0B,4CAA4C,CAI/F,SAAS,EAAoB,EAA2B,CACtD,GAAI,EAAM,SAAW,GACnB,MAAM,IAAI,EAAkB,mCAAoC,oCAAoC,EAAM,SAAS,CAGrH,OACE,GAAiB,EAAM,GAAK,MAAS,GACrC,EAAgB,EAAM,GAAK,IAC3B,GAAiB,EAAM,GAAK,MAAS,GACrC,GAAkB,EAAM,GAAK,IAAS,GAAO,EAAM,GAAK,MAAS,GACjE,GAAiB,EAAM,GAAK,KAAS,GACrC,GAAkB,EAAM,GAAK,IAAS,GAAO,EAAM,GAAK,MAAS,GACjE,GAAkB,EAAM,GAAK,KAAS,GAAO,EAAM,GAAK,MAAS,GACjE,GAAiB,EAAM,GAAK,MAAS,GACrC,GAAkB,EAAM,GAAK,IAAS,GAAO,EAAM,GAAK,MAAS,GACjE,EAAgB,EAAM,GAAK,IAC3B,GAAiB,EAAM,GAAK,MAAS,GACrC,GAAkB,EAAM,GAAK,IAAS,GAAO,EAAM,GAAK,MAAS,GACjE,GAAiB,EAAM,GAAK,KAAS,GACrC,GAAkB,EAAM,GAAK,IAAS,GAAO,EAAM,GAAK,MAAS,GACjE,GAAkB,EAAM,GAAK,KAAS,GAAO,EAAM,GAAK,MAAS,GACjE,GAAiB,EAAM,GAAK,MAAS,GACrC,GAAkB,EAAM,GAAK,IAAS,GAAO,EAAM,IAAM,MAAS,GAClE,EAAgB,EAAM,IAAM,IAC5B,GAAiB,EAAM,IAAM,MAAS,GACtC,GAAkB,EAAM,IAAM,IAAS,GAAO,EAAM,IAAM,MAAS,GACnE,GAAiB,EAAM,IAAM,KAAS,GACtC,GAAkB,EAAM,IAAM,IAAS,GAAO,EAAM,IAAM,MAAS,GACnE,GAAkB,EAAM,IAAM,KAAS,GAAO,EAAM,IAAM,MAAS,GACnE,GAAiB,EAAM,IAAM,MAAS,GACtC,GAAkB,EAAM,IAAM,IAAS,GAAO,EAAM,IAAM,MAAS,GACnE,EAAgB,EAAM,IAAM,IAIhC,SAAS,EAAoB,EAA4B,CACvD,EAAuBA,EAAO,CAE9B,IAAM,EAAa,MAAc,GAAqB,CACtD,IAAK,IAAI,EAAI,EAAG,EAAI,GAAsB,GAAK,EAC7C,EAAO,GAAK,EAAkBA,EAAQ,EAAE,CAG1C,IAAM,EAAQ,IAAI,WAAW,GAAwB,CAkBrD,MAjBA,GAAM,GAAM,EAAO,IAAM,EAAK,EAAO,GACrC,EAAM,GAAM,EAAO,IAAM,EAAM,EAAO,IAAM,EAC5C,EAAM,IAAO,EAAO,GAAK,IAAS,EAAM,EAAO,IAAM,EAAM,EAAO,IAAM,EACxE,EAAM,IAAO,EAAO,GAAK,KAAS,EAAM,EAAO,IAAM,EACrD,EAAM,IAAO,EAAO,GAAK,IAAS,EAAM,EAAO,IAAM,EAAM,EAAO,IAAM,EACxE,EAAM,IAAO,EAAO,GAAK,IAAS,EAAK,EAAO,GAC9C,EAAM,GAAM,EAAO,KAAO,EAAM,EAAO,KAAO,EAC9C,EAAM,IAAO,EAAO,IAAM,IAAS,EAAM,EAAO,KAAO,EAAM,EAAO,KAAO,EAC3E,EAAM,IAAO,EAAO,IAAM,KAAS,EAAM,EAAO,KAAO,EACvD,EAAM,IAAO,EAAO,IAAM,IAAS,EAAM,EAAO,KAAO,EAAM,EAAO,KAAO,EAC3E,EAAM,KAAQ,EAAO,IAAM,IAAS,EAAK,EAAO,IAChD,EAAM,IAAO,EAAO,KAAO,EAAM,EAAO,KAAO,EAC/C,EAAM,KAAQ,EAAO,IAAM,IAAS,EAAM,EAAO,KAAO,EAAM,EAAO,KAAO,EAC5E,EAAM,KAAQ,EAAO,IAAM,KAAS,EAAM,EAAO,KAAO,EACxD,EAAM,KAAQ,EAAO,IAAM,IAAS,EAAM,EAAO,KAAO,EAAM,EAAO,KAAO,EAC5E,EAAM,KAAQ,EAAO,IAAM,IAAS,EAAK,EAAO,IAEzC,EAGT,SAAS,EAAkB,EAAyB,CAClD,GAAI,EAAM,SAAW,GACnB,MAAM,IAAI,EAAkB,mCAAoC,oCAAoC,EAAM,SAAS,CAGrH,GAAI,EAAM,IAAM,GAAM,IAAM,EAAM,GAAK,MAAU,IAC/C,MAAM,IAAI,EAAkB,qBAAsB,gDAAgD,CAItG,SAAS,EAAsB,EAA4B,CACzD,IAAM,EAAQ,EAAoBA,EAAO,CAEzC,OADA,EAAkB,EAAM,CACjB,EAGT,SAAS,EAAoB,EAA0B,CACrD,GAAI,CAAC,EAAO,QAAQ,EAAK,CACvB,MAAM,IAAI,EAAkB,qBAAsB,sCAAsC,CAG1F,OAAO,EAAO,QAAQ,EAAK,CAG7B,SAAS,EAAY,EAA0B,CAC7C,IAAM,EAAiB,EAAG,YAAY,IAAI,CAE1C,GAAI,IAAmB,EACrB,MAAM,IAAI,EAAW,wBAAyB,iCAAiC,CAGjF,IAAMD,EAAS,IAAmB,GAAK,GAAK,EAAG,MAAM,EAAG,EAAe,CACjEC,EAAS,IAAmB,GAAK,EAAK,EAAG,MAAM,EAAiB,EAAE,CAKxE,OAHA,EAAkBD,EAAO,CAGlB,CAAE,OAAA,EAAQ,OAAA,EAAQ,MAFX,EAAsBC,EAAO,CAEX,CAGlC,SAAS,EAAoB,EAAgB,EAAwB,CACnE,OAAOD,IAAW,GAAKC,EAAS,GAAGD,EAAO,GAAGC,IAG/C,SAAS,EAA4B,EAAgB,EAA2B,CAG9E,OAFA,EAAkBD,EAAO,CACzB,EAAkB,EAAM,CACjB,EAAoBA,EAAQ,EAAoB,EAAM,CAAC,CAGhE,SAAS,EAAyB,EAA2B,CAC3D,IAAI,EAAQ,EACZ,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,GAAK,EAC1B,EAAQ,EAAQ,IAAM,EAAM,GAE9B,OAAO,EAGT,SAAS,EAAS,EAAgB,EAAiC,CAEjE,OAAO,EAA4BA,EADrB,EAAO,EAAS,IAAI,WAAW,GAAwB,CAAC,CACrB,CAGnD,SAAS,EAAc,EAAwB,CAC7C,OAAO,EAAY,EAAG,CAAC,MAGzB,SAAS,EAAgB,EAAgB,EAA2B,CAClE,OAAO,EAA4BA,EAAQ,EAAM,CAGnD,SAAS,EAAa,EAAoB,CACxC,OAAO,EAAO,UAAU,EAAc,EAAG,CAAC,CAG5C,SAAS,EAAe,EAAgB,EAAsB,CAC5D,OAAO,EAA4BA,EAAQ,EAAoB,EAAK,CAAC,CAGvE,SAAS,EAAU,EAAoB,CACrC,OAAO,EAAyB,EAAY,EAAG,CAAC,MAAM,CAGxD,SAAS,EAAO,EAAoB,CAClC,OAAO,EAAY,EAAG,CAAC,OAGzB,SAAS,EAAO,EAAoB,CAClC,OAAO,EAAY,EAAG,CAAC,OAGzB,SAAS,EAAQ,EAA2B,CAC1C,GAAI,OAAO,GAAO,SAChB,MAAO,GAGT,GAAI,CACF,EAAY,EAAG,MACT,CACN,MAAO,GAGT,MAAO,GAqBT,MAAaE,EAAiB,OAAO,OAAO,EAAU,CACpD,QAAS,EACT,UAAW,EACX,OAAQ,EACR,SAAU,EACV,YACA,SACA,SACA,UACD,CAAC"} |
| import{ParseError as e}from"./errors.mjs";function t(e){return e>=48&&e<=57?e-48:e>=65&&e<=70?e-65+10:e>=97&&e<=102?e-97+10:-1}const n=[0,0,1,1,2,2,3,3,-1,4,4,5,5,-1,6,6,7,7,-1,8,8,9,9,-1,10,10,11,11,12,12,13,13,14,14,15,15],r=[!0,!1,!0,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!0,!1,!0,!1,!0,!1,!0,!1],i=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`));function a(e){return i[e[0]]+i[e[1]]+i[e[2]]+i[e[3]]+`-`+i[e[4]]+i[e[5]]+`-`+i[e[6]]+i[e[7]]+`-`+i[e[8]]+i[e[9]]+`-`+i[e[10]]+i[e[11]]+i[e[12]]+i[e[13]]+i[e[14]]+i[e[15]]}function o(i){if(i.length!==36)throw new e(`UUID_INVALID_LENGTH`,`UUID string must be 36 characters, got ${i.length}`);if(i[8]!==`-`||i[13]!==`-`||i[18]!==`-`||i[23]!==`-`)throw new e(`UUID_INVALID_SEPARATORS`,`UUID string has invalid separators at positions 8, 13, 18, 23. Received: "${i}"`);let a=new Uint8Array(16);for(let o=0;o<36;o+=1){let s=n[o];if(s===-1)continue;let c=t(i.charCodeAt(o));if(c===-1)throw new e(`UUID_INVALID_HEX_CHAR`,`UUID string contains invalid hex character at position ${o}`);r[o]?a[s]=c<<4:a[s]|=c}return a}export{o as n,a as t}; | ||
| //# sourceMappingURL=uuid-Ub6ladEr.mjs.map |
| {"version":3,"file":"uuid-Ub6ladEr.mjs","names":["UUID_CHAR_TO_BYTE: number[]","UUID_CHAR_IS_HIGH: boolean[]","HEX_TABLE: string[]"],"sources":["../src/uuid/common/hex.ts","../src/uuid/common/uuid.ts"],"sourcesContent":["// ASCII code ranges for hex character validation\nconst ASCII_0 = 48 // '0'\nconst ASCII_9 = 57 // '9'\nconst ASCII_A = 65 // 'A'\nconst ASCII_F = 70 // 'F'\nconst ASCII_a = 97 // 'a'\nconst ASCII_f = 102 // 'f'\n\n/**\n * Convert a hex character ASCII code to its numeric value (0-15).\n * Returns -1 for invalid hex characters.\n */\nexport function hexValue(code: number): number {\n if (code >= ASCII_0 && code <= ASCII_9) {\n return code - ASCII_0\n }\n if (code >= ASCII_A && code <= ASCII_F) {\n return code - ASCII_A + 10\n }\n if (code >= ASCII_a && code <= ASCII_f) {\n return code - ASCII_a + 10\n }\n return -1 // Invalid hex character\n}\n","import { ParseError } from '../../errors'\nimport { hexValue } from './hex'\n\nconst UUID_BYTE_LENGTH = 16\nconst UUID_STRING_LENGTH = 36\n\n// Mapping from UUID string position to byte index.\n// -1 indicates a dash position that should be skipped.\n// This avoids intermediate string allocations during parsing.\nconst UUID_CHAR_TO_BYTE: number[] = [\n 0,\n 0,\n 1,\n 1,\n 2,\n 2,\n 3,\n 3, // chars 0-7 → bytes 0-3\n -1, // char 8 is '-'\n 4,\n 4,\n 5,\n 5, // chars 9-12 → bytes 4-5\n -1, // char 13 is '-'\n 6,\n 6,\n 7,\n 7, // chars 14-17 → bytes 6-7\n -1, // char 18 is '-'\n 8,\n 8,\n 9,\n 9, // chars 19-22 → bytes 8-9\n -1, // char 23 is '-'\n 10,\n 10,\n 11,\n 11,\n 12,\n 12,\n 13,\n 13,\n 14,\n 14,\n 15,\n 15, // chars 24-35 → bytes 10-15\n]\n\n// Whether each position is the high nibble (true) or low nibble (false)\nconst UUID_CHAR_IS_HIGH: boolean[] = [\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false, // chars 0-7\n false, // dash (ignored)\n true,\n false,\n true,\n false, // chars 9-12\n false, // dash\n true,\n false,\n true,\n false, // chars 14-17\n false, // dash\n true,\n false,\n true,\n false, // chars 19-22\n false, // dash\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false, // chars 24-35\n]\n\n// Pre-computed lookup table for byte-to-hex conversion (0x00 -> \"00\", 0xff -> \"ff\")\n//\n// Note: this table must remain defined in the same module as `formatUuid`, otherwise the v8 optimizer\n// will cause a performance drop of ~36%.\nconst HEX_TABLE: string[] = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))\n\nexport function formatUuid(bytes: Uint8Array): string {\n // Direct string concatenation - optimized for V8's string builder.\n // This approach avoids loop overhead and intermediate allocations.\n // See: https://github.com/uuidjs/uuid/pull/434\n return (\n HEX_TABLE[bytes[0]] +\n HEX_TABLE[bytes[1]] +\n HEX_TABLE[bytes[2]] +\n HEX_TABLE[bytes[3]] +\n '-' +\n HEX_TABLE[bytes[4]] +\n HEX_TABLE[bytes[5]] +\n '-' +\n HEX_TABLE[bytes[6]] +\n HEX_TABLE[bytes[7]] +\n '-' +\n HEX_TABLE[bytes[8]] +\n HEX_TABLE[bytes[9]] +\n '-' +\n HEX_TABLE[bytes[10]] +\n HEX_TABLE[bytes[11]] +\n HEX_TABLE[bytes[12]] +\n HEX_TABLE[bytes[13]] +\n HEX_TABLE[bytes[14]] +\n HEX_TABLE[bytes[15]]\n )\n}\n\nexport function parseUuid(value: string): Uint8Array {\n if (value.length !== UUID_STRING_LENGTH) {\n throw new ParseError('UUID_INVALID_LENGTH', `UUID string must be 36 characters, got ${value.length}`)\n }\n\n // Validate separator positions directly (more efficient than full loop)\n if (value[8] !== '-' || value[13] !== '-' || value[18] !== '-' || value[23] !== '-') {\n throw new ParseError(\n 'UUID_INVALID_SEPARATORS',\n `UUID string has invalid separators at positions 8, 13, 18, 23. Received: \"${value}\"`,\n )\n }\n\n // Parse bytes directly from UUID string without intermediate string allocations.\n // This avoids the 9 allocations (5 slices + 4 concatenations) of the naive approach.\n const bytes = new Uint8Array(UUID_BYTE_LENGTH)\n\n for (let i = 0; i < UUID_STRING_LENGTH; i += 1) {\n const byteIdx = UUID_CHAR_TO_BYTE[i]\n if (byteIdx === -1) continue // Skip dash positions\n\n const nibble = hexValue(value.charCodeAt(i))\n if (nibble === -1) {\n throw new ParseError('UUID_INVALID_HEX_CHAR', `UUID string contains invalid hex character at position ${i}`)\n }\n\n if (UUID_CHAR_IS_HIGH[i]) {\n bytes[byteIdx] = nibble << 4\n } else {\n bytes[byteIdx] |= nibble\n }\n }\n\n return bytes\n}\n"],"mappings":"0CAYA,SAAgB,EAAS,EAAsB,CAU7C,OATI,GAAQ,IAAW,GAAQ,GACtB,EAAO,GAEZ,GAAQ,IAAW,GAAQ,GACtB,EAAO,GAAU,GAEtB,GAAQ,IAAW,GAAQ,IACtB,EAAO,GAAU,GAEnB,GCnBT,MAMMA,EAA8B,CAClC,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACD,CAGKC,EAA+B,CACnC,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACD,CAMKC,EAAsB,MAAM,KAAK,CAAE,OAAQ,IAAK,EAAG,EAAG,IAAM,EAAE,SAAS,GAAG,CAAC,SAAS,EAAG,IAAI,CAAC,CAElG,SAAgB,EAAW,EAA2B,CAIpD,OACE,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAIpB,SAAgB,EAAU,EAA2B,CACnD,GAAI,EAAM,SAAW,GACnB,MAAM,IAAI,EAAW,sBAAuB,0CAA0C,EAAM,SAAS,CAIvG,GAAI,EAAM,KAAO,KAAO,EAAM,MAAQ,KAAO,EAAM,MAAQ,KAAO,EAAM,MAAQ,IAC9E,MAAM,IAAI,EACR,0BACA,6EAA6E,EAAM,GACpF,CAKH,IAAM,EAAQ,IAAI,WAAW,GAAiB,CAE9C,IAAK,IAAI,EAAI,EAAG,EAAI,GAAoB,GAAK,EAAG,CAC9C,IAAM,EAAU,EAAkB,GAClC,GAAI,IAAY,GAAI,SAEpB,IAAM,EAAS,EAAS,EAAM,WAAW,EAAE,CAAC,CAC5C,GAAI,IAAW,GACb,MAAM,IAAI,EAAW,wBAAyB,0DAA0D,IAAI,CAG1G,EAAkB,GACpB,EAAM,GAAW,GAAU,EAE3B,EAAM,IAAY,EAItB,OAAO"} |
| import { InvalidInputError, ParseError } from '../errors' | ||
| import type { UuidV7Options } from '../uuid/v7' | ||
| import { uuidv7 } from '../uuid/v7' | ||
| export type TypeidOptions = UuidV7Options | ||
| export type Typeid = { | ||
| (prefix: string, options?: TypeidOptions): string | ||
| toBytes(id: string): Uint8Array | ||
| fromBytes(prefix: string, bytes: Uint8Array): string | ||
| toUuid(id: string): string | ||
| fromUuid(prefix: string, uuid: string): string | ||
| timestamp(id: string): number | ||
| prefix(id: string): string | ||
| suffix(id: string): string | ||
| isValid(id: unknown): id is string | ||
| } | ||
| const TYPEID_SUFFIX_LENGTH = 26 | ||
| const TYPEID_UUID_BYTE_LENGTH = 16 | ||
| const TYPEID_ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz' | ||
| const BASE32_DECODE: number[] = Array.from({ length: 128 }, () => -1) | ||
| for (let i = 0; i < TYPEID_ALPHABET.length; i += 1) { | ||
| BASE32_DECODE[TYPEID_ALPHABET.charCodeAt(i)] = i | ||
| } | ||
| type ParsedTypeid = { | ||
| prefix: string | ||
| suffix: string | ||
| bytes: Uint8Array | ||
| } | ||
| function assertValidPrefix(prefix: string): void { | ||
| if (prefix.length === 0) { | ||
| return | ||
| } | ||
| if (prefix.length > 63) { | ||
| throw new InvalidInputError('TYPEID_PREFIX_TOO_LONG', 'TypeID prefix must be at most 63 characters') | ||
| } | ||
| for (let i = 0; i < prefix.length; i += 1) { | ||
| const code = prefix.charCodeAt(i) | ||
| const isLowercaseLetter = code >= 97 && code <= 122 | ||
| const isUnderscore = code === 95 | ||
| if (!isLowercaseLetter && !isUnderscore) { | ||
| throw new InvalidInputError( | ||
| 'TYPEID_PREFIX_INVALID_CHARACTER', | ||
| 'TypeID prefix must contain only lowercase ASCII letters and underscores', | ||
| ) | ||
| } | ||
| if ((i === 0 || i === prefix.length - 1) && !isLowercaseLetter) { | ||
| throw new InvalidInputError('TYPEID_PREFIX_INVALID_BOUNDARY', 'TypeID prefix must start and end with a-z') | ||
| } | ||
| } | ||
| } | ||
| function decodeSuffixValue(suffix: string, index: number): number { | ||
| const code = suffix.charCodeAt(index) | ||
| const value = code < BASE32_DECODE.length ? BASE32_DECODE[code] : -1 | ||
| if (value === -1) { | ||
| throw new ParseError( | ||
| 'TYPEID_SUFFIX_INVALID_CHARACTER', | ||
| `TypeID suffix contains invalid character at position ${index}`, | ||
| ) | ||
| } | ||
| return value | ||
| } | ||
| function assertValidSuffixShape(suffix: string): void { | ||
| if (suffix.length !== TYPEID_SUFFIX_LENGTH) { | ||
| throw new ParseError('TYPEID_SUFFIX_INVALID_LENGTH', `TypeID suffix must be 26 characters, got ${suffix.length}`) | ||
| } | ||
| if (suffix[0] > '7') { | ||
| throw new ParseError('TYPEID_SUFFIX_OVERFLOW', 'TypeID suffix must encode a 128-bit value') | ||
| } | ||
| } | ||
| function encodeBytesToSuffix(bytes: Uint8Array): string { | ||
| if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) { | ||
| throw new InvalidInputError('TYPEID_UUID_BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`) | ||
| } | ||
| return ( | ||
| TYPEID_ALPHABET[(bytes[0] & 0xe0) >> 5] + | ||
| TYPEID_ALPHABET[bytes[0] & 0x1f] + | ||
| TYPEID_ALPHABET[(bytes[1] & 0xf8) >> 3] + | ||
| TYPEID_ALPHABET[((bytes[1] & 0x07) << 2) | ((bytes[2] & 0xc0) >> 6)] + | ||
| TYPEID_ALPHABET[(bytes[2] & 0x3e) >> 1] + | ||
| TYPEID_ALPHABET[((bytes[2] & 0x01) << 4) | ((bytes[3] & 0xf0) >> 4)] + | ||
| TYPEID_ALPHABET[((bytes[3] & 0x0f) << 1) | ((bytes[4] & 0x80) >> 7)] + | ||
| TYPEID_ALPHABET[(bytes[4] & 0x7c) >> 2] + | ||
| TYPEID_ALPHABET[((bytes[4] & 0x03) << 3) | ((bytes[5] & 0xe0) >> 5)] + | ||
| TYPEID_ALPHABET[bytes[5] & 0x1f] + | ||
| TYPEID_ALPHABET[(bytes[6] & 0xf8) >> 3] + | ||
| TYPEID_ALPHABET[((bytes[6] & 0x07) << 2) | ((bytes[7] & 0xc0) >> 6)] + | ||
| TYPEID_ALPHABET[(bytes[7] & 0x3e) >> 1] + | ||
| TYPEID_ALPHABET[((bytes[7] & 0x01) << 4) | ((bytes[8] & 0xf0) >> 4)] + | ||
| TYPEID_ALPHABET[((bytes[8] & 0x0f) << 1) | ((bytes[9] & 0x80) >> 7)] + | ||
| TYPEID_ALPHABET[(bytes[9] & 0x7c) >> 2] + | ||
| TYPEID_ALPHABET[((bytes[9] & 0x03) << 3) | ((bytes[10] & 0xe0) >> 5)] + | ||
| TYPEID_ALPHABET[bytes[10] & 0x1f] + | ||
| TYPEID_ALPHABET[(bytes[11] & 0xf8) >> 3] + | ||
| TYPEID_ALPHABET[((bytes[11] & 0x07) << 2) | ((bytes[12] & 0xc0) >> 6)] + | ||
| TYPEID_ALPHABET[(bytes[12] & 0x3e) >> 1] + | ||
| TYPEID_ALPHABET[((bytes[12] & 0x01) << 4) | ((bytes[13] & 0xf0) >> 4)] + | ||
| TYPEID_ALPHABET[((bytes[13] & 0x0f) << 1) | ((bytes[14] & 0x80) >> 7)] + | ||
| TYPEID_ALPHABET[(bytes[14] & 0x7c) >> 2] + | ||
| TYPEID_ALPHABET[((bytes[14] & 0x03) << 3) | ((bytes[15] & 0xe0) >> 5)] + | ||
| TYPEID_ALPHABET[bytes[15] & 0x1f] | ||
| ) | ||
| } | ||
| function decodeSuffixToBytes(suffix: string): Uint8Array { | ||
| assertValidSuffixShape(suffix) | ||
| const values = new Array<number>(TYPEID_SUFFIX_LENGTH) | ||
| for (let i = 0; i < TYPEID_SUFFIX_LENGTH; i += 1) { | ||
| values[i] = decodeSuffixValue(suffix, i) | ||
| } | ||
| const bytes = new Uint8Array(TYPEID_UUID_BYTE_LENGTH) | ||
| bytes[0] = (values[0] << 5) | values[1] | ||
| bytes[1] = (values[2] << 3) | (values[3] >> 2) | ||
| bytes[2] = ((values[3] & 0x03) << 6) | (values[4] << 1) | (values[5] >> 4) | ||
| bytes[3] = ((values[5] & 0x0f) << 4) | (values[6] >> 1) | ||
| bytes[4] = ((values[6] & 0x01) << 7) | (values[7] << 2) | (values[8] >> 3) | ||
| bytes[5] = ((values[8] & 0x07) << 5) | values[9] | ||
| bytes[6] = (values[10] << 3) | (values[11] >> 2) | ||
| bytes[7] = ((values[11] & 0x03) << 6) | (values[12] << 1) | (values[13] >> 4) | ||
| bytes[8] = ((values[13] & 0x0f) << 4) | (values[14] >> 1) | ||
| bytes[9] = ((values[14] & 0x01) << 7) | (values[15] << 2) | (values[16] >> 3) | ||
| bytes[10] = ((values[16] & 0x07) << 5) | values[17] | ||
| bytes[11] = (values[18] << 3) | (values[19] >> 2) | ||
| bytes[12] = ((values[19] & 0x03) << 6) | (values[20] << 1) | (values[21] >> 4) | ||
| bytes[13] = ((values[21] & 0x0f) << 4) | (values[22] >> 1) | ||
| bytes[14] = ((values[22] & 0x01) << 7) | (values[23] << 2) | (values[24] >> 3) | ||
| bytes[15] = ((values[24] & 0x07) << 5) | values[25] | ||
| return bytes | ||
| } | ||
| function assertUuidV7Bytes(bytes: Uint8Array): void { | ||
| if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) { | ||
| throw new InvalidInputError('TYPEID_UUID_BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`) | ||
| } | ||
| if (bytes[6] >> 4 !== 7 || (bytes[8] & 0xc0) !== 0x80) { | ||
| throw new InvalidInputError('TYPEID_UUID_NOT_V7', 'TypeID UUID bytes must encode a UUID v7 value') | ||
| } | ||
| } | ||
| function uuidV7BytesFromSuffix(suffix: string): Uint8Array { | ||
| const bytes = decodeSuffixToBytes(suffix) | ||
| assertUuidV7Bytes(bytes) | ||
| return bytes | ||
| } | ||
| function uuidV7BytesFromUuid(uuid: string): Uint8Array { | ||
| if (!uuidv7.isValid(uuid)) { | ||
| throw new InvalidInputError('TYPEID_UUID_NOT_V7', 'TypeID can only wrap UUID v7 values') | ||
| } | ||
| return uuidv7.toBytes(uuid) | ||
| } | ||
| function parseTypeid(id: string): ParsedTypeid { | ||
| const separatorIndex = id.lastIndexOf('_') | ||
| if (separatorIndex === 0) { | ||
| throw new ParseError('TYPEID_INVALID_FORMAT', 'TypeID must not start with "_"') | ||
| } | ||
| const prefix = separatorIndex === -1 ? '' : id.slice(0, separatorIndex) | ||
| const suffix = separatorIndex === -1 ? id : id.slice(separatorIndex + 1) | ||
| assertValidPrefix(prefix) | ||
| const bytes = uuidV7BytesFromSuffix(suffix) | ||
| return { prefix, suffix, bytes } | ||
| } | ||
| function joinPrefixAndSuffix(prefix: string, suffix: string): string { | ||
| return prefix === '' ? suffix : `${prefix}_${suffix}` | ||
| } | ||
| function formatTypeidFromUuidV7Bytes(prefix: string, bytes: Uint8Array): string { | ||
| assertValidPrefix(prefix) | ||
| assertUuidV7Bytes(bytes) | ||
| return joinPrefixAndSuffix(prefix, encodeBytesToSuffix(bytes)) | ||
| } | ||
| function timestampFromUuidV7Bytes(bytes: Uint8Array): number { | ||
| let msecs = 0 | ||
| for (let i = 0; i < 6; i += 1) { | ||
| msecs = msecs * 256 + bytes[i] | ||
| } | ||
| return msecs | ||
| } | ||
| function typeidFn(prefix: string, options?: TypeidOptions): string { | ||
| const bytes = uuidv7(options, new Uint8Array(TYPEID_UUID_BYTE_LENGTH)) | ||
| return formatTypeidFromUuidV7Bytes(prefix, bytes) | ||
| } | ||
| function typeidToBytes(id: string): Uint8Array { | ||
| return parseTypeid(id).bytes | ||
| } | ||
| function typeidFromBytes(prefix: string, bytes: Uint8Array): string { | ||
| return formatTypeidFromUuidV7Bytes(prefix, bytes) | ||
| } | ||
| function typeidToUuid(id: string): string { | ||
| return uuidv7.fromBytes(typeidToBytes(id)) | ||
| } | ||
| function typeidFromUuid(prefix: string, uuid: string): string { | ||
| return formatTypeidFromUuidV7Bytes(prefix, uuidV7BytesFromUuid(uuid)) | ||
| } | ||
| function timestamp(id: string): number { | ||
| return timestampFromUuidV7Bytes(parseTypeid(id).bytes) | ||
| } | ||
| function prefix(id: string): string { | ||
| return parseTypeid(id).prefix | ||
| } | ||
| function suffix(id: string): string { | ||
| return parseTypeid(id).suffix | ||
| } | ||
| function isValid(id: unknown): id is string { | ||
| if (typeof id !== 'string') { | ||
| return false | ||
| } | ||
| try { | ||
| parseTypeid(id) | ||
| } catch { | ||
| return false | ||
| } | ||
| return true | ||
| } | ||
| /** | ||
| * Generate a TypeID string backed by UUID v7. | ||
| * | ||
| * TypeID combines a lowercase snake_case type prefix with a 26-character | ||
| * modified base32 encoding of a UUID v7, producing sortable domain identifiers | ||
| * such as `user_01h2xcejqtf2nbrexx3vqjhp41`. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { typeid } from 'uniku/typeid' | ||
| * | ||
| * const id = typeid('user') | ||
| * // => "user_01h2xcejqtf2nbrexx3vqjhp41" | ||
| * | ||
| * const uuid = typeid.toUuid(id) | ||
| * const restored = typeid.fromUuid('user', uuid) | ||
| * ``` | ||
| */ | ||
| export const typeid: Typeid = Object.assign(typeidFn, { | ||
| toBytes: typeidToBytes, | ||
| fromBytes: typeidFromBytes, | ||
| toUuid: typeidToUuid, | ||
| fromUuid: typeidFromUuid, | ||
| timestamp, | ||
| prefix, | ||
| suffix, | ||
| isValid, | ||
| }) | ||
| export { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors' |
@@ -1,2 +0,2 @@ | ||
| import{t as e}from"../random-CWCVvNLb.mjs";import{InvalidInputError as t,UniqueIdError as n}from"../errors.mjs";import{sha3_512 as r}from"@noble/hashes/sha3.js";const i=/^[a-z][0-9a-z]+$/,a=`0123456789abcdefghijklmnopqrstuvwxyz`,o=new TextEncoder,s={counter:void 0,fingerprint:void 0};function c(){return e()%476782368}function l(e){let t=0n;for(let n of e)t=t*256n+BigInt(n);return t}function u(e){if(e===0n)return`0`;let t=[];for(;e>0n;)t.push(a[Number(e%36n)]),e/=36n;return t.reverse().join(``)}function d(e){return`abcdefghijklmnopqrstuvwxyz`[Math.floor(e()*26)]}function f(e,t){let n=Array(e);for(let r=0;r<e;r++)n[r]=a[Math.floor(t()*36)];return n.join(``)}function p(e){return r(o.encode(e))}function m(){let e=h;return u(l(p(Object.keys(globalThis).toString()+f(32,e)))).slice(1,33)}function h(){return e()/4294967296}function g(e){if(e){if(e.length===0)throw new t(`CUID2_RANDOM_BYTES_EMPTY`,`Random byte array cannot be empty`);let n=0;return()=>{let t=e[n%e.length]/256;return n+=1,t}}return h}function _(e){let n=e?.length??24;if(n<2||n>32)throw new t(`CUID2_LENGTH_OUT_OF_RANGE`,`CUID2 length must be between 2 and 32. Received: ${n}`);let r=g(e?.random);s.counter===void 0&&(s.counter=c()),s.fingerprint===void 0&&(s.fingerprint=m());let i=d(r),a=Date.now().toString(36);s.counter+=1;let o=s.counter.toString(36);return i+u(l(p(a+f(n,r)+o+s.fingerprint))).slice(1,n)}function v(e){return typeof e==`string`&&e.length>=2&&e.length<=32&&i.test(e)}const y=Object.assign(_,{isValid:v});export{t as InvalidInputError,n as UniqueIdError,y as cuid2}; | ||
| import{t as e}from"../random-CGMm8owG.mjs";import{InvalidInputError as t,UniqueIdError as n}from"../errors.mjs";import{sha3_512 as r}from"@noble/hashes/sha3.js";const i=/^[a-z][0-9a-z]+$/,a=`0123456789abcdefghijklmnopqrstuvwxyz`,o=new TextEncoder,s={counter:void 0,fingerprint:void 0};function c(){return e()%476782368}function l(e){let t=0n;for(let n of e)t=t*256n+BigInt(n);return t}function u(e){if(e===0n)return`0`;let t=[];for(;e>0n;)t.push(a[Number(e%36n)]),e/=36n;return t.reverse().join(``)}function d(e){return`abcdefghijklmnopqrstuvwxyz`[Math.floor(e()*26)]}function f(e,t){let n=Array(e);for(let r=0;r<e;r++)n[r]=a[Math.floor(t()*36)];return n.join(``)}function p(e){return r(o.encode(e))}function m(){let e=h;return u(l(p(Object.keys(globalThis).toString()+f(32,e)))).slice(1,33)}function h(){return e()/4294967296}function g(e){if(e){if(e.length===0)throw new t(`CUID2_RANDOM_BYTES_EMPTY`,`Random byte array cannot be empty`);let n=0;return()=>{let t=e[n%e.length]/256;return n+=1,t}}return h}function _(e){let n=e?.length??24;if(n<2||n>32)throw new t(`CUID2_LENGTH_OUT_OF_RANGE`,`CUID2 length must be between 2 and 32. Received: ${n}`);let r=g(e?.random);s.counter===void 0&&(s.counter=c()),s.fingerprint===void 0&&(s.fingerprint=m());let i=d(r),a=Date.now().toString(36);s.counter+=1;let o=s.counter.toString(36);return i+u(l(p(a+f(n,r)+o+s.fingerprint))).slice(1,n)}function v(e){return typeof e==`string`&&e.length>=2&&e.length<=32&&i.test(e)}const y=Object.assign(_,{isValid:v});export{t as InvalidInputError,n as UniqueIdError,y as cuid2}; | ||
| //# sourceMappingURL=cuid2.mjs.map |
@@ -1,2 +0,2 @@ | ||
| import{n as e}from"../random-CWCVvNLb.mjs";import{BufferError as t,InvalidInputError as n,ParseError as r,UniqueIdError as i}from"../errors.mjs";import{n as a}from"../bytes-NRtBOHK5.mjs";const o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`,s=62n,c=(1n<<160n)-1n,l=new Uint8Array(65536);l.fill(255);for(let e=0;e<62;e+=1)l[o.charCodeAt(e)]=e;function u(e){if(e.length<20)throw new t(`KSUID_BYTES_TOO_SHORT`,`KSUID bytes must be at least 20 bytes, got ${e.length}`);let n=0n;for(let t=0;t<20;t+=1)n=n<<8n|BigInt(e[t]);let r=``;for(;n>0n;){let e=n%s;n/=s,r=o[Number(e)]+r}return r.padStart(27,`0`)}function d(e){if(e.length!==27)throw new r(`KSUID_INVALID_LENGTH`,`KSUID string must be 27 characters, got ${e.length}`);let t=0n;for(let n=0;n<27;n+=1){let i=l[e.charCodeAt(n)];if(i===255)throw new r(`KSUID_INVALID_CHAR`,`Invalid KSUID character: ${e[n]}`);t=t*s+BigInt(i)}if(t>c)throw new r(`KSUID_OVERFLOW`,`KSUID string exceeds 160-bit range`);let n=new Uint8Array(20);for(let e=19;e>=0;--e)n[e]=Number(t&255n),t>>=8n;return n}const f=14e8;f+4294967295;const p=u(new Uint8Array(20).fill(255)),m=/^[0-9A-Za-z]{27}$/;function h(e,n,r,i=0){if(!r)r=new Uint8Array(20),i=0;else if(i<0||i+20>r.length)throw new t(`KSUID_BUFFER_OUT_OF_BOUNDS`,`KSUID byte range ${i}:${i+20-1} is out of buffer bounds`);a(r,i,e);for(let e=0;e<16;e+=1)r[i+4+e]=n[e];return r}function g(t,r,i=0){let a=t?.random;if(a&&a.length<16)throw new n(`KSUID_RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16 for KSUID`);let o,s=t?.secs;if(s!==void 0){if(s<f)throw new n(`KSUID_TIMESTAMP_TOO_LOW`,`Timestamp must be >= KSUID epoch`);if(s>5694967295)throw new n(`KSUID_TIMESTAMP_TOO_HIGH`,`Timestamp must be <= maximum KSUID timestamp`);o=s-f}else o=Math.floor(Date.now()/1e3)-f;let c=a??e();return r?(h(o,c,r,i),r):u(h(o,c))}function _(e){return d(e)}function v(e){return u(e)}function y(e){let t=d(e);return(((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)+f)*1e3}function b(e){return typeof e==`string`&&e.length===27&&m.test(e)&&e<=p}const x=Object.assign(g,{toBytes:_,fromBytes:v,timestamp:y,isValid:b,NIL:`000000000000000000000000000`,MAX:p});export{t as BufferError,n as InvalidInputError,r as ParseError,i as UniqueIdError,x as ksuid}; | ||
| import{n as e}from"../random-CGMm8owG.mjs";import{BufferError as t,InvalidInputError as n,ParseError as r,UniqueIdError as i}from"../errors.mjs";import{n as a}from"../bytes-DzcOKIx1.mjs";const o=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`,s=62n,c=(1n<<160n)-1n,l=new Uint8Array(65536);l.fill(255);for(let e=0;e<62;e+=1)l[o.charCodeAt(e)]=e;function u(e){if(e.length<20)throw new t(`KSUID_BYTES_TOO_SHORT`,`KSUID bytes must be at least 20 bytes, got ${e.length}`);let n=0n;for(let t=0;t<20;t+=1)n=n<<8n|BigInt(e[t]);let r=``;for(;n>0n;){let e=n%s;n/=s,r=o[Number(e)]+r}return r.padStart(27,`0`)}function d(e){if(e.length!==27)throw new r(`KSUID_INVALID_LENGTH`,`KSUID string must be 27 characters, got ${e.length}`);let t=0n;for(let n=0;n<27;n+=1){let i=l[e.charCodeAt(n)];if(i===255)throw new r(`KSUID_INVALID_CHAR`,`Invalid KSUID character: ${e[n]}`);t=t*s+BigInt(i)}if(t>c)throw new r(`KSUID_OVERFLOW`,`KSUID string exceeds 160-bit range`);let n=new Uint8Array(20);for(let e=19;e>=0;--e)n[e]=Number(t&255n),t>>=8n;return n}const f=14e8;f+4294967295;const p=u(new Uint8Array(20).fill(255)),m=/^[0-9A-Za-z]{27}$/;function h(e,n,r,i=0){if(!r)r=new Uint8Array(20),i=0;else if(i<0||i+20>r.length)throw new t(`KSUID_BUFFER_OUT_OF_BOUNDS`,`KSUID byte range ${i}:${i+20-1} is out of buffer bounds`);a(r,i,e);for(let e=0;e<16;e+=1)r[i+4+e]=n[e];return r}function g(t,r,i=0){let a=t?.random;if(a&&a.length<16)throw new n(`KSUID_RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16 for KSUID`);let o,s=t?.secs;if(s!==void 0){if(s<f)throw new n(`KSUID_TIMESTAMP_TOO_LOW`,`Timestamp must be >= KSUID epoch`);if(s>5694967295)throw new n(`KSUID_TIMESTAMP_TOO_HIGH`,`Timestamp must be <= maximum KSUID timestamp`);o=s-f}else o=Math.floor(Date.now()/1e3)-f;let c=a??e();return r?(h(o,c,r,i),r):u(h(o,c))}function _(e){return d(e)}function v(e){return u(e)}function y(e){let t=d(e);return(((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)+f)*1e3}function b(e){return typeof e==`string`&&e.length===27&&m.test(e)&&e<=p}const x=Object.assign(g,{toBytes:_,fromBytes:v,timestamp:y,isValid:b,NIL:`000000000000000000000000000`,MAX:p});export{t as BufferError,n as InvalidInputError,r as ParseError,i as UniqueIdError,x as ksuid}; | ||
| //# sourceMappingURL=ksuid.mjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"nanoid.d.mts","names":["nanoid: Nanoid"],"sources":["../../src/nanoid/nanoid.ts"],"sourcesContent":[],"mappings":";;;;cAGa,YAAA;KAyBD,aAAA;EAzBZ;AAyBA;AAkBA;AAqMA;;WAjNW;;;;;;;;;;;KAYC,MAAA;;;;;;YAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA+LCA,QAAQ"} | ||
| {"version":3,"file":"nanoid.d.mts","names":["nanoid: Nanoid"],"sources":["../../src/nanoid/nanoid.ts"],"sourcesContent":[],"mappings":";;;;cAGa,YAAA;KAmCD,aAAA;EAnCZ;AAmCA;AAkBA;AAoMA;;WAhNW;;;;;;;;;;;KAYC,MAAA;;;;;;YAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8LCA,QAAQ"} |
@@ -1,2 +0,2 @@ | ||
| import{InvalidInputError as e,UniqueIdError as t}from"../errors.mjs";const n=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`,r=2048,i=/^[A-Za-z0-9_-]+$/;let a,o=0;function s(e){let t=e*128;!a||a.length<t?(a=new Uint8Array(t),crypto.getRandomValues(a),o=0):o+e>a.length&&(crypto.getRandomValues(a),o=0),o+=e}function c(t){if(t.length<2)throw new e(`NANOID_ALPHABET_TOO_SHORT`,`Alphabet must contain at least 2 characters`);if(t.length>256)throw new e(`NANOID_ALPHABET_TOO_LONG`,`Alphabet must not exceed 256 characters`);let n=new Set;for(let r of t){let t=r.charCodeAt(0);if(t<32||t>126)throw new e(`NANOID_ALPHABET_INVALID_CHAR`,`Alphabet must contain only printable ASCII characters (32-126)`);if(n.has(r))throw new e(`NANOID_ALPHABET_DUPLICATE`,`Duplicate character in alphabet: "${r}"`);n.add(r)}}function l(t){if(!Number.isInteger(t)||t<0)throw new e(`NANOID_SIZE_INVALID`,`Size must be a non-negative integer`);if(t>r)throw new e(`NANOID_SIZE_TOO_LARGE`,`Size must not exceed ${r}`)}function u(t){if(t===void 0){s(21);let e=``;for(let t=o-21;t<o;t++)e+=n[a[t]&63];return e}let r=21,i=n,u;if(typeof t==`number`?r=t:(r=t.size??21,i=t.alphabet??n,u=t.random,t.alphabet!==void 0&&c(i)),l(r),r===0)return``;let d=i.length;if(!(d&d-1)){let t=d-1;if(u&&u.length<r)throw new e(`NANOID_RANDOM_BYTES_INSUFFICIENT`,`Insufficient random bytes: need ${r}, have ${u.length}`);let n=u?.subarray(0,r)??globalThis.crypto.getRandomValues(new Uint8Array(r)),a=``;for(let e=0;e<r;e++)a+=i[n[e]&t];return a}let f=(2<<31-Math.clz32(d-1|1))-1,p=Math.ceil(1.6*f*r/d),m=``,h=0;for(;m.length<r;){let t;if(u){if(u.length-h<p)throw new e(`NANOID_RANDOM_BYTES_INSUFFICIENT`,`Insufficient random bytes: need at least ${p} more, have ${u.length-h}`);t=u.subarray(h,h+p),h+=p}else t=globalThis.crypto.getRandomValues(new Uint8Array(p));for(let e=0;e<t.length&&m.length<r;e++){let n=t[e]&f;n<d&&(m+=i[n])}}return m}function d(e){return typeof e==`string`&&e.length>0&&i.test(e)}const f=Object.assign(u,{isValid:d});export{e as InvalidInputError,n as URL_ALPHABET,t as UniqueIdError,f as nanoid}; | ||
| import{InvalidInputError as e,UniqueIdError as t}from"../errors.mjs";const n=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`,r=2048,i=/^[A-Za-z0-9_-]+$/;let a,o=0;function s(e){let t=Math.min(e*128,65536);!a||a.length<t?(a=new Uint8Array(t),crypto.getRandomValues(a),o=0):o+e>a.length&&(crypto.getRandomValues(a),o=0),o+=e}function c(e){s(e);let t=``;for(let r=o-e;r<o;r++)t+=n[a[r]&63];return t}function l(t){if(t.length<2)throw new e(`NANOID_ALPHABET_TOO_SHORT`,`Alphabet must contain at least 2 characters`);if(t.length>256)throw new e(`NANOID_ALPHABET_TOO_LONG`,`Alphabet must not exceed 256 characters`);let n=new Set;for(let r of t){let t=r.charCodeAt(0);if(t<32||t>126)throw new e(`NANOID_ALPHABET_INVALID_CHAR`,`Alphabet must contain only printable ASCII characters (32-126)`);if(n.has(r))throw new e(`NANOID_ALPHABET_DUPLICATE`,`Duplicate character in alphabet: "${r}"`);n.add(r)}}function u(t){if(!Number.isInteger(t)||t<0)throw new e(`NANOID_SIZE_INVALID`,`Size must be a non-negative integer`);if(t>r)throw new e(`NANOID_SIZE_TOO_LARGE`,`Size must not exceed ${r}`)}function d(t){if(t===void 0)return c(21);let r=21,i=n,a;if(typeof t==`number`?r=t:(r=t.size??21,i=t.alphabet??n,a=t.random,t.alphabet!==void 0&&l(i)),u(r),r===0)return``;if(i===n&&a===void 0)return c(r);let o=i.length;if(!(o&o-1)){let t=o-1;if(a&&a.length<r)throw new e(`NANOID_RANDOM_BYTES_INSUFFICIENT`,`Insufficient random bytes: need ${r}, have ${a.length}`);let n=a?.subarray(0,r)??globalThis.crypto.getRandomValues(new Uint8Array(r)),s=``;for(let e=0;e<r;e++)s+=i[n[e]&t];return s}let s=(2<<31-Math.clz32(o-1|1))-1,d=Math.ceil(1.6*s*r/o),f=``,p=0;for(;f.length<r;){let t;if(a){if(a.length-p<d)throw new e(`NANOID_RANDOM_BYTES_INSUFFICIENT`,`Insufficient random bytes: need at least ${d} more, have ${a.length-p}`);t=a.subarray(p,p+d),p+=d}else t=globalThis.crypto.getRandomValues(new Uint8Array(d));for(let e=0;e<t.length&&f.length<r;e++){let n=t[e]&s;n<o&&(f+=i[n])}}return f}function f(e){return typeof e==`string`&&e.length>0&&i.test(e)}const p=Object.assign(d,{isValid:f});export{e as InvalidInputError,n as URL_ALPHABET,t as UniqueIdError,p as nanoid}; | ||
| //# sourceMappingURL=nanoid.mjs.map |
@@ -1,1 +0,1 @@ | ||
| {"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// Keep Nanoid's private pool for its default hot path. It consumes `size`\n// bytes directly without the shared helper's UUID/CUID2-oriented branches.\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":"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"} | ||
| {"version":3,"file":"nanoid.mjs","names":["pool: Uint8Array | undefined","randomBytes: Uint8Array | undefined","mask","id","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// Keep Nanoid's private pool for its default hot path. It consumes `size`\n// bytes directly without the shared helper's UUID/CUID2-oriented branches.\nconst POOL_SIZE_MULTIPLIER = 128\nconst MAX_POOL_SIZE = 65_536\nlet pool: Uint8Array | undefined\nlet poolOffset = 0\n\nfunction fillPool(bytes: number): void {\n const size = Math.min(bytes * POOL_SIZE_MULTIPLIER, MAX_POOL_SIZE)\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\nfunction defaultAlphabetFromPool(size: number): string {\n fillPool(size)\n let id = ''\n for (let i = poolOffset - size; i < poolOffset; i++) {\n id += URL_ALPHABET[pool![i] & 63]\n }\n return id\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 return defaultAlphabetFromPool(DEFAULT_SIZE)\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 if (alphabet === URL_ALPHABET && randomBytes === undefined) {\n return defaultAlphabetFromPool(size)\n }\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":"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"} |
@@ -1,2 +0,2 @@ | ||
| import{n as e}from"../random-CWCVvNLb.mjs";import{BufferError as t,InvalidInputError as n,ParseError as r,UniqueIdError as i}from"../errors.mjs";import{r as a,t as o}from"../bytes-NRtBOHK5.mjs";const s=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`,c=new Uint8Array(65536);c.fill(255);for(let e=0;e<32;e+=1){let t=s.charCodeAt(e),n=s[e].toLowerCase().charCodeAt(0);c[t]=e,c[n]=e}function l(e,t){return new r(`ULID_INVALID_CHAR`,`Invalid ULID character: ${e[t]}`)}function u(){return new r(`ULID_TIMESTAMP_OVERFLOW`,`ULID timestamp exceeds 48 bits`)}function d(e){let t=c[e.charCodeAt(0)];if(t===255)throw l(e,0);if(t>7)throw u();let n=t;for(let t=1;t<10;t+=1){let r=c[e.charCodeAt(t)];if(r===255)throw l(e,t);n=n*32+r}return n}function f(e){return s[Math.floor(e/35184372088832)&31]+s[Math.floor(e/1099511627776)&31]+s[Math.floor(e/34359738368)&31]+s[Math.floor(e/1073741824)&31]+s[Math.floor(e/33554432)&31]+s[Math.floor(e/1048576)&31]+s[Math.floor(e/32768)&31]+s[Math.floor(e/1024)&31]+s[Math.floor(e/32)&31]+s[e&31]}function p(e){return s[e[0]>>3&31]+s[(e[0]<<2|e[1]>>6)&31]+s[e[1]>>1&31]+s[(e[1]<<4|e[2]>>4)&31]+s[(e[2]<<1|e[3]>>7)&31]+s[e[3]>>2&31]+s[(e[3]<<3|e[4]>>5)&31]+s[e[4]&31]+s[e[5]>>3&31]+s[(e[5]<<2|e[6]>>6)&31]+s[e[6]>>1&31]+s[(e[6]<<4|e[7]>>4)&31]+s[(e[7]<<1|e[8]>>7)&31]+s[e[8]>>2&31]+s[(e[8]<<3|e[9]>>5)&31]+s[e[9]&31]}function m(e){if(e.length!==26)throw new r(`ULID_INVALID_LENGTH`,`ULID string must be 26 characters`);return d(e)}function h(e){if(e.length!==26)throw new r(`ULID_INVALID_LENGTH`,`ULID string must be 26 characters`);let t=new Uint8Array(16),n=c[e.charCodeAt(0)],i=c[e.charCodeAt(1)],a=c[e.charCodeAt(2)],o=c[e.charCodeAt(3)],s=c[e.charCodeAt(4)],d=c[e.charCodeAt(5)],f=c[e.charCodeAt(6)],p=c[e.charCodeAt(7)],m=c[e.charCodeAt(8)],h=c[e.charCodeAt(9)],g=c[e.charCodeAt(10)],_=c[e.charCodeAt(11)],v=c[e.charCodeAt(12)],y=c[e.charCodeAt(13)],b=c[e.charCodeAt(14)],x=c[e.charCodeAt(15)],S=c[e.charCodeAt(16)],C=c[e.charCodeAt(17)],w=c[e.charCodeAt(18)],T=c[e.charCodeAt(19)],E=c[e.charCodeAt(20)],D=c[e.charCodeAt(21)],O=c[e.charCodeAt(22)],k=c[e.charCodeAt(23)],A=c[e.charCodeAt(24)],j=c[e.charCodeAt(25)];if((n|i|a|o|s|d|f|p|m|h|g|_|v|y|b|x|S|C|w|T|E|D|O|k|A|j)&128){for(let t=0;t<26;t+=1)if(c[e.charCodeAt(t)]===255)throw l(e,t)}if(n>7)throw u();return t[0]=n<<5|i,t[1]=a<<3|o>>2,t[2]=o<<6|s<<1|d>>4,t[3]=d<<4|f>>1,t[4]=f<<7|p<<2|m>>3,t[5]=m<<5|h,t[6]=g<<3|_>>2,t[7]=_<<6|v<<1|y>>4,t[8]=y<<4|b>>1,t[9]=b<<7|x<<2|S>>3,t[10]=S<<5|C,t[11]=w<<3|T>>2,t[12]=T<<6|E<<1|D>>4,t[13]=D<<4|O>>1,t[14]=O<<7|k<<2|A>>3,t[15]=A<<5|j,t}function g(e){if(e.length<16)throw new t(`ULID_BYTES_TOO_SHORT`,`Byte array must be at least 16 bytes`);let n=0;for(let t=0;t<6;t+=1)n=n*256+e[t];return f(n)+p(e.subarray(6,16))}const _=/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/i,v={msecs:-1/0,lastRandom:new Uint8Array(10)};function y(e,n,r,i=0){if(!r)r=new Uint8Array(16),i=0;else if(i<0||i+16>r.length)throw new t(`ULID_BUFFER_OUT_OF_BOUNDS`,`ULID byte range ${i}:${i+15} is out of buffer bounds`);a(r,i,e);for(let e=0;e<10;e+=1)r[i+6+e]=n[e];return r}function b(t,r,i=0){let a,s,c=Date.now();if(t)if(a=t.msecs??c,t.random){if(t.random.length<10)throw new n(`ULID_RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 10 for ULID`);s=t.random}else s=e();else if(a=c,a>v.msecs)s=e(),v.msecs=a,v.lastRandom.set(s.subarray(0,10));else{if(a=v.msecs,!o(v.lastRandom))throw v.lastRandom.fill(255),new n(`ULID_RANDOM_OVERFLOW`,`ULID random component overflowed while preserving monotonic order`);s=v.lastRandom}return r?(y(a,s,r,i),r):f(a)+p(s)}function x(e){return typeof e==`string`&&_.test(e)}const S=Object.assign(b,{toBytes:e=>h(e),fromBytes:e=>g(e),timestamp:e=>m(e),isValid:x,NIL:`00000000000000000000000000`,MAX:`7ZZZZZZZZZZZZZZZZZZZZZZZZZ`});export{t as BufferError,n as InvalidInputError,r as ParseError,i as UniqueIdError,S as ulid}; | ||
| import{n as e}from"../random-CGMm8owG.mjs";import{BufferError as t,InvalidInputError as n,ParseError as r,UniqueIdError as i}from"../errors.mjs";import{r as a,t as o}from"../bytes-DzcOKIx1.mjs";const s=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`,c=new Uint8Array(65536);c.fill(255);for(let e=0;e<32;e+=1){let t=s.charCodeAt(e),n=s[e].toLowerCase().charCodeAt(0);c[t]=e,c[n]=e}function l(e,t){return new r(`ULID_INVALID_CHAR`,`Invalid ULID character: ${e[t]}`)}function u(){return new r(`ULID_TIMESTAMP_OVERFLOW`,`ULID timestamp exceeds 48 bits`)}function d(e){let t=c[e.charCodeAt(0)];if(t===255)throw l(e,0);if(t>7)throw u();let n=t;for(let t=1;t<10;t+=1){let r=c[e.charCodeAt(t)];if(r===255)throw l(e,t);n=n*32+r}return n}function f(e){return s[Math.floor(e/35184372088832)&31]+s[Math.floor(e/1099511627776)&31]+s[Math.floor(e/34359738368)&31]+s[Math.floor(e/1073741824)&31]+s[Math.floor(e/33554432)&31]+s[Math.floor(e/1048576)&31]+s[Math.floor(e/32768)&31]+s[Math.floor(e/1024)&31]+s[Math.floor(e/32)&31]+s[e&31]}function p(e){return s[e[0]>>3&31]+s[(e[0]<<2|e[1]>>6)&31]+s[e[1]>>1&31]+s[(e[1]<<4|e[2]>>4)&31]+s[(e[2]<<1|e[3]>>7)&31]+s[e[3]>>2&31]+s[(e[3]<<3|e[4]>>5)&31]+s[e[4]&31]+s[e[5]>>3&31]+s[(e[5]<<2|e[6]>>6)&31]+s[e[6]>>1&31]+s[(e[6]<<4|e[7]>>4)&31]+s[(e[7]<<1|e[8]>>7)&31]+s[e[8]>>2&31]+s[(e[8]<<3|e[9]>>5)&31]+s[e[9]&31]}function m(e){if(e.length!==26)throw new r(`ULID_INVALID_LENGTH`,`ULID string must be 26 characters`);return d(e)}function h(e){if(e.length!==26)throw new r(`ULID_INVALID_LENGTH`,`ULID string must be 26 characters`);let t=new Uint8Array(16),n=c[e.charCodeAt(0)],i=c[e.charCodeAt(1)],a=c[e.charCodeAt(2)],o=c[e.charCodeAt(3)],s=c[e.charCodeAt(4)],d=c[e.charCodeAt(5)],f=c[e.charCodeAt(6)],p=c[e.charCodeAt(7)],m=c[e.charCodeAt(8)],h=c[e.charCodeAt(9)],g=c[e.charCodeAt(10)],_=c[e.charCodeAt(11)],v=c[e.charCodeAt(12)],y=c[e.charCodeAt(13)],b=c[e.charCodeAt(14)],x=c[e.charCodeAt(15)],S=c[e.charCodeAt(16)],C=c[e.charCodeAt(17)],w=c[e.charCodeAt(18)],T=c[e.charCodeAt(19)],E=c[e.charCodeAt(20)],D=c[e.charCodeAt(21)],O=c[e.charCodeAt(22)],k=c[e.charCodeAt(23)],A=c[e.charCodeAt(24)],j=c[e.charCodeAt(25)];if((n|i|a|o|s|d|f|p|m|h|g|_|v|y|b|x|S|C|w|T|E|D|O|k|A|j)&128){for(let t=0;t<26;t+=1)if(c[e.charCodeAt(t)]===255)throw l(e,t)}if(n>7)throw u();return t[0]=n<<5|i,t[1]=a<<3|o>>2,t[2]=o<<6|s<<1|d>>4,t[3]=d<<4|f>>1,t[4]=f<<7|p<<2|m>>3,t[5]=m<<5|h,t[6]=g<<3|_>>2,t[7]=_<<6|v<<1|y>>4,t[8]=y<<4|b>>1,t[9]=b<<7|x<<2|S>>3,t[10]=S<<5|C,t[11]=w<<3|T>>2,t[12]=T<<6|E<<1|D>>4,t[13]=D<<4|O>>1,t[14]=O<<7|k<<2|A>>3,t[15]=A<<5|j,t}function g(e){if(e.length<16)throw new t(`ULID_BYTES_TOO_SHORT`,`Byte array must be at least 16 bytes`);let n=0;for(let t=0;t<6;t+=1)n=n*256+e[t];return f(n)+p(e.subarray(6,16))}const _=/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/i,v={msecs:-1/0,lastRandom:new Uint8Array(10)};function y(e,n,r,i=0){if(!r)r=new Uint8Array(16),i=0;else if(i<0||i+16>r.length)throw new t(`ULID_BUFFER_OUT_OF_BOUNDS`,`ULID byte range ${i}:${i+15} is out of buffer bounds`);a(r,i,e);for(let e=0;e<10;e+=1)r[i+6+e]=n[e];return r}function b(t,r,i=0){let a,s,c=Date.now();if(t)if(a=t.msecs??c,t.random){if(t.random.length<10)throw new n(`ULID_RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 10 for ULID`);s=t.random}else s=e();else if(a=c,a>v.msecs)s=e(),v.msecs=a,v.lastRandom.set(s.subarray(0,10));else{if(a=v.msecs,!o(v.lastRandom))throw v.lastRandom.fill(255),new n(`ULID_RANDOM_OVERFLOW`,`ULID random component overflowed while preserving monotonic order`);s=v.lastRandom}return r?(y(a,s,r,i),r):f(a)+p(s)}function x(e){return typeof e==`string`&&_.test(e)}const S=Object.assign(b,{toBytes:e=>h(e),fromBytes:e=>g(e),timestamp:e=>m(e),isValid:x,NIL:`00000000000000000000000000`,MAX:`7ZZZZZZZZZZZZZZZZZZZZZZZZZ`});export{t as BufferError,n as InvalidInputError,r as ParseError,i as UniqueIdError,S as ulid}; | ||
| //# sourceMappingURL=ulid.mjs.map |
@@ -1,2 +0,2 @@ | ||
| import{n as e}from"../random-CWCVvNLb.mjs";import{BufferError as t,InvalidInputError as n,ParseError as r,UniqueIdError as i}from"../errors.mjs";import{n as a,t as o}from"../uuid-QysI8pWE.mjs";const s=globalThis.crypto.randomUUID.bind(globalThis.crypto),c=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function l(e,r,i=0){if(e.length<16)throw new n(`UUID_RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16`);if(e[6]=e[6]&15|64,e[8]=e[8]&63|128,!r)return e;if(i<0||i+16>r.length)throw new t(`UUID_BUFFER_OUT_OF_BOUNDS`,`UUID byte range ${i}:${i+15} is out of buffer bounds`);for(let t=0;t<16;t+=1)r[i+t]=e[t];return r}function u(e,t,n){return!t&&!e?s():d(e,t,n)}function d(t,n,r){let i=l(t?.random??e(),n,r);return n??o(i)}function f(e){return typeof e==`string`&&c.test(e)}const p=Object.assign(u,{toBytes:a,fromBytes:o,isValid:f,NIL:`00000000-0000-0000-0000-000000000000`,MAX:`ffffffff-ffff-ffff-ffff-ffffffffffff`});export{t as BufferError,n as InvalidInputError,r as ParseError,i as UniqueIdError,p as uuidv4}; | ||
| import{n as e}from"../random-CGMm8owG.mjs";import{BufferError as t,InvalidInputError as n,ParseError as r,UniqueIdError as i}from"../errors.mjs";import{n as a,t as o}from"../uuid-Ub6ladEr.mjs";const s=globalThis.crypto.randomUUID.bind(globalThis.crypto),c=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function l(e,r,i=0){if(e.length<16)throw new n(`UUID_RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16`);if(e[6]=e[6]&15|64,e[8]=e[8]&63|128,!r)return e;if(i<0||i+16>r.length)throw new t(`UUID_BUFFER_OUT_OF_BOUNDS`,`UUID byte range ${i}:${i+15} is out of buffer bounds`);for(let t=0;t<16;t+=1)r[i+t]=e[t];return r}function u(e,t,n){return!t&&!e?s():d(e,t,n)}function d(t,n,r){let i=l(t?.random??e(),n,r);return n??o(i)}function f(e){return typeof e==`string`&&c.test(e)}const p=Object.assign(u,{toBytes:a,fromBytes:o,isValid:f,NIL:`00000000-0000-0000-0000-000000000000`,MAX:`ffffffff-ffff-ffff-ffff-ffffffffffff`});export{t as BufferError,n as InvalidInputError,r as ParseError,i as UniqueIdError,p as uuidv4}; | ||
| //# sourceMappingURL=v4.mjs.map |
@@ -1,2 +0,2 @@ | ||
| import{n as e}from"../random-CWCVvNLb.mjs";import{BufferError as t,InvalidInputError as n,ParseError as r,UniqueIdError as i}from"../errors.mjs";import{n as a,t as o}from"../uuid-QysI8pWE.mjs";const s=/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,c=new Uint8Array(16),l={msecs:-1/0,seq:0};function u(e,r,i,a,o=0){if(e.length<16)throw new n(`UUID_RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16`);if(o<0||o+16>a.length)throw new t(`UUID_BUFFER_OUT_OF_BOUNDS`,`UUID byte range ${o}:${o+15} is out of buffer bounds`);return r??=Date.now(),i??=e[6]<<23|e[7]<<16|e[8]<<8|e[9],a[o++]=r/1099511627776&255,a[o++]=r/4294967296&255,a[o++]=r/16777216&255,a[o++]=r/65536&255,a[o++]=r/256&255,a[o++]=r&255,a[o++]=112|i>>>28&15,a[o++]=i>>>20&255,a[o++]=128|i>>>14&63,a[o++]=i>>>6&255,a[o++]=i<<2&255|e[10]&3,a[o++]=e[11],a[o++]=e[12],a[o++]=e[13],a[o++]=e[14],a[o++]=e[15],a}function d(t,n,r){let i;if(t)i=u(t.random??e(),t.msecs,t.seq,n??c,n?r:0);else{let t=Date.now(),a=e();t>l.msecs?(l.seq=a[6]<<23|a[7]<<16|a[8]<<8|a[9],l.msecs=t):(l.seq=l.seq+1|0,l.seq<0&&(l.seq=0,l.msecs++)),i=u(a,l.msecs,l.seq,n??c,n?r:0)}return n?i:o(i)}function f(e){let t=a(e),n=0;for(let e=0;e<6;e+=1)n=n*256+t[e];return n}function p(e){return typeof e==`string`&&s.test(e)}const m=Object.assign(d,{toBytes:a,fromBytes:o,timestamp:f,isValid:p,NIL:`00000000-0000-0000-0000-000000000000`,MAX:`ffffffff-ffff-ffff-ffff-ffffffffffff`});export{t as BufferError,n as InvalidInputError,r as ParseError,i as UniqueIdError,m as uuidv7}; | ||
| import{n as e}from"../random-CGMm8owG.mjs";import{BufferError as t,InvalidInputError as n,ParseError as r,UniqueIdError as i}from"../errors.mjs";import{n as a,t as o}from"../uuid-Ub6ladEr.mjs";const s=/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,c=new Uint8Array(16),l={msecs:-1/0,seq:0};function u(e,r,i,a,o=0){if(e.length<16)throw new n(`UUID_RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16`);if(o<0||o+16>a.length)throw new t(`UUID_BUFFER_OUT_OF_BOUNDS`,`UUID byte range ${o}:${o+15} is out of buffer bounds`);return r??=Date.now(),i??=e[6]<<23|e[7]<<16|e[8]<<8|e[9],a[o++]=r/1099511627776&255,a[o++]=r/4294967296&255,a[o++]=r/16777216&255,a[o++]=r/65536&255,a[o++]=r/256&255,a[o++]=r&255,a[o++]=112|i>>>28&15,a[o++]=i>>>20&255,a[o++]=128|i>>>14&63,a[o++]=i>>>6&255,a[o++]=i<<2&255|e[10]&3,a[o++]=e[11],a[o++]=e[12],a[o++]=e[13],a[o++]=e[14],a[o++]=e[15],a}function d(t,n,r){let i;if(t)i=u(t.random??e(),t.msecs,t.seq,n??c,n?r:0);else{let t=Date.now(),a=e();t>l.msecs?(l.seq=a[6]<<23|a[7]<<16|a[8]<<8|a[9],l.msecs=t):(l.seq=l.seq+1|0,l.seq<0&&(l.seq=0,l.msecs++)),i=u(a,l.msecs,l.seq,n??c,n?r:0)}return n?i:o(i)}function f(e){let t=a(e),n=0;for(let e=0;e<6;e+=1)n=n*256+t[e];return n}function p(e){return typeof e==`string`&&s.test(e)}const m=Object.assign(d,{toBytes:a,fromBytes:o,timestamp:f,isValid:p,NIL:`00000000-0000-0000-0000-000000000000`,MAX:`ffffffff-ffff-ffff-ffff-ffffffffffff`});export{t as BufferError,n as InvalidInputError,r as ParseError,i as UniqueIdError,m as uuidv7}; | ||
| //# sourceMappingURL=v7.mjs.map |
+9
-2
| { | ||
| "private": false, | ||
| "name": "uniku", | ||
| "version": "0.0.13", | ||
| "description": "Minimal, tree-shakeable UUID utilities for every JavaScript runtime", | ||
| "version": "0.1.0", | ||
| "description": "Minimal, tree-shakeable unique ID generators for every JavaScript runtime", | ||
| "author": { | ||
@@ -26,2 +26,3 @@ "name": "Alberto Schiabel", | ||
| "ulid", | ||
| "typeid", | ||
| "cuid2", | ||
@@ -74,2 +75,7 @@ "nanoid", | ||
| }, | ||
| "./typeid": { | ||
| "types": "./build/typeid/typeid.d.mts", | ||
| "import": "./build/typeid/typeid.mjs", | ||
| "default": "./build/typeid/typeid.mjs" | ||
| }, | ||
| "./cuid2": { | ||
@@ -105,2 +111,3 @@ "types": "./build/cuid2/cuid2.d.mts", | ||
| "nanoid": "^5.1.6", | ||
| "typeid-js": "1.2.0", | ||
| "ulid": "3.0.2", | ||
@@ -107,0 +114,0 @@ "uuid": "13.0.0" |
+46
-1
@@ -31,2 +31,3 @@ # uniku | ||
| | UUID v7 | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | | ||
| | TypeID | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | ||
| | ULID | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | | ||
@@ -68,2 +69,4 @@ | CUID2 | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | | ||
| | Nanoid | **~comparable speed** | | ||
| | Nanoid (10 chars) | npm is 1.1× faster | | ||
| | TypeID | **2.6× faster** | | ||
| | UUID v4 | npm is 1.1× faster | | ||
@@ -78,6 +81,8 @@ | ||
| | Database primary keys | **UUID v7** or **ULID** | Time-ordered for index efficiency | | ||
| | API/domain identifiers | **TypeID** | UUID v7 with readable type prefixes like `user_...` | | ||
| | URL shorteners | **Nanoid** | Compact, URL-safe characters | | ||
| | Prevent enumeration | **CUID2** | Non-sequential, secure | | ||
| | Maximum compatibility | **UUID v4** | Universal standard | | ||
| | Distributed systems (high entropy) | **KSUID** | 128-bit payload, second precision | | ||
| | Distributed systems needing sortable, URL-safe IDs | **ULID** | Millisecond ordering + 80-bit entropy | | ||
| | Very high-volume distributed systems | **KSUID** | Time-ordered with 128-bit entropy | | ||
@@ -104,2 +109,8 @@ ### Detailed Guide | ||
| **TypeID** — Use when API IDs should expose their entity type. | ||
| - Prefix plus 26-character UUID v7 suffix, e.g. `user_01h2xcejqtf2nbrexx3vqjhp41` | ||
| - Empty prefix support for canonical 26-character TypeIDs | ||
| - Time-ordered through UUID v7, with lowercase snake_case type prefixes | ||
| - Best for: Public API identifiers, logs, debugging, domain-specific IDs | ||
| **KSUID** — Use when you need highest collision resistance. | ||
@@ -154,2 +165,3 @@ - 27 characters, time-ordered with second precision | ||
| | ULID | 26 chars | 16 bytes | 38% | | ||
| | TypeID | prefix + 27 chars | 16 bytes | prefix-dependent | | ||
| | KSUID | 27 chars | 20 bytes | 26% | | ||
@@ -187,2 +199,3 @@ | Nanoid | 21 chars | N/A | - | | ||
| | `uniku/ulid` | ~1.8 KB | | ||
| | `uniku/typeid` | ~1.6 KB | | ||
| | `uniku/cuid2` | ~1007 B* | | ||
@@ -235,2 +248,17 @@ | `uniku/nanoid` | ~1.1 KB | | ||
| ### TypeID (prefixed UUID v7) | ||
| ```ts | ||
| import { typeid } from 'uniku/typeid' | ||
| const id = typeid('user') | ||
| // => "user_01h2xcejqtf2nbrexx3vqjhp41" | ||
| const uuid = typeid.toUuid(id) | ||
| const restored = typeid.fromUuid('user', uuid) | ||
| const canonical = typeid('') | ||
| // => "01h2xcejqtf2nbrexx3vqjhp41" | ||
| ``` | ||
| ### CUID2 (secure, non-time-ordered) | ||
@@ -371,2 +399,18 @@ | ||
| ### `typeid` (from `uniku/typeid`) | ||
| ```ts | ||
| typeid(prefix: string, options?: TypeidOptions): string | ||
| typeid.toBytes(id: string): Uint8Array | ||
| typeid.fromBytes(prefix: string, bytes: Uint8Array): string | ||
| typeid.toUuid(id: string): string | ||
| typeid.fromUuid(prefix: string, uuid: string): string | ||
| typeid.timestamp(id: string): number | ||
| typeid.prefix(id: string): string | ||
| typeid.suffix(id: string): string | ||
| typeid.isValid(id: unknown): id is string | ||
| ``` | ||
| Use an empty prefix (`typeid('')`) to generate Jetify-compatible prefixless TypeIDs. | ||
| ### `cuid2` (from `uniku/cuid2`) | ||
@@ -414,2 +458,3 @@ | ||
| - [ulid](https://github.com/ulid/javascript): the reference ULID implementation for JavaScript | ||
| - [TypeID](https://github.com/jetify-com/typeid): type-safe UUID v7 extension with readable prefixes | ||
| - [@paralleldrive/cuid2](https://github.com/paralleldrive/cuid2): secure, collision-resistant IDs | ||
@@ -416,0 +461,0 @@ - [@owpz/ksuid](https://github.com/owpz/ksuid): K-Sortable Unique Identifier |
+16
-7
@@ -13,2 +13,3 @@ import { InvalidInputError } from '../errors' | ||
| const POOL_SIZE_MULTIPLIER = 128 | ||
| const MAX_POOL_SIZE = 65_536 | ||
| let pool: Uint8Array | undefined | ||
@@ -18,3 +19,3 @@ let poolOffset = 0 | ||
| function fillPool(bytes: number): void { | ||
| const size = bytes * POOL_SIZE_MULTIPLIER | ||
| const size = Math.min(bytes * POOL_SIZE_MULTIPLIER, MAX_POOL_SIZE) | ||
| if (!pool || pool.length < size) { | ||
@@ -31,2 +32,11 @@ pool = new Uint8Array(size) | ||
| function defaultAlphabetFromPool(size: number): string { | ||
| fillPool(size) | ||
| let id = '' | ||
| for (let i = poolOffset - size; i < poolOffset; i++) { | ||
| id += URL_ALPHABET[pool![i] & 63] | ||
| } | ||
| return id | ||
| } | ||
| export type NanoidOptions = { | ||
@@ -110,8 +120,3 @@ /** | ||
| if (sizeOrOptions === undefined) { | ||
| fillPool(DEFAULT_SIZE) | ||
| let id = '' | ||
| for (let i = poolOffset - DEFAULT_SIZE; i < poolOffset; i++) { | ||
| id += URL_ALPHABET[pool![i] & 63] | ||
| } | ||
| return id | ||
| return defaultAlphabetFromPool(DEFAULT_SIZE) | ||
| } | ||
@@ -138,2 +143,6 @@ | ||
| if (alphabet === URL_ALPHABET && randomBytes === undefined) { | ||
| return defaultAlphabetFromPool(size) | ||
| } | ||
| const alphabetLen = alphabet.length | ||
@@ -140,0 +149,0 @@ |
| function e(e){for(let t=e.length-1;t>=0;--t){if(e[t]<255)return e[t]+=1,!0;e[t]=0}return!1}function t(e,t,n){e[t]=n/1099511627776&255,e[t+1]=n/4294967296&255,e[t+2]=n/16777216&255,e[t+3]=n/65536&255,e[t+4]=n/256&255,e[t+5]=n&255}function n(e,t,n){e[t]=n>>>24&255,e[t+1]=n>>>16&255,e[t+2]=n>>>8&255,e[t+3]=n&255}export{n,t as r,e as t}; | ||
| //# sourceMappingURL=bytes-NRtBOHK5.mjs.map |
| {"version":3,"file":"bytes-NRtBOHK5.mjs","names":[],"sources":["../src/common/bytes.ts"],"sourcesContent":["/**\n * Common byte manipulation utilities shared across ID generators.\n */\n\n/**\n * Increment a byte array by 1 in-place, propagating carry from LSB to MSB.\n * Mutates the input array directly - no allocation.\n *\n * Used by ULID and KSUID for monotonic ordering within the same time unit.\n *\n * @returns true if increment succeeded, false if all bytes overflowed to 0\n */\nexport function incrementBytesInPlace(bytes: Uint8Array): boolean {\n for (let i = bytes.length - 1; i >= 0; i -= 1) {\n if (bytes[i] < 255) {\n bytes[i] += 1\n return true\n }\n bytes[i] = 0\n }\n\n // All bytes overflowed to 0 - astronomically unlikely (1 in 2^80 for ULID, 1 in 2^128 for KSUID)\n return false\n}\n\n/**\n * Write a 48-bit timestamp as big-endian bytes.\n * Used by UUID v7 and ULID for millisecond-precision timestamps.\n *\n * @param buf - Target buffer\n * @param offset - Starting byte offset\n * @param msecs - Milliseconds since Unix epoch (must fit in 48 bits)\n */\nexport function writeTimestamp48(buf: Uint8Array, offset: number, msecs: number): void {\n buf[offset] = (msecs / 0x10000000000) & 0xff\n buf[offset + 1] = (msecs / 0x100000000) & 0xff\n buf[offset + 2] = (msecs / 0x1000000) & 0xff\n buf[offset + 3] = (msecs / 0x10000) & 0xff\n buf[offset + 4] = (msecs / 0x100) & 0xff\n buf[offset + 5] = msecs & 0xff\n}\n\n/**\n * Write a 32-bit timestamp as big-endian bytes.\n * Used by KSUID for second-precision timestamps.\n *\n * `writeTimestamp32(buf, offset, timestamp)` is equivalent to `new DataView(buf.buffer, offset, 4).setUint32(offset, timestamp, false)`,\n * but it's faster because it doesn't require creating a DataView object.\n *\n * @param buf - Target buffer\n * @param offset - Starting byte offset\n * @param secs - Seconds (must fit in 32 bits)\n */\nexport function writeTimestamp32(buf: Uint8Array, offset: number, secs: number): void {\n buf[offset] = (secs >>> 24) & 0xff\n buf[offset + 1] = (secs >>> 16) & 0xff\n buf[offset + 2] = (secs >>> 8) & 0xff\n buf[offset + 3] = secs & 0xff\n}\n"],"mappings":"AAYA,SAAgB,EAAsB,EAA4B,CAChE,IAAK,IAAI,EAAI,EAAM,OAAS,EAAG,GAAK,EAAG,IAAQ,CAC7C,GAAI,EAAM,GAAK,IAEb,MADA,GAAM,IAAM,EACL,GAET,EAAM,GAAK,EAIb,MAAO,GAWT,SAAgB,EAAiB,EAAiB,EAAgB,EAAqB,CACrF,EAAI,GAAW,EAAQ,cAAiB,IACxC,EAAI,EAAS,GAAM,EAAQ,WAAe,IAC1C,EAAI,EAAS,GAAM,EAAQ,SAAa,IACxC,EAAI,EAAS,GAAM,EAAQ,MAAW,IACtC,EAAI,EAAS,GAAM,EAAQ,IAAS,IACpC,EAAI,EAAS,GAAK,EAAQ,IAc5B,SAAgB,EAAiB,EAAiB,EAAgB,EAAoB,CACpF,EAAI,GAAW,IAAS,GAAM,IAC9B,EAAI,EAAS,GAAM,IAAS,GAAM,IAClC,EAAI,EAAS,GAAM,IAAS,EAAK,IACjC,EAAI,EAAS,GAAK,EAAO"} |
| const e=globalThis.crypto.getRandomValues.bind(globalThis.crypto),t=new Uint8Array(256);let n=256;function r(){e(t),n=0}function i(){n>252&&r();let e=t[n]*16777216+t[n+1]*65536+t[n+2]*256+t[n+3]>>>0;return n+=4,e}function a(){n>240&&r();let e=n;return n+=16,t.subarray(e,n)}export{a as n,i as t}; | ||
| //# sourceMappingURL=random-CWCVvNLb.mjs.map |
| {"version":3,"file":"random-CWCVvNLb.mjs","names":[],"sources":["../src/common/random.ts"],"sourcesContent":["const randomFill = /*@__PURE__*/ globalThis.crypto.getRandomValues.bind(globalThis.crypto)\n\n/**\n * Simple random byte pool for ID generation.\n *\n * Module-level state is per JavaScript isolate, so SharedArrayBuffer and Atomics\n * only add overhead here. Returned views are consumed synchronously by callers.\n */\n\nconst POOL_SIZE = 256\nconst pool = new Uint8Array(POOL_SIZE)\nlet poolOffset = POOL_SIZE\n\nfunction refillPool(): void {\n randomFill(pool)\n poolOffset = 0\n}\n\n/**\n * Return a view of `count` random bytes from the pool.\n */\nexport function randomBytes(count: number): Uint8Array {\n if (count > POOL_SIZE) {\n return randomFill(new Uint8Array(count))\n }\n\n if (poolOffset + count > POOL_SIZE) {\n refillPool()\n }\n\n const start = poolOffset\n poolOffset += count\n return pool.subarray(start, poolOffset)\n}\n\n/**\n * Generate a random unsigned 32-bit integer from the shared pool.\n */\nexport function randomUint32(): number {\n if (poolOffset > POOL_SIZE - 4) {\n refillPool()\n }\n\n const value =\n (pool[poolOffset] * 0x1000000 +\n pool[poolOffset + 1] * 0x10000 +\n pool[poolOffset + 2] * 0x100 +\n pool[poolOffset + 3]) >>>\n 0\n poolOffset += 4\n return value\n}\n\n/**\n * Generate 16 bytes of cryptographically strong random data.\n * Uses a pre-filled pool to minimize crypto API calls.\n */\nexport function rng(): Uint8Array {\n if (poolOffset > POOL_SIZE - 16) {\n refillPool()\n }\n\n const start = poolOffset\n poolOffset += 16\n return pool.subarray(start, poolOffset)\n}\n"],"mappings":"AAAA,MAAM,EAA2B,WAAW,OAAO,gBAAgB,KAAK,WAAW,OAAO,CAUpF,EAAO,IAAI,WAAW,IAAU,CACtC,IAAI,EAAa,IAEjB,SAAS,GAAmB,CAC1B,EAAW,EAAK,CAChB,EAAa,EAuBf,SAAgB,GAAuB,CACjC,EAAa,KACf,GAAY,CAGd,IAAM,EACH,EAAK,GAAc,SAClB,EAAK,EAAa,GAAK,MACvB,EAAK,EAAa,GAAK,IACvB,EAAK,EAAa,KACpB,EAEF,MADA,IAAc,EACP,EAOT,SAAgB,GAAkB,CAC5B,EAAa,KACf,GAAY,CAGd,IAAM,EAAQ,EAEd,MADA,IAAc,GACP,EAAK,SAAS,EAAO,EAAW"} |
| import{ParseError as e}from"./errors.mjs";function t(e){return e>=48&&e<=57?e-48:e>=65&&e<=70?e-65+10:e>=97&&e<=102?e-97+10:-1}const n=[0,0,1,1,2,2,3,3,-1,4,4,5,5,-1,6,6,7,7,-1,8,8,9,9,-1,10,10,11,11,12,12,13,13,14,14,15,15],r=[!0,!1,!0,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!1,!0,!1,!0,!1,!0,!1,!0,!1,!0,!1,!0,!1],i=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`));function a(e){return i[e[0]]+i[e[1]]+i[e[2]]+i[e[3]]+`-`+i[e[4]]+i[e[5]]+`-`+i[e[6]]+i[e[7]]+`-`+i[e[8]]+i[e[9]]+`-`+i[e[10]]+i[e[11]]+i[e[12]]+i[e[13]]+i[e[14]]+i[e[15]]}function o(i){if(i.length!==36)throw new e(`UUID_INVALID_LENGTH`,`UUID string must be 36 characters, got ${i.length}`);if(i[8]!==`-`||i[13]!==`-`||i[18]!==`-`||i[23]!==`-`)throw new e(`UUID_INVALID_SEPARATORS`,`UUID string has invalid separators at positions 8, 13, 18, 23. Received: "${i}"`);let a=new Uint8Array(16);for(let o=0;o<36;o+=1){let s=n[o];if(s===-1)continue;let c=t(i.charCodeAt(o));if(c===-1)throw new e(`UUID_INVALID_HEX_CHAR`,`UUID string contains invalid hex character at position ${o}`);r[o]?a[s]=c<<4:a[s]|=c}return a}export{o as n,a as t}; | ||
| //# sourceMappingURL=uuid-QysI8pWE.mjs.map |
| {"version":3,"file":"uuid-QysI8pWE.mjs","names":["UUID_CHAR_TO_BYTE: number[]","UUID_CHAR_IS_HIGH: boolean[]","HEX_TABLE: string[]"],"sources":["../src/uuid/common/hex.ts","../src/uuid/common/uuid.ts"],"sourcesContent":["// ASCII code ranges for hex character validation\nconst ASCII_0 = 48 // '0'\nconst ASCII_9 = 57 // '9'\nconst ASCII_A = 65 // 'A'\nconst ASCII_F = 70 // 'F'\nconst ASCII_a = 97 // 'a'\nconst ASCII_f = 102 // 'f'\n\n/**\n * Convert a hex character ASCII code to its numeric value (0-15).\n * Returns -1 for invalid hex characters.\n */\nexport function hexValue(code: number): number {\n if (code >= ASCII_0 && code <= ASCII_9) {\n return code - ASCII_0\n }\n if (code >= ASCII_A && code <= ASCII_F) {\n return code - ASCII_A + 10\n }\n if (code >= ASCII_a && code <= ASCII_f) {\n return code - ASCII_a + 10\n }\n return -1 // Invalid hex character\n}\n","import { ParseError } from '../../errors'\nimport { hexValue } from './hex'\n\nconst UUID_BYTE_LENGTH = 16\nconst UUID_STRING_LENGTH = 36\n\n// Mapping from UUID string position to byte index.\n// -1 indicates a dash position that should be skipped.\n// This avoids intermediate string allocations during parsing.\nconst UUID_CHAR_TO_BYTE: number[] = [\n 0,\n 0,\n 1,\n 1,\n 2,\n 2,\n 3,\n 3, // chars 0-7 → bytes 0-3\n -1, // char 8 is '-'\n 4,\n 4,\n 5,\n 5, // chars 9-12 → bytes 4-5\n -1, // char 13 is '-'\n 6,\n 6,\n 7,\n 7, // chars 14-17 → bytes 6-7\n -1, // char 18 is '-'\n 8,\n 8,\n 9,\n 9, // chars 19-22 → bytes 8-9\n -1, // char 23 is '-'\n 10,\n 10,\n 11,\n 11,\n 12,\n 12,\n 13,\n 13,\n 14,\n 14,\n 15,\n 15, // chars 24-35 → bytes 10-15\n]\n\n// Whether each position is the high nibble (true) or low nibble (false)\nconst UUID_CHAR_IS_HIGH: boolean[] = [\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false, // chars 0-7\n false, // dash (ignored)\n true,\n false,\n true,\n false, // chars 9-12\n false, // dash\n true,\n false,\n true,\n false, // chars 14-17\n false, // dash\n true,\n false,\n true,\n false, // chars 19-22\n false, // dash\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false,\n true,\n false, // chars 24-35\n]\n\n// Pre-computed lookup table for byte-to-hex conversion (0x00 -> \"00\", 0xff -> \"ff\")\n//\n// Note: this table must remain defined in the same module as `formatUuid`, otherwise the v8 optimizer\n// will cause a performance drop of ~36%.\nconst HEX_TABLE: string[] = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'))\n\nexport function formatUuid(bytes: Uint8Array): string {\n // Direct string concatenation - optimized for V8's string builder.\n // This approach avoids loop overhead and intermediate allocations.\n // See: https://github.com/uuidjs/uuid/pull/434\n return (\n HEX_TABLE[bytes[0]] +\n HEX_TABLE[bytes[1]] +\n HEX_TABLE[bytes[2]] +\n HEX_TABLE[bytes[3]] +\n '-' +\n HEX_TABLE[bytes[4]] +\n HEX_TABLE[bytes[5]] +\n '-' +\n HEX_TABLE[bytes[6]] +\n HEX_TABLE[bytes[7]] +\n '-' +\n HEX_TABLE[bytes[8]] +\n HEX_TABLE[bytes[9]] +\n '-' +\n HEX_TABLE[bytes[10]] +\n HEX_TABLE[bytes[11]] +\n HEX_TABLE[bytes[12]] +\n HEX_TABLE[bytes[13]] +\n HEX_TABLE[bytes[14]] +\n HEX_TABLE[bytes[15]]\n )\n}\n\nexport function parseUuid(value: string): Uint8Array {\n if (value.length !== UUID_STRING_LENGTH) {\n throw new ParseError('UUID_INVALID_LENGTH', `UUID string must be 36 characters, got ${value.length}`)\n }\n\n // Validate separator positions directly (more efficient than full loop)\n if (value[8] !== '-' || value[13] !== '-' || value[18] !== '-' || value[23] !== '-') {\n throw new ParseError(\n 'UUID_INVALID_SEPARATORS',\n `UUID string has invalid separators at positions 8, 13, 18, 23. Received: \"${value}\"`,\n )\n }\n\n // Parse bytes directly from UUID string without intermediate string allocations.\n // This avoids the 9 allocations (5 slices + 4 concatenations) of the naive approach.\n const bytes = new Uint8Array(UUID_BYTE_LENGTH)\n\n for (let i = 0; i < UUID_STRING_LENGTH; i += 1) {\n const byteIdx = UUID_CHAR_TO_BYTE[i]\n if (byteIdx === -1) continue // Skip dash positions\n\n const nibble = hexValue(value.charCodeAt(i))\n if (nibble === -1) {\n throw new ParseError('UUID_INVALID_HEX_CHAR', `UUID string contains invalid hex character at position ${i}`)\n }\n\n if (UUID_CHAR_IS_HIGH[i]) {\n bytes[byteIdx] = nibble << 4\n } else {\n bytes[byteIdx] |= nibble\n }\n }\n\n return bytes\n}\n"],"mappings":"0CAYA,SAAgB,EAAS,EAAsB,CAU7C,OATI,GAAQ,IAAW,GAAQ,GACtB,EAAO,GAEZ,GAAQ,IAAW,GAAQ,GACtB,EAAO,GAAU,GAEtB,GAAQ,IAAW,GAAQ,IACtB,EAAO,GAAU,GAEnB,GCnBT,MAMMA,EAA8B,CAClC,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,EACA,EACA,EACA,EACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACD,CAGKC,EAA+B,CACnC,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACD,CAMKC,EAAsB,MAAM,KAAK,CAAE,OAAQ,IAAK,EAAG,EAAG,IAAM,EAAE,SAAS,GAAG,CAAC,SAAS,EAAG,IAAI,CAAC,CAElG,SAAgB,EAAW,EAA2B,CAIpD,OACE,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,IAChB,EAAU,EAAM,IAChB,IACA,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAChB,EAAU,EAAM,KAIpB,SAAgB,EAAU,EAA2B,CACnD,GAAI,EAAM,SAAW,GACnB,MAAM,IAAI,EAAW,sBAAuB,0CAA0C,EAAM,SAAS,CAIvG,GAAI,EAAM,KAAO,KAAO,EAAM,MAAQ,KAAO,EAAM,MAAQ,KAAO,EAAM,MAAQ,IAC9E,MAAM,IAAI,EACR,0BACA,6EAA6E,EAAM,GACpF,CAKH,IAAM,EAAQ,IAAI,WAAW,GAAiB,CAE9C,IAAK,IAAI,EAAI,EAAG,EAAI,GAAoB,GAAK,EAAG,CAC9C,IAAM,EAAU,EAAkB,GAClC,GAAI,IAAY,GAAI,SAEpB,IAAM,EAAS,EAAS,EAAM,WAAW,EAAE,CAAC,CAC5C,GAAI,IAAW,GACb,MAAM,IAAI,EAAW,wBAAyB,0DAA0D,IAAI,CAG1G,EAAkB,GACpB,EAAM,GAAW,GAAU,EAE3B,EAAM,IAAY,EAItB,OAAO"} |
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 2 instances
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 2 instances
305767
75.24%56
12%1959
15.1%469
10.61%0
-100%7
16.67%12
9.09%