@tnid/core 0.0.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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +509 -0
  3. package/esm/_dnt.shims.d.ts +5 -0
  4. package/esm/_dnt.shims.d.ts.map +1 -0
  5. package/esm/_dnt.shims.js +61 -0
  6. package/esm/bits.d.ts +18 -0
  7. package/esm/bits.d.ts.map +1 -0
  8. package/esm/bits.js +91 -0
  9. package/esm/data_encoding.d.ts +16 -0
  10. package/esm/data_encoding.d.ts.map +1 -0
  11. package/esm/data_encoding.js +103 -0
  12. package/esm/dynamic.d.ts +36 -0
  13. package/esm/dynamic.d.ts.map +1 -0
  14. package/esm/dynamic.js +173 -0
  15. package/esm/factory.d.ts +27 -0
  16. package/esm/factory.d.ts.map +1 -0
  17. package/esm/factory.js +107 -0
  18. package/esm/index.d.ts +5 -0
  19. package/esm/index.d.ts.map +1 -0
  20. package/esm/index.js +9 -0
  21. package/esm/name_encoding.d.ts +15 -0
  22. package/esm/name_encoding.d.ts.map +1 -0
  23. package/esm/name_encoding.js +92 -0
  24. package/esm/package.json +3 -0
  25. package/esm/types.d.ts +93 -0
  26. package/esm/types.d.ts.map +1 -0
  27. package/esm/types.js +4 -0
  28. package/esm/uuid.d.ts +17 -0
  29. package/esm/uuid.d.ts.map +1 -0
  30. package/esm/uuid.js +55 -0
  31. package/esm/uuidlike.d.ts +17 -0
  32. package/esm/uuidlike.d.ts.map +1 -0
  33. package/esm/uuidlike.js +38 -0
  34. package/package.json +37 -0
  35. package/script/_dnt.shims.d.ts +5 -0
  36. package/script/_dnt.shims.d.ts.map +1 -0
  37. package/script/_dnt.shims.js +65 -0
  38. package/script/bits.d.ts +18 -0
  39. package/script/bits.d.ts.map +1 -0
  40. package/script/bits.js +134 -0
  41. package/script/data_encoding.d.ts +16 -0
  42. package/script/data_encoding.d.ts.map +1 -0
  43. package/script/data_encoding.js +108 -0
  44. package/script/dynamic.d.ts +36 -0
  45. package/script/dynamic.d.ts.map +1 -0
  46. package/script/dynamic.js +176 -0
  47. package/script/factory.d.ts +27 -0
  48. package/script/factory.d.ts.map +1 -0
  49. package/script/factory.js +110 -0
  50. package/script/index.d.ts +5 -0
  51. package/script/index.d.ts.map +1 -0
  52. package/script/index.js +15 -0
  53. package/script/name_encoding.d.ts +15 -0
  54. package/script/name_encoding.d.ts.map +1 -0
  55. package/script/name_encoding.js +97 -0
  56. package/script/package.json +3 -0
  57. package/script/types.d.ts +93 -0
  58. package/script/types.d.ts.map +1 -0
  59. package/script/types.js +5 -0
  60. package/script/uuid.d.ts +17 -0
  61. package/script/uuid.d.ts.map +1 -0
  62. package/script/uuid.js +65 -0
  63. package/script/uuidlike.d.ts +17 -0
  64. package/script/uuidlike.d.ts.map +1 -0
  65. package/script/uuidlike.js +41 -0
@@ -0,0 +1,93 @@
1
+ /** Valid characters for TNID names (5-bit encoding): 0-4, a-z */
2
+ export type NameChar = "0" | "1" | "2" | "3" | "4" | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z";
3
+ /** Recursive validation - check one character at a time to avoid type explosion */
4
+ type ValidateNameChars<S extends string> = S extends "" ? true : S extends `${infer First}${infer Rest}` ? First extends NameChar ? ValidateNameChars<Rest> : false : false;
5
+ /** Check string length is 1-4 using tuple length trick */
6
+ type StringLength<S extends string, Acc extends unknown[] = []> = S extends "" ? Acc["length"] : S extends `${infer _}${infer Rest}` ? StringLength<Rest, [...Acc, unknown]> : never;
7
+ type ValidLength = 1 | 2 | 3 | 4;
8
+ /**
9
+ * Validate a TNID name at compile time.
10
+ * Must be 1-4 characters, each being a valid NameChar.
11
+ */
12
+ export type ValidateName<S extends string> = ValidateNameChars<S> extends true ? StringLength<S> extends ValidLength ? S : never : never;
13
+ /**
14
+ * A TNID value branded with its name. At runtime this is just a string.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * // Define a NamedTnid and matching type
19
+ * const UserId = Tnid("user");
20
+ * type UserId = TnidType<typeof UserId>;
21
+ *
22
+ * // Generate IDs
23
+ * const id: UserId = UserId.new_v0(); // time-sortable
24
+ * const id2: UserId = UserId.new_v1(); // high-entropy random
25
+ *
26
+ * // Parse from strings
27
+ * const parsed = UserId.parse("user.abc..."); // validates name matches
28
+ * const fromUuid = UserId.parseUuidString("d6157329-4640-8e30-...");
29
+ *
30
+ * // DynamicTnid - runtime name validation
31
+ * DynamicTnid.new_v0("item"); // create with runtime name
32
+ * DynamicTnid.new_v1("item"); // create with runtime name
33
+ * DynamicTnid.parse("post.xyz..."); // parse any TNID
34
+ * DynamicTnid.getName(id); // "user"
35
+ * DynamicTnid.getVariant(id); // "v0" | "v1" | "v2" | "v3"
36
+ *
37
+ * // UuidLike - wrapper for any UUID hex string
38
+ * UuidLike.fromTnid(id); // TNID to UUID string
39
+ * UuidLike.parse("d6157329-..."); // parse any UUID (format only)
40
+ * UuidLike.toTnid(uuid); // UUID to DynamicTnid (validates)
41
+ *
42
+ * // Type safety: different names are incompatible
43
+ * const PostId = Tnid("post");
44
+ * type PostId = TnidType<typeof PostId>;
45
+ * const postId: PostId = PostId.new_v0();
46
+ * // id = postId; // Compile error!
47
+ *
48
+ * // DynamicTnid type accepts any TNID
49
+ * function log(id: DynamicTnid) { console.log(DynamicTnid.getName(id)); }
50
+ * log(id); // works
51
+ * log(postId); // works
52
+ * ```
53
+ */
54
+ export type TnidValue<Name extends string> = string & {
55
+ tnid: Name;
56
+ };
57
+ /** TNID variant: v0=time-ordered, v1=random, v2/v3=reserved */
58
+ export type TnidVariant = "v0" | "v1" | "v2" | "v3";
59
+ /** Case for UUID hex string formatting. */
60
+ export type Case = "lower" | "upper";
61
+ export interface NamedTnid<Name extends string> {
62
+ /** The TNID name */
63
+ readonly name: Name;
64
+ /** Generate a new time-sortable TNID (variant 0) */
65
+ new_v0(): TnidValue<Name>;
66
+ /** Generate a new random TNID (variant 1) */
67
+ new_v1(): TnidValue<Name>;
68
+ /** Construct a V0 TNID from specific parts (for deterministic testing) */
69
+ v0_from_parts(timestampMs: bigint, randomBits: bigint): TnidValue<Name>;
70
+ /** Construct a V1 TNID from specific parts (for deterministic testing) */
71
+ v1_from_parts(randomBits: bigint): TnidValue<Name>;
72
+ /**
73
+ * Parse and validate a TNID string.
74
+ * @throws Error if the string is invalid or the name doesn't match
75
+ */
76
+ parse(s: string): TnidValue<Name>;
77
+ /**
78
+ * Parse a UUID hex string into a TNID.
79
+ * Validates that it's a valid UUIDv8 TNID and the name matches.
80
+ * @throws Error if the UUID is invalid or the name doesn't match
81
+ */
82
+ parseUuidString(uuid: string): TnidValue<Name>;
83
+ /** Get the name encoded as a 5-character hex string. */
84
+ nameHex(): string;
85
+ /** Get the variant of a TNID. */
86
+ variant(id: TnidValue<Name>): TnidVariant;
87
+ /** Convert a TNID to UUID hex string format. */
88
+ toUuidString(id: TnidValue<Name>, caseFormat?: Case): string;
89
+ }
90
+ /** Extract the `TnidValue` type from a NamedTnid. */
91
+ export type TnidType<T> = T extends NamedTnid<infer N> ? TnidValue<N> : never;
92
+ export {};
93
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // TNID Type Definitions
4
+ // =============================================================================
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ import type { TnidVariant } from "./types.js";
2
+ export declare const UUID_REGEX: RegExp;
3
+ /** Convert a 128-bit value to UUID hex string format */
4
+ export declare function valueToUuidString(value: bigint, upperCase?: boolean): string;
5
+ /** Parse a UUID hex string to a 128-bit value */
6
+ export declare function parseUuidStringToValue(uuid: string): bigint;
7
+ /** Extract name bits from a 128-bit TNID value */
8
+ export declare function extractNameBitsFromValue(value: bigint): number;
9
+ /** Extract TNID variant from a 128-bit value */
10
+ export declare function extractVariantFromValue(value: bigint): TnidVariant;
11
+ /** Validate that a 128-bit value has correct UUIDv8 version and variant bits */
12
+ export declare function validateUuidBits(value: bigint): boolean;
13
+ /** Convert bytes to TNID string */
14
+ export declare function bytesToTnidString(bytes: Uint8Array, name: string): string;
15
+ /** Convert 128-bit value to TNID string */
16
+ export declare function valueToTnidString(value: bigint): string;
17
+ //# sourceMappingURL=uuid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../src/uuid.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK9C,eAAO,MAAM,UAAU,QAC4C,CAAC;AAEpE,wDAAwD;AACxD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,OAAe,GACzB,MAAM,CAMR;AAED,iDAAiD;AACjD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED,kDAAkD;AAClD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,gDAAgD;AAChD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAIlE;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAUvD;AAED,mCAAmC;AACnC,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGzE;AAED,2CAA2C;AAC3C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKvD"}
package/script/uuid.js ADDED
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // UUID String Utilities
4
+ // =============================================================================
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UUID_REGEX = void 0;
7
+ exports.valueToUuidString = valueToUuidString;
8
+ exports.parseUuidStringToValue = parseUuidStringToValue;
9
+ exports.extractNameBitsFromValue = extractNameBitsFromValue;
10
+ exports.extractVariantFromValue = extractVariantFromValue;
11
+ exports.validateUuidBits = validateUuidBits;
12
+ exports.bytesToTnidString = bytesToTnidString;
13
+ exports.valueToTnidString = valueToTnidString;
14
+ const name_encoding_js_1 = require("./name_encoding.js");
15
+ const data_encoding_js_1 = require("./data_encoding.js");
16
+ const bits_js_1 = require("./bits.js");
17
+ exports.UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
18
+ /** Convert a 128-bit value to UUID hex string format */
19
+ function valueToUuidString(value, upperCase = false) {
20
+ const hex = value.toString(16).padStart(32, "0");
21
+ const uuid = `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
22
+ return upperCase ? uuid.toUpperCase() : uuid.toLowerCase();
23
+ }
24
+ /** Parse a UUID hex string to a 128-bit value */
25
+ function parseUuidStringToValue(uuid) {
26
+ if (!exports.UUID_REGEX.test(uuid)) {
27
+ throw new Error(`Invalid UUID format: ${uuid}`);
28
+ }
29
+ const hex = uuid.replace(/-/g, "");
30
+ return BigInt("0x" + hex);
31
+ }
32
+ /** Extract name bits from a 128-bit TNID value */
33
+ function extractNameBitsFromValue(value) {
34
+ return Number((value >> 108n) & 0xfffffn);
35
+ }
36
+ /** Extract TNID variant from a 128-bit value */
37
+ function extractVariantFromValue(value) {
38
+ const variantBits = Number((value >> 60n) & 3n);
39
+ const variants = ["v0", "v1", "v2", "v3"];
40
+ return variants[variantBits];
41
+ }
42
+ /** Validate that a 128-bit value has correct UUIDv8 version and variant bits */
43
+ function validateUuidBits(value) {
44
+ // Check UUID version (bits 76-79 should be 0x8)
45
+ const version = Number((value >> 76n) & 0xfn);
46
+ if (version !== 8)
47
+ return false;
48
+ // Check UUID variant (bits 62-63 should be 0b10)
49
+ const variant = Number((value >> 62n) & 3n);
50
+ if (variant !== 0b10)
51
+ return false;
52
+ return true;
53
+ }
54
+ /** Convert bytes to TNID string */
55
+ function bytesToTnidString(bytes, name) {
56
+ const dataEncoded = (0, data_encoding_js_1.encodeData)(bytes);
57
+ return `${name}.${dataEncoded}`;
58
+ }
59
+ /** Convert 128-bit value to TNID string */
60
+ function valueToTnidString(value) {
61
+ const nameBits = extractNameBitsFromValue(value);
62
+ const name = (0, name_encoding_js_1.decodeName)(nameBits);
63
+ const bytes = (0, bits_js_1.valueToBytes)(value);
64
+ return bytesToTnidString(bytes, name);
65
+ }
@@ -0,0 +1,17 @@
1
+ import type { DynamicTnid } from "./dynamic.js";
2
+ /** A UUID hex string (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) that may or may not be a valid TNID. */
3
+ export type UuidLike = string & {
4
+ __uuidlike: true;
5
+ };
6
+ /** Wrapper for UUID hex strings that may or may not be valid TNIDs. */
7
+ export declare const UuidLike: {
8
+ /** Create from a TNID (always valid). */
9
+ readonly fromTnid: (id: DynamicTnid) => UuidLike;
10
+ /** Parse UUID hex string (format validation only, not TNID validation). */
11
+ readonly parse: (s: string) => UuidLike;
12
+ /** Try to convert to DynamicTnid (validates TNID structure). */
13
+ readonly toTnid: (uuid: UuidLike) => DynamicTnid;
14
+ /** Format as uppercase UUID hex string. */
15
+ readonly toUpperCase: (uuid: UuidLike) => UuidLike;
16
+ };
17
+ //# sourceMappingURL=uuidlike.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uuidlike.d.ts","sourceRoot":"","sources":["../src/uuidlike.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,oGAAoG;AACpG,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,UAAU,EAAE,IAAI,CAAA;CAAE,CAAC;AAWrD,uEAAuE;AACvE,eAAO,MAAM,QAAQ;IACnB,yCAAyC;4BAC5B,WAAW,KAAG,QAAQ;IAInC,2EAA2E;wBAClE,MAAM,KAAG,QAAQ;IAQ1B,gEAAgE;4BACnD,QAAQ,KAAG,WAAW;IAanC,2CAA2C;iCACzB,QAAQ,KAAG,QAAQ;CAG7B,CAAC"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // UuidLike - Wrapper for UUID hex strings
4
+ // =============================================================================
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UuidLike = void 0;
7
+ const name_encoding_js_1 = require("./name_encoding.js");
8
+ const uuid_js_1 = require("./uuid.js");
9
+ const dynamic_js_1 = require("./dynamic.js");
10
+ /** Wrapper for UUID hex strings that may or may not be valid TNIDs. */
11
+ exports.UuidLike = {
12
+ /** Create from a TNID (always valid). */
13
+ fromTnid(id) {
14
+ return (0, dynamic_js_1.toUuidStringImpl)(id, false);
15
+ },
16
+ /** Parse UUID hex string (format validation only, not TNID validation). */
17
+ parse(s) {
18
+ // Validate format only
19
+ if (!uuid_js_1.UUID_REGEX.test(s)) {
20
+ throw new Error(`Invalid UUID format: ${s}`);
21
+ }
22
+ return s.toLowerCase();
23
+ },
24
+ /** Try to convert to DynamicTnid (validates TNID structure). */
25
+ toTnid(uuid) {
26
+ const value = (0, uuid_js_1.parseUuidStringToValue)(uuid);
27
+ if (!(0, uuid_js_1.validateUuidBits)(value)) {
28
+ throw new Error("Invalid TNID: not a valid UUIDv8");
29
+ }
30
+ const nameBits = (0, uuid_js_1.extractNameBitsFromValue)(value);
31
+ const name = (0, name_encoding_js_1.decodeName)(nameBits);
32
+ if (!(0, name_encoding_js_1.isValidNameRuntime)(name)) {
33
+ throw new Error("Invalid TNID: invalid name encoding");
34
+ }
35
+ return (0, uuid_js_1.valueToTnidString)(value);
36
+ },
37
+ /** Format as uppercase UUID hex string. */
38
+ toUpperCase(uuid) {
39
+ return uuid.toUpperCase();
40
+ },
41
+ };