{"_id":"@codician-team/coid","name":"@codician-team/coid","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@codician-team/coid","version":"1.0.0","description":"128-bit lexicographically sortable, human-readable identifiers.","type":"module","license":"MIT","author":{"name":"Codician"},"repository":{"type":"git","url":"git+https://github.com/codician-team/coid.git"},"bugs":{"url":"https://github.com/codician-team/coid/issues"},"homepage":"https://github.com/codician-team/coid#readme","sideEffects":false,"engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"module":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"tsc","bench":"npm install --prefix bench --silent && npm run build --silent && node bench/runtime.node.mjs","test":"npm run build --silent && node --test test/coid.test.mjs","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test"},"devDependencies":{"@types/node":"^24.0.0","typescript":"^5.8.3"},"keywords":["id","uuid","uuidv7","ulid","sortable","identifier"],"gitHead":"fe3b54aa106af96791272cf3706af14c260ae6ed","_id":"@codician-team/coid@1.0.0","_nodeVersion":"24.17.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-2q4NdcoK8smXn0mpr40aPm/FD/4WDEWg1ENDD6zlsiGBG8zL0toblK+t9IZAaGX+qZMfjO5aaUasCXyXqKBqfQ==","shasum":"35d4b7e26e9f0dfda2459ea051c184f8df4dcb6b","tarball":"https://registry.npmjs.org/@codician-team/coid/-/coid-1.0.0.tgz","fileCount":7,"unpackedSize":38726,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICNHVfq1z5zkcb4EbcSEQBISaUf2d4jhlqllqZ2Q11+pAiAIVOY5DzajKQbVW9T+7xELPaqrvDKKHrqWVRHMgu0VHg=="}]},"_npmUser":{"name":"codician-team","email":"altug.ankarali@icloud.com"},"directories":{},"maintainers":[{"name":"codician-team","email":"altug.ankarali@icloud.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/coid_1.0.0_1781935438344_0.835500511184091"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-20T06:03:58.230Z","1.0.0":"2026-06-20T06:03:58.482Z","modified":"2026-06-20T06:03:58.708Z"},"maintainers":[{"name":"codician-team","email":"altug.ankarali@icloud.com"}],"description":"128-bit lexicographically sortable, human-readable identifiers.","homepage":"https://github.com/codician-team/coid#readme","keywords":["id","uuid","uuidv7","ulid","sortable","identifier"],"repository":{"type":"git","url":"git+https://github.com/codician-team/coid.git"},"author":{"name":"Codician"},"bugs":{"url":"https://github.com/codician-team/coid/issues"},"license":"MIT","readme":"# coid\n\n`coid` is basically **UUIDv7 for humans**: a 128-bit, UUID-shaped identifier that\nsorts chronologically in database indexes, but starts with a UTC timestamp you\ncan read without decoding.\n\nUse it where you'd reach for UUIDv7/ULID, but still want IDs that explain\nthemselves in logs, URLs, support tickets, and database rows — coordination-free,\nno machine IDs, and a full **64-bit cryptographic random tail**.\n\n```ts\nimport { coid, parseCoid } from \"@codician-team/coid\";\n\nconst id = coid();\n// 26061912-5549-9998-a1b2-c3d4e5f60718\n\nparseCoid(id).date.toISOString();\n// 2026-06-19T12:55:49.999Z\n```\n\nWith UUIDv7 you get sortable time. With `coid`, you get sortable time you can\nread:\n\n```text\ncoid    26061912-5549-9998-a1b2-c3d4e5f60718  -> 2026-06-19 12:55:49.999 UTC\nuuidv7  01978f77-dbcf-7a50-9f9a-8c0f0d8f8b4a  -> decode it first\n```\n\n## Install\n\n```sh\nnpm install @codician-team/coid\n```\n\nNode.js 20+, ESM-only. No runtime dependencies.\n\n## The format\n\n```text\n26061912-5549-9998-a1b2-c3d4e5f60718\nYYMMDDHH-mmss-MMMx-rrrr-rrrrrrrrrrrr\ndate    time  ms │ random tail\n                 └ sub-ms fraction (1/16 ms)\n```\n\n| Group | Meaning | Encoding |\n|-------|---------|----------|\n| `YYMMDDHH` | year (`20xx`), month, day, hour | decimal, UTC |\n| `mmss` | minute, second | decimal |\n| `MMM` | millisecond (`000`–`999`) | decimal |\n| `x` | sub-millisecond fraction (1/16 ms ≈ 62.5 µs), clock-derived | hex |\n| group 4 + 5 | 64-bit cryptographic random | hex |\n\nThe entire left half is plain decimal, so `26061912-5549-999` reads directly as\n`2026-06-19 12:55:49.999`. Comparing two coids as strings orders them by time,\nthen the sub-ms fraction, then random — the same order PostgreSQL gives a `UUID`\ncolumn, so they're a drop-in sortable key. The sub-ms nibble follows PostgreSQL\n18's `uuidv7()` approach (extra clock precision). See [`SPEC.md`](./SPEC.md) for\nthe bit layout, collision analysis, and sorting guarantees.\n\n> Years are two digits: coid covers UTC **2000–2099**. Generating outside that\n> range throws.\n\n## Usage\n\n```ts\nimport { coid, isCoid, parseCoid, assertCoid } from \"@codician-team/coid\";\n\ncoid();                              // now\ncoid(new Date(\"2030-01-01T00:00Z\")); // a specific UTC instant\n\nisCoid(\"not-an-id\");                 // false (also rejects impossible dates like Feb 30)\nassertCoid(value);                   // throws CoidError if invalid, else narrows to Coid\n\nconst p = parseCoid(id);\np.date; p.year; p.month; /* … */ p.fraction; p.random; // fraction: 0–15, random: bigint\n```\n\n### Independent generators\n\nThe module-level `coid()` shares one default generator. To inject a clock or\nrandom source (handy in tests or custom runtimes), create your own:\n\n```ts\nimport { createCoidGenerator } from \"@codician-team/coid\";\n\nconst gen = createCoidGenerator({\n  now: () => performance.timeOrigin + performance.now(), // fractional Unix ms\n  randomBytes: (b) => crypto.getRandomValues(b)          // CSPRNG (e.g. Web Crypto)\n});\n\ngen.generate();\n```\n\n## API\n\n| Export | Returns | Notes |\n|--------|---------|-------|\n| `coid(date?)` | `Coid` | Generate from the shared default generator. |\n| `createCoidGenerator(options?)` | `CoidGenerator` | Independent generator. |\n| `CoidGenerator#generate(date?)` | `Coid` | Generate the next id. |\n| `parseCoid(value)` | `ParsedCoid` | Decode all fields. Throws on invalid. |\n| `isCoid(value)` | `value is Coid` | Type guard; calendar-validated. |\n| `assertCoid(value)` | `asserts … is Coid` | Throws `CoidError` if invalid. |\n| `dateFromCoid(value)` | `Date` | Shorthand accessor. |\n| `randomFromCoid(value)` | `bigint` | Shorthand accessor (64-bit). |\n| `CoidError` | — | Thrown for malformed/impossible input. |\n\nParsing is case-insensitive; output is always canonical. Validation is exact — a\nstring must name a real UTC instant in 2000–2099, not merely match the shape.\n\n## Performance\n\nThe engine is one inlined clock read, a per-ms timestamp cache, one draw from a\nbatched CSPRNG pool, written into a reused scratch buffer and decoded once. The\nbundled benchmark pits `coid()` against its direct peers (the **real npm\npackages** for IDs that are both **128-bit / fit a PostgreSQL `UUID` column** and\n**time-sortable**):\n\n```text\n$ npm run bench                      # Node 24, Apple Silicon — indicative\ncoid()                  ~21M ops/sec   1.00x   ms time + sub-ms + 64b random\ncoid() web APIs         ~16M ops/sec   0.73x   injected Web Performance + Web Crypto\nuuidv7                  ~3.4M ops/sec   0.16x   ms time + counter/rand (uuidv7)\nulid                    ~3.2M ops/sec   0.15x   ms time + 80b random (ulid)\nuuid v6                 ~1.3M ops/sec   0.06x   reordered-v1 time (uuid)\n```\n\nEvery competitor is the actual published library, called through its recommended\nAPI. They live in `bench/`'s own `package.json`, so the package itself ships\nwith **zero dependencies** and none reach consumers. Run `npm run bench` on your\nown hardware for real numbers (it installs the bench deps on first run).\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-3e5b48420a8aa655f1331518ad87d34d"}