@ingram-tech/nk-db 1.5.0 → 1.6.0

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.
package/README.md CHANGED
@@ -144,19 +144,20 @@ The same surface is available programmatically:
144
144
 
145
145
  ## Prefixed ids (`@ingram-tech/nk-db/id`)
146
146
 
147
- UUIDv7 minting (`uuidGenerateId`) plus a base58 "skin" for wire ids
148
- (`team_3nX…` ↔ stored UUID): `toPrefixedId` / `fromPrefixedId` / `base58Id`,
149
- and `createIdRegistry` for typed per-entity helpers.
147
+ The codec is the standalone [`id758`](https://github.com/ingram-technologies/id758)
148
+ package: `uuidv7()`, `encodeId` / `decodeId` / `mintId`, and `createIdRegistry`
149
+ for typed per-entity helpers. This subpath re-exports all of it, plus the
150
+ pre-extraction names (`uuidGenerateId`, `toPrefixedId`, `fromPrefixedId`,
151
+ `base58Id`) as deprecated aliases, so either import path works.
150
152
 
151
- **This module is isomorphic** zero imports, randomness from Web Crypto so a
153
+ **The module is isomorphic** (no imports, randomness from Web Crypto), so a
152
154
  Drizzle `schema.ts`, a client component or an edge runtime can all use it. Keep
153
155
  it that way: a single `node:crypto` import makes every module that touches an id
154
156
  node-only (a test enforces this).
155
157
 
156
- Store the raw `uuid` and skin at the edge. The prefixed id is presentation, not
158
+ Store the raw `uuid` and encode at the edge. The prefixed id is presentation, not
157
159
  identity: inside the DB, "which entity is this?" is already carried by the
158
- column, so storing the prefix duplicates schema metadata into every row and puts
159
- codec bugs permanently on disk.
160
+ column, so storing the prefix duplicates schema metadata into every row.
160
161
 
161
162
  **Ids are self-describing, uuids are not.** A prefix names its entity, so
162
163
  decoding needs no context — `entityOf(registry, id)` and `decodeAnyId(registry,
package/dist/id.d.ts CHANGED
@@ -1,134 +1,21 @@
1
1
  /**
2
- * The Ingram id codec a UUIDv7 and its base58 skin. It lives here in nk-db
3
- * (the lowest package in the graph) behind the `@ingram-tech/nk-db/id` subpath,
4
- * so it stays dependency-free no `pg` / `drizzle` — and any site can mint ids
5
- * without pulling a heavier slice.
2
+ * `@ingram-tech/nk-db/id`the fleet's id codec, now published standalone as
3
+ * [`id758`](https://github.com/ingram-technologies/id758). This subpath stays
4
+ * as the nextkit-facing entry point: it re-exports the whole `id758` surface
5
+ * plus the names nextkit sites adopted before the extraction, so nothing that
6
+ * imports from here needs to change. New code may import `id758` directly.
6
7
  *
7
- * **This module is isomorphic and must stay that way.** It has no imports at
8
- * all: randomness comes from Web Crypto (`crypto.getRandomValues`, a global on
9
- * Node 19+, Bun, Deno, edge runtimes and browsers), not `node:crypto`. That is
10
- * load-bearing, not incidental — a `node:crypto` import here makes every module
11
- * that touches an id node-only, which in practice means a Drizzle `schema.ts`
12
- * cannot encode/decode without dragging `node:crypto` into client bundles, and
13
- * sites end up dependency-injecting the codec to route around it. Keep the
14
- * import list empty.
15
- *
16
- * When a service has a non-JS twin of this codec (e.g. a Python API), keep its
17
- * byte string vectors identical to the ones in `id.test.ts`, so a stored
18
- * UUIDv7 and a prefixed base58 id are the same encoding of the same 16 bytes.
19
- * That cross-impl contract is the most important property of this file — keep
20
- * the vectors in lockstep.
21
- *
22
- * Store the hyphenated UUIDv7 at rest (uuid columns stay native and time-ordered
23
- * for index locality) and use {@link toPrefixedId} to skin it as a prefixed
24
- * base58 id for the wire / display, {@link fromPrefixedId} to recover it.
25
- * {@link base58Id} mints a fresh one directly; {@link createIdRegistry} builds a
26
- * typed, prefix-validated set of helpers for a project's entities.
27
- */
28
- /**
29
- * Mint a **UUIDv7** (RFC 9562): a 48-bit Unix-ms timestamp prefix + random tail,
30
- * version `7`, variant `10`. UUID-shaped (drops straight into a `uuid` column)
31
- * while staying time-ordered for index locality. Used as Better Auth's
32
- * `advanced.database.generateId`. Node/Bun's `randomUUID` is v4-only, so we lay
33
- * the bytes out by hand.
34
- */
35
- export declare const uuidGenerateId: () => Uuid;
36
- /** Skin a stored hyphenated UUIDv7 as a prefixed base58 id, e.g. `team_…`. */
37
- export declare function toPrefixedId(uuid: string, prefix: string): string;
38
- /** Inverse of {@link toPrefixedId}: recover the hyphenated UUIDv7. */
39
- export declare function fromPrefixedId(id: string): string;
40
- /** Mint a fresh prefixed base58 id (UUIDv7 core), for text-id sites / API parity. */
41
- export declare function base58Id(prefix: string): string;
42
- declare const ID_BRAND: unique symbol;
43
- declare const UUID_BRAND: unique symbol;
44
- /**
45
- * A prefixed base58 public id for entity `E` (e.g. `org_…`), branded by entity
46
- * so ids of different entities — and plain strings — can't be mixed silently. A
47
- * plain `string` at runtime; the brand is minted by a {@link createIdRegistry}
48
- * helper and erased on the wire.
49
- */
50
- export type Id<E extends string> = string & {
51
- readonly [ID_BRAND]: E;
52
- };
53
- /**
54
- * A hyphenated UUIDv7 at rest, branded distinct from a public {@link Id} so a
55
- * skinned id can't be fed into a uuid slot (or a uuid into an id slot) by
56
- * accident. Recovered from an {@link Id} by a registry helper's `decode`.
57
- */
58
- export type Uuid = string & {
59
- readonly [UUID_BRAND]: "Uuid";
60
- };
61
- /**
62
- * Whether `value` is a hyphenated uuid — the sanctioned string→{@link Uuid}
63
- * bless: narrowing through the shape check is never a blind cast. Use at trust
64
- * boundaries (env/config, external payloads, `crypto.randomUUID()`).
65
- */
66
- export declare const isUuid: (value: string | null | undefined) => value is Uuid;
67
- /** The throwing {@link isUuid}: bless a string you require to be a uuid. */
68
- export declare function asUuid(value: string): Uuid;
69
- /** Typed helpers for one entity's prefixed ids — built by {@link createIdRegistry}. */
70
- export interface IdHelper<E extends string = string> {
71
- /** This entity's prefix, e.g. `"agt"` (no trailing underscore). */
72
- readonly prefix: string;
73
- /** Mint a fresh prefixed id (new UUIDv7 core). */
74
- mint(): Id<E>;
75
- /** Skin a stored hyphenated UUIDv7 as this entity's prefixed id. */
76
- encode(uuid: string): Id<E>;
77
- /** Recover the hyphenated UUIDv7; throws if the prefix / shape doesn't match. */
78
- decode(id: string): Uuid;
79
- /**
80
- * Recover the hyphenated UUIDv7, or `null` if `id` isn't a well-formed
81
- * prefixed id for this entity. The throw-free {@link decode}, for validating
82
- * untrusted input (a path param, a query string) without a try/catch.
83
- */
84
- decodeOrNull(id: string): Uuid | null;
85
- /** Whether `id` is a well-formed prefixed id for this entity (narrows to {@link Id}). */
86
- is(id: string): id is Id<E>;
87
- }
88
- /** The map returned by {@link createIdRegistry}: one {@link IdHelper} per key. */
89
- export type IdRegistry<K extends string> = {
90
- [E in K]: IdHelper<E>;
91
- };
92
- /**
93
- * Build a typed, prefix-validated id registry for a project's entities — one
94
- * place to declare every prefix instead of hand-rolling encode/decode wrappers:
95
- *
96
- * ```ts
97
- * const ids = createIdRegistry({ org: "org", agent: "agt", session: "cs" });
98
- * ids.org.mint(); // "org_3k9…"
99
- * ids.org.encode(uuid); // "org_…"
100
- * ids.org.decode("org_…"); // uuid — throws on a wrong / missing prefix
101
- * ids.agent.is(someId); // boolean
102
- * ```
103
- */
104
- export declare function createIdRegistry<const T extends Record<string, string>>(prefixes: T): {
105
- [K in keyof T]: IdHelper;
106
- };
107
- /**
108
- * Which entity a prefixed id belongs to, or `null` if no helper in `registry`
109
- * recognises it (a raw uuid, a sentinel, a foreign prefix).
110
- *
111
- * A public id is **self-describing**: its prefix names its entity, so resolving
112
- * one needs no surrounding context. That is the property behind every
113
- * entity-agnostic decode — a polymorphic FK whose target is named by a sibling
114
- * `*_type` column, a raw-SQL binding that only has a value, a webhook payload.
115
- * The inverse does **not** hold: a bare uuid carries no entity, so encoding
116
- * always needs to know which entity you meant.
117
- *
118
- * Standalone rather than a registry method: the registry is keyed by entity
119
- * name, so a method would collide with an entity literally called `entityOf`.
120
- */
121
- export declare function entityOf<K extends string>(registry: Record<K, IdHelper>, value: string): K | null;
122
- /**
123
- * Decode a prefixed id belonging to **any** entity in `registry` (see
124
- * {@link entityOf}), for the boundaries that can't name one: polymorphic FKs,
125
- * raw-SQL id bindings, generic audit/event payloads.
126
- *
127
- * Tolerant by design — a value no helper recognises is returned unchanged, so an
128
- * already-decoded uuid passes straight through and this is safe to apply to a
129
- * value that may or may not be skinned. Use a helper's `decode`/`decodeOrNull`
130
- * when you know the entity and want a wrong prefix rejected.
131
- */
132
- export declare function decodeAnyId<K extends string>(registry: Record<K, IdHelper>, value: string): Uuid;
133
- export {};
8
+ * Like `id758` itself, this module must stay isomorphic (no node-only imports):
9
+ * it is pulled into Drizzle schemas, client components and edge runtimes.
10
+ */
11
+ export * from "id758";
12
+ import { decodeId, encodeId, mintId, uuidv7 } from "id758";
13
+ /** @deprecated Use `uuidv7` from `id758`. */
14
+ export declare const uuidGenerateId: typeof uuidv7;
15
+ /** @deprecated Use `encodeId` from `id758`. */
16
+ export declare const toPrefixedId: typeof encodeId;
17
+ /** @deprecated Use `decodeId` from `id758`. */
18
+ export declare const fromPrefixedId: typeof decodeId;
19
+ /** @deprecated Use `mintId` from `id758`. */
20
+ export declare const base58Id: typeof mintId;
134
21
  //# sourceMappingURL=id.d.ts.map
package/dist/id.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,QAAO,IAYjC,CAAC;AA0DF,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,OAAO,CAAC,MAAM,QAAQ,EAAE,OAAO,MAAM,CAAC;AACtC,OAAO,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AAExC;;;;;GAKG;AACH,MAAM,MAAM,EAAE,CAAC,CAAC,SAAS,MAAM,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAEvE;;;;GAIG;AACH,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAM9D;;;;GAIG;AACH,eAAO,MAAM,MAAM,UAAW,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,KAAK,IAAI,IAClB,CAAC;AAElD,4EAA4E;AAC5E,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG1C;AAED,uFAAuF;AACvF,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAClD,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACd,oEAAoE;IACpE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5B,iFAAiF;IACjF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,yFAAyF;IACzF,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;CAC5B;AAED,kFAAkF;AAClF,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI;KAAG,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;CAAE,CAAC;AAmBrE;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtE,QAAQ,EAAE,CAAC,GACT;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,QAAQ;CAAE,CAM9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EACxC,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,EAC7B,KAAK,EAAE,MAAM,GACX,CAAC,GAAG,IAAI,CAOV;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAC3C,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,EAC7B,KAAK,EAAE,MAAM,GACX,IAAI,CAGN"}
1
+ {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,OAAO,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE3D,6CAA6C;AAC7C,eAAO,MAAM,cAAc,eAAS,CAAC;AACrC,+CAA+C;AAC/C,eAAO,MAAM,YAAY,iBAAW,CAAC;AACrC,+CAA+C;AAC/C,eAAO,MAAM,cAAc,iBAAW,CAAC;AACvC,6CAA6C;AAC7C,eAAO,MAAM,QAAQ,eAAS,CAAC"}
package/dist/id.js CHANGED
@@ -1,204 +1,21 @@
1
1
  /**
2
- * The Ingram id codec a UUIDv7 and its base58 skin. It lives here in nk-db
3
- * (the lowest package in the graph) behind the `@ingram-tech/nk-db/id` subpath,
4
- * so it stays dependency-free no `pg` / `drizzle` — and any site can mint ids
5
- * without pulling a heavier slice.
2
+ * `@ingram-tech/nk-db/id`the fleet's id codec, now published standalone as
3
+ * [`id758`](https://github.com/ingram-technologies/id758). This subpath stays
4
+ * as the nextkit-facing entry point: it re-exports the whole `id758` surface
5
+ * plus the names nextkit sites adopted before the extraction, so nothing that
6
+ * imports from here needs to change. New code may import `id758` directly.
6
7
  *
7
- * **This module is isomorphic and must stay that way.** It has no imports at
8
- * all: randomness comes from Web Crypto (`crypto.getRandomValues`, a global on
9
- * Node 19+, Bun, Deno, edge runtimes and browsers), not `node:crypto`. That is
10
- * load-bearing, not incidental — a `node:crypto` import here makes every module
11
- * that touches an id node-only, which in practice means a Drizzle `schema.ts`
12
- * cannot encode/decode without dragging `node:crypto` into client bundles, and
13
- * sites end up dependency-injecting the codec to route around it. Keep the
14
- * import list empty.
15
- *
16
- * When a service has a non-JS twin of this codec (e.g. a Python API), keep its
17
- * byte → string vectors identical to the ones in `id.test.ts`, so a stored
18
- * UUIDv7 and a prefixed base58 id are the same encoding of the same 16 bytes.
19
- * That cross-impl contract is the most important property of this file — keep
20
- * the vectors in lockstep.
21
- *
22
- * Store the hyphenated UUIDv7 at rest (uuid columns stay native and time-ordered
23
- * for index locality) and use {@link toPrefixedId} to skin it as a prefixed
24
- * base58 id for the wire / display, {@link fromPrefixedId} to recover it.
25
- * {@link base58Id} mints a fresh one directly; {@link createIdRegistry} builds a
26
- * typed, prefix-validated set of helpers for a project's entities.
27
- */
28
- /**
29
- * Mint a **UUIDv7** (RFC 9562): a 48-bit Unix-ms timestamp prefix + random tail,
30
- * version `7`, variant `10`. UUID-shaped (drops straight into a `uuid` column)
31
- * while staying time-ordered for index locality. Used as Better Auth's
32
- * `advanced.database.generateId`. Node/Bun's `randomUUID` is v4-only, so we lay
33
- * the bytes out by hand.
34
- */
35
- export const uuidGenerateId = () => {
36
- const bytes = crypto.getRandomValues(new Uint8Array(16));
37
- const ts = Date.now();
38
- bytes[0] = Math.floor(ts / 2 ** 40) & 0xff;
39
- bytes[1] = Math.floor(ts / 2 ** 32) & 0xff;
40
- bytes[2] = Math.floor(ts / 2 ** 24) & 0xff;
41
- bytes[3] = Math.floor(ts / 2 ** 16) & 0xff;
42
- bytes[4] = Math.floor(ts / 2 ** 8) & 0xff;
43
- bytes[5] = ts & 0xff;
44
- bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x70; // version 7
45
- bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80; // variant 10
46
- return bytesToUuid(bytes); // mint site
47
- };
48
- const B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
49
- // ceil(128 / log2(58)): a 16-byte value never needs more than 22 digits. We
50
- // left-pad to it so every body is uniform width and sorts lexically ==
51
- // chronologically (UUIDv7's ms-timestamp prefix lives in the high bytes).
52
- const WIDTH = 22;
53
- // A bare base58 body: 22 chars, Bitcoin alphabet (no 0 / I / O / l).
54
- const BODY = "[1-9A-HJ-NP-Za-km-z]{22}";
55
- /** Big-endian base58 (Bitcoin alphabet) of 16 bytes, left-padded to `WIDTH`. */
56
- function encode58(bytes) {
57
- let n = 0n;
58
- for (const b of bytes)
59
- n = (n << 8n) | BigInt(b);
60
- let out = "";
61
- while (n > 0n) {
62
- out = B58.charAt(Number(n % 58n)) + out;
63
- n /= 58n;
64
- }
65
- return out.padStart(WIDTH, B58.charAt(0));
66
- }
67
- /** Inverse of {@link encode58}: a base58 body back to 16 bytes. */
68
- function decode58(body) {
69
- let n = 0n;
70
- for (const ch of body) {
71
- const v = B58.indexOf(ch);
72
- if (v < 0)
73
- throw new Error(`invalid base58 char: ${ch}`);
74
- n = n * 58n + BigInt(v);
75
- }
76
- // 58^22 slightly exceeds 2^128, so a high-range 22-char body can overflow 16
77
- // bytes; silently truncating would alias two distinct wire ids to one UUID.
78
- if (n >= 1n << 128n)
79
- throw new Error(`base58 value out of uuid range: ${body}`);
80
- const bytes = new Uint8Array(16);
81
- for (let i = 15; i >= 0; i--) {
82
- bytes[i] = Number(n & 0xffn);
83
- n >>= 8n;
84
- }
85
- return bytes;
86
- }
87
- /** A hyphenated UUID string → its 16 raw bytes. */
88
- function uuidToBytes(uuid) {
89
- const hex = uuid.replace(/-/g, "");
90
- if (!/^[0-9a-fA-F]{32}$/.test(hex))
91
- throw new Error(`not a uuid: ${uuid}`);
92
- const bytes = new Uint8Array(16);
93
- for (let i = 0; i < 16; i++) {
94
- bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
95
- }
96
- return bytes;
97
- }
98
- /** 16 raw bytes → a canonical hyphenated UUID string. */
99
- function bytesToUuid(bytes) {
100
- const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
101
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
102
- }
103
- /** Skin a stored hyphenated UUIDv7 as a prefixed base58 id, e.g. `team_…`. */
104
- export function toPrefixedId(uuid, prefix) {
105
- return `${prefix}_${encode58(uuidToBytes(uuid))}`;
106
- }
107
- /** Inverse of {@link toPrefixedId}: recover the hyphenated UUIDv7. */
108
- export function fromPrefixedId(id) {
109
- const body = id.slice(id.indexOf("_") + 1);
110
- return bytesToUuid(decode58(body));
111
- }
112
- /** Mint a fresh prefixed base58 id (UUIDv7 core), for text-id sites / API parity. */
113
- export function base58Id(prefix) {
114
- return toPrefixedId(uuidGenerateId(), prefix);
115
- }
116
- // Any RFC 9562 version (1-8): sites mint v7, but migrated rows are often v4.
117
- const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
118
- /**
119
- * Whether `value` is a hyphenated uuid — the sanctioned string→{@link Uuid}
120
- * bless: narrowing through the shape check is never a blind cast. Use at trust
121
- * boundaries (env/config, external payloads, `crypto.randomUUID()`).
122
- */
123
- export const isUuid = (value) => typeof value === "string" && UUID_RE.test(value);
124
- /** The throwing {@link isUuid}: bless a string you require to be a uuid. */
125
- export function asUuid(value) {
126
- if (!isUuid(value))
127
- throw new Error(`not a uuid: ${value}`);
128
- return value;
129
- }
130
- function makeHelper(prefix) {
131
- // Prefixes are developer-controlled identifier constants, never user input.
132
- const matcher = new RegExp(`^${prefix}_${BODY}$`);
133
- // The brands are erased at runtime; these casts are the sole mint sites.
134
- return {
135
- prefix,
136
- mint: () => base58Id(prefix),
137
- encode: (uuid) => toPrefixedId(uuid, prefix),
138
- decode: (id) => {
139
- if (!matcher.test(id))
140
- throw new Error(`not a ${prefix}_ id: ${id}`);
141
- return fromPrefixedId(id);
142
- },
143
- decodeOrNull: (id) => (matcher.test(id) ? fromPrefixedId(id) : null),
144
- is: (id) => matcher.test(id),
145
- };
146
- }
147
- /**
148
- * Build a typed, prefix-validated id registry for a project's entities — one
149
- * place to declare every prefix instead of hand-rolling encode/decode wrappers:
150
- *
151
- * ```ts
152
- * const ids = createIdRegistry({ org: "org", agent: "agt", session: "cs" });
153
- * ids.org.mint(); // "org_3k9…"
154
- * ids.org.encode(uuid); // "org_…"
155
- * ids.org.decode("org_…"); // uuid — throws on a wrong / missing prefix
156
- * ids.agent.is(someId); // boolean
157
- * ```
158
- */
159
- export function createIdRegistry(prefixes) {
160
- const reg = {};
161
- for (const [key, prefix] of Object.entries(prefixes)) {
162
- reg[key] = makeHelper(prefix);
163
- }
164
- return reg;
165
- }
166
- /**
167
- * Which entity a prefixed id belongs to, or `null` if no helper in `registry`
168
- * recognises it (a raw uuid, a sentinel, a foreign prefix).
169
- *
170
- * A public id is **self-describing**: its prefix names its entity, so resolving
171
- * one needs no surrounding context. That is the property behind every
172
- * entity-agnostic decode — a polymorphic FK whose target is named by a sibling
173
- * `*_type` column, a raw-SQL binding that only has a value, a webhook payload.
174
- * The inverse does **not** hold: a bare uuid carries no entity, so encoding
175
- * always needs to know which entity you meant.
176
- *
177
- * Standalone rather than a registry method: the registry is keyed by entity
178
- * name, so a method would collide with an entity literally called `entityOf`.
179
- */
180
- export function entityOf(registry, value) {
181
- // Cheap reject: every prefixed id has one, and raw uuids never do.
182
- if (!value.includes("_"))
183
- return null;
184
- for (const entity of Object.keys(registry)) {
185
- if (registry[entity].is(value))
186
- return entity;
187
- }
188
- return null;
189
- }
190
- /**
191
- * Decode a prefixed id belonging to **any** entity in `registry` (see
192
- * {@link entityOf}), for the boundaries that can't name one: polymorphic FKs,
193
- * raw-SQL id bindings, generic audit/event payloads.
194
- *
195
- * Tolerant by design — a value no helper recognises is returned unchanged, so an
196
- * already-decoded uuid passes straight through and this is safe to apply to a
197
- * value that may or may not be skinned. Use a helper's `decode`/`decodeOrNull`
198
- * when you know the entity and want a wrong prefix rejected.
8
+ * Like `id758` itself, this module must stay isomorphic (no node-only imports):
9
+ * it is pulled into Drizzle schemas, client components and edge runtimes.
199
10
  */
200
- export function decodeAnyId(registry, value) {
201
- const entity = entityOf(registry, value);
202
- return entity === null ? value : registry[entity].decode(value);
203
- }
11
+ export * from "id758";
12
+ import { decodeId, encodeId, mintId, uuidv7 } from "id758";
13
+ /** @deprecated Use `uuidv7` from `id758`. */
14
+ export const uuidGenerateId = uuidv7;
15
+ /** @deprecated Use `encodeId` from `id758`. */
16
+ export const toPrefixedId = encodeId;
17
+ /** @deprecated Use `decodeId` from `id758`. */
18
+ export const fromPrefixedId = decodeId;
19
+ /** @deprecated Use `mintId` from `id758`. */
20
+ export const base58Id = mintId;
204
21
  //# sourceMappingURL=id.js.map
package/dist/id.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"id.js","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,OAAO,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE3D,6CAA6C;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AACrC,+CAA+C;AAC/C,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC;AACrC,+CAA+C;AAC/C,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AACvC,6CAA6C;AAC7C,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingram-tech/nk-db",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "The Ingram Postgres data layer: one TLS-aware pg pool, raw-SQL helpers, Drizzle wiring, and a PGlite (no-Docker) dev/test harness for Next.js sites.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -51,6 +51,7 @@
51
51
  "test": "vitest run"
52
52
  },
53
53
  "dependencies": {
54
+ "id758": "^1.0.0",
54
55
  "zod": "^4.4.3"
55
56
  },
56
57
  "peerDependencies": {
@@ -68,13 +69,13 @@
68
69
  }
69
70
  },
70
71
  "devDependencies": {
71
- "@electric-sql/pglite": "^0.5.4",
72
- "@electric-sql/pglite-socket": "^0.2.7",
73
- "@ingram-tech/nk-dev": "0.11.0",
74
- "@types/node": "^26.1.2",
75
- "@types/pg": "^8.20.1",
72
+ "@electric-sql/pglite": "^0.5.5",
73
+ "@electric-sql/pglite-socket": "^0.2.8",
74
+ "@ingram-tech/nk-dev": "0.11.1",
75
+ "@types/node": "^26.2.0",
76
+ "@types/pg": "^8.23.1",
76
77
  "drizzle-orm": "^0.45.2",
77
- "pg": "^8.22.0",
78
+ "pg": "^8.23.0",
78
79
  "typescript": "^7.0.2",
79
80
  "vitest": "^4.1.10"
80
81
  }