@smonn/ids 0.12.3 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +42 -32
  2. package/dist/{adapter-types-CdYJM6Sf.d.mts → adapter-types-CIc-4O-P.d.mts} +2 -2
  3. package/dist/{adapter-types-CdYJM6Sf.d.mts.map → adapter-types-CIc-4O-P.d.mts.map} +1 -1
  4. package/dist/cli.mjs +316 -178
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/{codec-shell-DvrTDa65.mjs → codec-shell-C2NKQEx2.mjs} +5 -1
  7. package/dist/codec-shell-C2NKQEx2.mjs.map +1 -0
  8. package/dist/{digest-CknNw2wa.mjs → digest-DsGeXfk3.mjs} +9 -24
  9. package/dist/digest-DsGeXfk3.mjs.map +1 -0
  10. package/dist/digest.d.mts +3 -3
  11. package/dist/digest.d.mts.map +1 -1
  12. package/dist/digest.mjs +1 -1
  13. package/dist/drizzle.d.mts +3 -3
  14. package/dist/drizzle.d.mts.map +1 -1
  15. package/dist/drizzle.mjs.map +1 -1
  16. package/dist/error-Cp5qYZcv.mjs.map +1 -1
  17. package/dist/{error-JIPylU_E.d.mts → error-Dqyho9vp.d.mts} +7 -2
  18. package/dist/error-Dqyho9vp.d.mts.map +1 -0
  19. package/dist/express.d.mts +2 -2
  20. package/dist/fastify.d.mts +2 -2
  21. package/dist/graphql.d.mts +3 -3
  22. package/dist/graphql.mjs +2 -2
  23. package/dist/graphql.mjs.map +1 -1
  24. package/dist/hono.d.mts +2 -2
  25. package/dist/hono.mjs +1 -2
  26. package/dist/hono.mjs.map +1 -1
  27. package/dist/index.d.mts +21 -5
  28. package/dist/index.d.mts.map +1 -1
  29. package/dist/index.mjs +1 -1
  30. package/dist/{key-material-f29JIyrz.mjs → key-material-DvjACe89.mjs} +53 -2
  31. package/dist/key-material-DvjACe89.mjs.map +1 -0
  32. package/dist/kysely.d.mts +3 -3
  33. package/dist/kysely.d.mts.map +1 -1
  34. package/dist/kysely.mjs.map +1 -1
  35. package/dist/mikro-orm.d.mts +3 -3
  36. package/dist/mikro-orm.d.mts.map +1 -1
  37. package/dist/mikro-orm.mjs.map +1 -1
  38. package/dist/nestjs.d.mts +2 -2
  39. package/dist/nestjs.mjs +1 -1
  40. package/dist/nestjs.mjs.map +1 -1
  41. package/dist/{opaque-BQVNoIIh.mjs → opaque-BW3Uzeeb.mjs} +5 -28
  42. package/dist/opaque-BW3Uzeeb.mjs.map +1 -0
  43. package/dist/opaque.d.mts +22 -4
  44. package/dist/opaque.d.mts.map +1 -1
  45. package/dist/opaque.mjs +1 -1
  46. package/dist/prisma.d.mts +32 -27
  47. package/dist/prisma.d.mts.map +1 -1
  48. package/dist/prisma.mjs +11 -15
  49. package/dist/prisma.mjs.map +1 -1
  50. package/dist/{reverse-DsPd7Lco.mjs → reverse-BW8g_cln.mjs} +12 -5
  51. package/dist/reverse-BW8g_cln.mjs.map +1 -0
  52. package/dist/reverse.d.mts +20 -4
  53. package/dist/reverse.d.mts.map +1 -1
  54. package/dist/reverse.mjs +1 -1
  55. package/dist/{rng-Clos6uC0.mjs → rng-BHFxX1Fc.mjs} +2 -2
  56. package/dist/{rng-Clos6uC0.mjs.map → rng-BHFxX1Fc.mjs.map} +1 -1
  57. package/dist/{signed-4h2BnlWx.mjs → signed-BTz3ZFYE.mjs} +12 -33
  58. package/dist/signed-BTz3ZFYE.mjs.map +1 -0
  59. package/dist/signed.d.mts +13 -4
  60. package/dist/signed.d.mts.map +1 -1
  61. package/dist/signed.mjs +1 -1
  62. package/dist/{timestamp-Cg9nRfnK.mjs → timestamp-CleAIdZI.mjs} +12 -5
  63. package/dist/timestamp-CleAIdZI.mjs.map +1 -0
  64. package/dist/typeorm.d.mts +2 -2
  65. package/dist/typeorm.d.mts.map +1 -1
  66. package/dist/typeorm.mjs.map +1 -1
  67. package/dist/{types-g7CiQDyE.d.mts → types-wplmOgOK.d.mts} +20 -3
  68. package/dist/types-wplmOgOK.d.mts.map +1 -0
  69. package/dist/{wrapped-BQ-lNECo.mjs → wrapped-DPlsv1x-.mjs} +18 -76
  70. package/dist/wrapped-DPlsv1x-.mjs.map +1 -0
  71. package/dist/wrapped.d.mts +31 -5
  72. package/dist/wrapped.d.mts.map +1 -1
  73. package/dist/wrapped.mjs +1 -1
  74. package/package.json +80 -27
  75. package/dist/codec-shell-DvrTDa65.mjs.map +0 -1
  76. package/dist/digest-CknNw2wa.mjs.map +0 -1
  77. package/dist/error-JIPylU_E.d.mts.map +0 -1
  78. package/dist/key-material-f29JIyrz.mjs.map +0 -1
  79. package/dist/opaque-BQVNoIIh.mjs.map +0 -1
  80. package/dist/reverse-DsPd7Lco.mjs.map +0 -1
  81. package/dist/signed-4h2BnlWx.mjs.map +0 -1
  82. package/dist/timestamp-Cg9nRfnK.mjs.map +0 -1
  83. package/dist/types-g7CiQDyE.d.mts.map +0 -1
  84. package/dist/wrapped-BQ-lNECo.mjs.map +0 -1
package/README.md CHANGED
@@ -8,10 +8,7 @@ Public-facing branded IDs for TypeScript apps. Type-safe, sortable, and codec-pl
8
8
  pnpm add @smonn/ids
9
9
  ```
10
10
 
11
- Each ID looks like `usr_01h7b3k9rqxn4cw3p9r8t2sgkw`: a three-letter brand, an
12
- underscore, then 26 Crockford base32 characters of payload. The default
13
- Timestamp codec encodes a 48-bit millisecond Unix timestamp followed by 80
14
- random bits — the same byte layout as a [ULID](https://github.com/ulid/spec).
11
+ Each ID looks like `usr_01h7b3k9rqxn4cw3p9r8t2sgkw`: a three-letter brand, an underscore, then 26 Crockford base32 characters of payload. The default Timestamp codec encodes a 48-bit millisecond Unix timestamp followed by 80 random bits — the same byte layout as a [ULID](https://github.com/ulid/spec).
15
12
 
16
13
  ## Quickstart
17
14
 
@@ -35,26 +32,22 @@ if (r.ok) {
35
32
  }
36
33
  ```
37
34
 
38
- `safeParse` accepts mixed case and the Crockford visual aliases (`o → 0`,
39
- `i → 1`, `l → 1`) and always returns the canonical lowercase form. See the
40
- [Timestamp codec guide](https://ids.smonn.se/codecs/timestamp/) for sorting,
41
- backfills (`generateAt`), range queries, structured errors, Standard Schema, and
42
- JSON Schema.
35
+ `safeParse` accepts mixed case and the Crockford visual aliases (`o → 0`, `i → 1`, `l → 1`) and always returns the canonical lowercase form. See the [Timestamp codec guide](https://ids.smonn.se/codecs/timestamp/) for sorting, backfills (`generateAt`), range queries, structured errors, Standard Schema, and JSON Schema.
43
36
 
44
37
  ## Choosing a codec
45
38
 
46
- All six codecs share the same `<brand>_<26 chars>` wire shape but make different
47
- trade-offs. They are wire-indistinguishable, so codec choice is a per-brand
48
- commitment.
39
+ All six codecs share the same `<brand>_<26 chars>` wire shape but make different trade-offs. They are wire-indistinguishable — `safeParse`, `is`, and `parse` cannot distinguish an Opaque Timestamp ID from a Timestamp ID at runtime. Cross-codec confusion is undetectable by the library; the consumer is responsible for routing a given ID to the correct codec for the brand. Codec choice is therefore a per-brand commitment.
49
40
 
50
- | Codec | Import | Sort direction | Key required | Timestamp extractable |
51
- | ----------------- | -------------------- | ------------------------- | ------------------ | -------------------------- |
52
- | Timestamp | `@smonn/ids` | Ascending (oldest-first) | No | Always (plaintext) |
53
- | Reverse Timestamp | `@smonn/ids/reverse` | Descending (newest-first) | No | Always (plaintext) |
54
- | Signed Timestamp | `@smonn/ids/signed` | Ascending (oldest-first) | Yes (signing key) | Always (plaintext) |
55
- | Opaque Timestamp | `@smonn/ids/opaque` | None (encrypted) | Yes (AES key) | With key only |
56
- | Wrapped key | `@smonn/ids/wrapped` | None | Yes (wrapping key) | N/A — not timestamp-family |
57
- | Digest | `@smonn/ids/digest` | None | Yes (digest key) | N/A — not timestamp-family |
41
+ | Codec | Import | Sort direction | Key required | Timestamp extractable |
42
+ | --- | --- | --- | --- | --- |
43
+ | Timestamp | `@smonn/ids` | Ascending (oldest-first) | No | Always (plaintext) |
44
+ | Reverse Timestamp | `@smonn/ids/reverse` | Descending (newest-first) | No | Always (plaintext) |
45
+ | Signed Timestamp | `@smonn/ids/signed` | Ascending (oldest-first) | Yes (signing key) | Always (plaintext) |
46
+ | Opaque Timestamp | `@smonn/ids/opaque` | None (encrypted) | Yes (AES key) | With key only |
47
+ | Wrapped key | `@smonn/ids/wrapped` | None | Yes (wrapping key) | N/A — not timestamp-family |
48
+ | Digest | `@smonn/ids/digest` | None | Yes (digest key) | N/A — not timestamp-family |
49
+
50
+ The Timestamp codec is the default and ships from the root `@smonn/ids` entry — it has no `/timestamp` subpath by design. If you try `import ... from "@smonn/ids/timestamp"` you will get a module-resolution error; use `@smonn/ids` directly. Every other codec uses a named subpath (`/reverse`, `/signed`, `/opaque`, `/wrapped`, `/digest`); this asymmetry is intentional and permanent.
58
51
 
59
52
  - **Newest-first scans** on forward-only KV stores → [Reverse Timestamp](https://ids.smonn.se/codecs/reverse/)
60
53
  - **Tamper-evident share links** verified without a DB lookup → [Signed Timestamp](https://ids.smonn.se/codecs/signed/) (integrity)
@@ -66,28 +59,45 @@ Try them all live in the [playground](https://ids.smonn.se/playground/).
66
59
 
67
60
  ## Integrations
68
61
 
69
- Framework and ORM adapters ship as optional subpath exports (each requires its
70
- own peer dependency):
62
+ Framework and ORM adapters ship as optional subpath exports (each requires its own peer dependency):
71
63
 
72
64
  - **HTTP route params:** [Hono](https://ids.smonn.se/adapters/hono/), [Express](https://ids.smonn.se/adapters/express/), [Fastify](https://ids.smonn.se/adapters/fastify/) — `idParam` middleware; [NestJS](https://ids.smonn.se/adapters/nestjs/) — `ParseIdPipe`
73
65
  - **ORM columns:** [Drizzle](https://ids.smonn.se/adapters/drizzle/) — `idColumn`, [Kysely](https://ids.smonn.se/adapters/kysely/) — `idColumn`, [MikroORM](https://ids.smonn.se/adapters/mikro-orm/) — `idType`, [Prisma](https://ids.smonn.se/adapters/prisma/) — `idField`, [TypeORM](https://ids.smonn.se/adapters/typeorm/) — `idTransformer`
74
66
  - **GraphQL:** [GraphQL](https://ids.smonn.se/adapters/graphql/) — `idScalar` custom scalar
75
67
  - **CLI:** brand-agnostic `inspect` / `generate` / `keygen` — `npx @smonn/ids --help` ([docs](https://ids.smonn.se/cli/))
76
68
 
77
- Every codec also implements [Standard Schema v1](https://standardschema.dev/), so
78
- it slots into Zod, Valibot, ArkType, tRPC, and any validator-aware library.
69
+ Every codec also implements [Standard Schema v1](https://standardschema.dev/), so it slots into Zod, Valibot, ArkType, tRPC, and any validator-aware library.
79
70
 
80
71
  ## What this is **not** for
81
72
 
82
- - **Internal surrogate primary keys.** If nobody outside your service sees the
83
- ID, the brand prefix and lenient parsing are dead weight. Use a `bigint`
84
- sequence.
85
- - **Wire-compatible ULIDs.** The byte layout is ULID-shaped, but the encoding is
86
- lowercase and brand-wrapped. Stock ULID parsers will reject these.
73
+ - **Internal surrogate primary keys.** If nobody outside your service sees the ID, the brand prefix and lenient parsing are dead weight. Use a `bigint` sequence.
74
+ - **Wire-compatible ULIDs.** The byte layout is ULID-shaped, but the encoding is lowercase and brand-wrapped. Stock ULID parsers will reject these.
87
75
  - **Distributed-trace / request-correlation IDs.** Use OpenTelemetry-format IDs.
88
- - **Hiding creation time with the Timestamp codec.** Anyone with one ID at a
89
- known creation time can compute the epoch offset. Use the Opaque Timestamp
90
- codec to hide creation time per-ID.
76
+ - **Hiding creation time with the Timestamp codec.** Anyone with one ID at a known creation time can compute the epoch offset. Use the Opaque Timestamp codec to hide creation time per-ID.
77
+
78
+ ## API surface
79
+
80
+ Exports from the main `@smonn/ids` entry point only. Codec-specific subpath exports (`@smonn/ids/reverse`, `@smonn/ids/opaque`, `@smonn/ids/signed`, `@smonn/ids/wrapped`, `@smonn/ids/digest`) and adapter subpaths are not listed here.
81
+
82
+ ### Types
83
+
84
+ - `Id<Brand>` — Canonical branded ID string for `Brand`; produced by `generate()` and `safeParse()`.
85
+ - `ParseError` — Parse failure reason string (`"not_string"`, `"invalid_prefix"`, or `"invalid_base32"`) returned by `safeParse()`.
86
+ - `ParseResult<Brand>` — Discriminated union returned by `safeParse()`: `{ ok: true; id: Id<Brand> }` or `{ ok: false; error: ParseError }`.
87
+ - `JsonSchema` — Shape of the object returned by a codec's `toJsonSchema()`.
88
+ - `IdsErrorCode` — String-literal union of the eleven stable error codes carried by `IdsError`.
89
+ - `TimestampCodec<Brand>` — Interface of a brand-scoped Timestamp codec instance returned by `createTimestampId()`.
90
+ - `TimestampOptions` — Construction options for `createTimestampId()`: `now`, `rng`, and `allowDuplicateBrand`.
91
+ - `ValidBrand<S>` — Compile-time validation that `S` is a well-formed brand (three lowercase `a–z` characters); intersect it with a codec constructor's brand parameter (`brand: Brand & ValidBrand<Brand>`) to reject malformed brands at the type level.
92
+
93
+ ### Classes
94
+
95
+ - `IdsError` — Single error class thrown by caller-reachable failures; carries a stable `code: IdsErrorCode`. Use `isIdsError()` rather than `instanceof` to detect across realms.
96
+
97
+ ### Functions
98
+
99
+ - `isIdsError(value)` — Type guard for `IdsError`; uses an internal brand to survive ESM/CJS dual-package duplication where bare `instanceof` fails.
100
+ - `createTimestampId(brand, options?)` — Creates a Timestamp codec for `brand` (three lowercase `a–z` characters).
91
101
 
92
102
  ## Links
93
103
 
@@ -1,4 +1,4 @@
1
- import { i as ParseResult } from "./types-g7CiQDyE.mjs";
1
+ import { i as ParseResult } from "./types-wplmOgOK.mjs";
2
2
 
3
3
  //#region src/adapters/adapter-types.d.ts
4
4
  /** Discriminated failure value passed to `onError` and emitted to the framework's error handler. */
@@ -17,4 +17,4 @@ type IdCodec<Brand extends string> = {
17
17
  type IdColumnCodec<Brand extends string> = IdCodec<Brand>;
18
18
  //#endregion
19
19
  export { IdColumnCodec as n, IdParamFailure as r, IdCodec as t };
20
- //# sourceMappingURL=adapter-types-CdYJM6Sf.d.mts.map
20
+ //# sourceMappingURL=adapter-types-CIc-4O-P.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"adapter-types-CdYJM6Sf.d.mts","names":[],"sources":["../src/adapters/adapter-types.ts"],"mappings":";;;;KAIY,cAAA;EAAA,SACG,MAAA;EAAA,SAAmC,MAAA;AAAA;EAAA,SACnC,MAAA;EAAA,SAA8B,MAAA;AAAA;;KAGjC,OAAA;EACV,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;AAAA;AADzC;AAAA,KAKY,aAAA,yBAAsC,OAAA,CAAQ,KAAA"}
1
+ {"version":3,"file":"adapter-types-CIc-4O-P.d.mts","names":[],"sources":["../src/adapters/adapter-types.ts"],"mappings":";;;;KAIY,cAAA;EAAA,SACG,MAAA;EAAA,SAAmC,MAAA;AAAA;EAAA,SACnC,MAAA;EAAA,SAA8B,MAAA;AAAA;;KAGjC,OAAA;EACV,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;AAAA;AADzC;AAAA,KAKY,aAAA,yBAAsC,OAAA,CAAQ,KAAA"}