@veridjs/core 1.0.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/LICENSE ADDED
@@ -0,0 +1 @@
1
+ MIT License
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # VID — Verifiable Identifier
2
+
3
+ VID is a cryptographically verifiable, globally unique identifier designed for distributed systems.
4
+
5
+ Unlike UUIDv4 or UUIDv7, VID includes built-in authenticity verification using HMAC signatures.
6
+
7
+ This prevents forged IDs and enables trustless validation.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ • Globally unique
14
+ • Cryptographically verifiable
15
+ • Database efficient (18 bytes binary)
16
+ • Supports MongoDB, PostgreSQL, Redis
17
+ • Time-sortable
18
+ • Zero dependencies
19
+ • High performance
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install @kishan/vid
27
+ Quick Start
28
+ import { VID } from "@kishan/vid"
29
+
30
+ const vid = VID.initialize({
31
+ secret: "your-secret-key",
32
+ keyVersion: 1
33
+ })
34
+
35
+ const id = vid.generate()
36
+
37
+ console.log(id.toString())
38
+
39
+ console.log(
40
+ vid.verify(id.toString())
41
+ )
42
+ Storage Options
43
+ String storage (recommended default):
44
+
45
+ id.toString()
46
+ Binary storage (optimized):
47
+
48
+ id.toBinary()
49
+ MongoDB Example
50
+ collection.insertOne({
51
+ _id: id.toBinary()
52
+ })
53
+
54
+ vid.verify(doc._id)
55
+ PostgreSQL Example
56
+ CREATE TABLE users (
57
+ id BYTEA PRIMARY KEY
58
+ );
59
+ await db.query(
60
+ "INSERT INTO users (id) VALUES ($1)",
61
+ [id.toBinary()]
62
+ )
63
+ Verification
64
+ vid.verify(id)
65
+ Returns true if valid.
66
+
67
+ False if tampered or forged.
68
+
69
+ Parsing
70
+ const metadata = vid.parse(id)
71
+
72
+ console.log(metadata.timestamp)
73
+ console.log(metadata.nodeId)
74
+ Security
75
+ VID uses HMAC-SHA256 signature truncated to 56 bits.
76
+
77
+ Verification uses constant-time comparison to prevent timing attacks.
78
+
79
+ Secret key never exposed.
80
+
81
+ Performance
82
+ Binary size: 18 bytes
83
+ String size: 26 chars
84
+
85
+ Index size smaller than UUIDv7.
86
+
@@ -0,0 +1,22 @@
1
+ /**
2
+ * MongoDB adapter for VID.
3
+ *
4
+ * Converts between VID binary format and MongoDB BSON Binary type.
5
+ *
6
+ * Does NOT require VIDValue instance.
7
+ * Works with Uint8Array directly.
8
+ */
9
+ export declare class VIDMongoAdapter {
10
+ /**
11
+ * Convert VID binary to MongoDB Binary.
12
+ *
13
+ * Accepts Uint8Array (from id.toBinary())
14
+ */
15
+ static toDatabase(binary: Uint8Array): Buffer;
16
+ /**
17
+ * Convert MongoDB Binary to Uint8Array.
18
+ *
19
+ * Output can be passed directly to vid.verify()
20
+ */
21
+ static fromDatabase(value: Buffer): Uint8Array;
22
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VIDMongoAdapter = void 0;
4
+ /**
5
+ * MongoDB adapter for VID.
6
+ *
7
+ * Converts between VID binary format and MongoDB BSON Binary type.
8
+ *
9
+ * Does NOT require VIDValue instance.
10
+ * Works with Uint8Array directly.
11
+ */
12
+ class VIDMongoAdapter {
13
+ /**
14
+ * Convert VID binary to MongoDB Binary.
15
+ *
16
+ * Accepts Uint8Array (from id.toBinary())
17
+ */
18
+ static toDatabase(binary) {
19
+ if (!(binary instanceof Uint8Array)) {
20
+ throw new Error("Expected Uint8Array");
21
+ }
22
+ return Buffer.from(binary);
23
+ }
24
+ /**
25
+ * Convert MongoDB Binary to Uint8Array.
26
+ *
27
+ * Output can be passed directly to vid.verify()
28
+ */
29
+ static fromDatabase(value) {
30
+ if (!(value instanceof Buffer)) {
31
+ throw new Error("Expected MongoDB Binary");
32
+ }
33
+ return new Uint8Array(value);
34
+ }
35
+ }
36
+ exports.VIDMongoAdapter = VIDMongoAdapter;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * PostgreSQL adapter for VID.
3
+ *
4
+ * Converts between VID binary format and PostgreSQL BYTEA format.
5
+ *
6
+ * PostgreSQL BYTEA maps to Node.js Buffer.
7
+ *
8
+ * This adapter does NOT depend on VIDValue.
9
+ * Works only with Uint8Array and Buffer.
10
+ */
11
+ export declare class VIDPostgresAdapter {
12
+ /**
13
+ * Convert VID binary (Uint8Array) to PostgreSQL Buffer.
14
+ *
15
+ * Usage:
16
+ *
17
+ * await db.query(
18
+ * "INSERT INTO users (id) VALUES ($1)",
19
+ * [VIDPostgresAdapter.toDatabase(id.toBinary())]
20
+ * )
21
+ */
22
+ static toDatabase(binary: Uint8Array): Buffer;
23
+ /**
24
+ * Convert PostgreSQL BYTEA (Buffer) to Uint8Array.
25
+ *
26
+ * Usage:
27
+ *
28
+ * const result = await db.query(...)
29
+ *
30
+ * vid.verify(
31
+ * VIDPostgresAdapter.fromDatabase(result.rows[0].id)
32
+ * )
33
+ */
34
+ static fromDatabase(buffer: Buffer): Uint8Array;
35
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VIDPostgresAdapter = void 0;
4
+ /**
5
+ * PostgreSQL adapter for VID.
6
+ *
7
+ * Converts between VID binary format and PostgreSQL BYTEA format.
8
+ *
9
+ * PostgreSQL BYTEA maps to Node.js Buffer.
10
+ *
11
+ * This adapter does NOT depend on VIDValue.
12
+ * Works only with Uint8Array and Buffer.
13
+ */
14
+ class VIDPostgresAdapter {
15
+ /**
16
+ * Convert VID binary (Uint8Array) to PostgreSQL Buffer.
17
+ *
18
+ * Usage:
19
+ *
20
+ * await db.query(
21
+ * "INSERT INTO users (id) VALUES ($1)",
22
+ * [VIDPostgresAdapter.toDatabase(id.toBinary())]
23
+ * )
24
+ */
25
+ static toDatabase(binary) {
26
+ if (!(binary instanceof Uint8Array)) {
27
+ throw new Error("VIDPostgresAdapter.toDatabase: expected Uint8Array");
28
+ }
29
+ return Buffer.from(binary);
30
+ }
31
+ /**
32
+ * Convert PostgreSQL BYTEA (Buffer) to Uint8Array.
33
+ *
34
+ * Usage:
35
+ *
36
+ * const result = await db.query(...)
37
+ *
38
+ * vid.verify(
39
+ * VIDPostgresAdapter.fromDatabase(result.rows[0].id)
40
+ * )
41
+ */
42
+ static fromDatabase(buffer) {
43
+ if (!Buffer.isBuffer(buffer)) {
44
+ throw new Error("VIDPostgresAdapter.fromDatabase: expected Buffer");
45
+ }
46
+ return new Uint8Array(buffer);
47
+ }
48
+ }
49
+ exports.VIDPostgresAdapter = VIDPostgresAdapter;
@@ -0,0 +1,103 @@
1
+ import { VIDOptions } from "../types";
2
+ import { VIDValue } from "./VIDValue";
3
+ /**
4
+ * VID — Verifiable Identifier Engine
5
+ *
6
+ * This class is the main entry point for generating, verifying,
7
+ * and parsing VIDs.
8
+ *
9
+ * It encapsulates all configuration required for identifier generation,
10
+ * including cryptographic secret, key version, and node identity.
11
+ *
12
+ * This class is stateless beyond its configuration and safe to use
13
+ * in distributed environments.
14
+ *
15
+ * Example usage:
16
+ *
17
+ * ```ts
18
+ * const vid = VID.initialize({
19
+ * secret: process.env.VID_SECRET!,
20
+ * keyVersion: 1,
21
+ * nodeId: 42
22
+ * })
23
+ *
24
+ * const id = vid.generate()
25
+ *
26
+ * console.log(id.toString())
27
+ *
28
+ * const valid = vid.verify(id)
29
+ *
30
+ * const metadata = vid.parse(id)
31
+ * ```
32
+ *
33
+ * Configuration must be initialized once per service instance.
34
+ */
35
+ export declare class VID {
36
+ /**
37
+ * Cryptographic secret used for HMAC signing.
38
+ *
39
+ * Stored internally as byte array for deterministic cryptographic behavior.
40
+ */
41
+ private readonly secret;
42
+ /**
43
+ * Secret version identifier.
44
+ *
45
+ * Embedded in VID binary structure.
46
+ * Enables secret rotation.
47
+ */
48
+ private readonly keyVersion;
49
+ /**
50
+ * Unique identifier for this node.
51
+ *
52
+ * Prevents collisions in distributed systems.
53
+ */
54
+ private readonly nodeId;
55
+ /**
56
+ * Private constructor.
57
+ *
58
+ * Use VID.initialize() instead.
59
+ */
60
+ private constructor();
61
+ /**
62
+ * Initializes VID engine instance.
63
+ *
64
+ * This must be called before generating identifiers.
65
+ *
66
+ * @param options.secret Cryptographic secret string (required)
67
+ * @param options.keyVersion Secret version number (required)
68
+ * @param options.nodeId Optional node identifier
69
+ *
70
+ * @returns VID instance
71
+ *
72
+ * Throws error if configuration invalid.
73
+ */
74
+ static initialize(options: VIDOptions): VID;
75
+ /**
76
+ * Generates a new VID.
77
+ *
78
+ * @returns VIDValue object
79
+ *
80
+ * Thread-safe within Node.js event loop.
81
+ */
82
+ generate(): VIDValue;
83
+ /**
84
+ * Verifies VID authenticity.
85
+ *
86
+ * Ensures identifier was generated using correct secret.
87
+ *
88
+ * @param id VIDValue instance
89
+ *
90
+ * @returns true if valid, false otherwise
91
+ */
92
+ verify(input: string | Uint8Array | Buffer | ArrayBuffer): boolean;
93
+ /**
94
+ * Parses VID metadata.
95
+ *
96
+ * Extracts timestamp, nodeId, sequence, and keyVersion.
97
+ *
98
+ * @param id VIDValue instance
99
+ *
100
+ * @returns VIDMetadata
101
+ */
102
+ parse(input: string | Uint8Array | Buffer | ArrayBuffer): import("../types").VIDMetadata;
103
+ }
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VID = void 0;
4
+ const VIDGenerator_1 = require("./VIDGenerator");
5
+ const VIDVerifier_1 = require("./VIDVerifier");
6
+ const VIDParser_1 = require("./VIDParser");
7
+ /**
8
+ * VID — Verifiable Identifier Engine
9
+ *
10
+ * This class is the main entry point for generating, verifying,
11
+ * and parsing VIDs.
12
+ *
13
+ * It encapsulates all configuration required for identifier generation,
14
+ * including cryptographic secret, key version, and node identity.
15
+ *
16
+ * This class is stateless beyond its configuration and safe to use
17
+ * in distributed environments.
18
+ *
19
+ * Example usage:
20
+ *
21
+ * ```ts
22
+ * const vid = VID.initialize({
23
+ * secret: process.env.VID_SECRET!,
24
+ * keyVersion: 1,
25
+ * nodeId: 42
26
+ * })
27
+ *
28
+ * const id = vid.generate()
29
+ *
30
+ * console.log(id.toString())
31
+ *
32
+ * const valid = vid.verify(id)
33
+ *
34
+ * const metadata = vid.parse(id)
35
+ * ```
36
+ *
37
+ * Configuration must be initialized once per service instance.
38
+ */
39
+ class VID {
40
+ /**
41
+ * Private constructor.
42
+ *
43
+ * Use VID.initialize() instead.
44
+ */
45
+ constructor(options) {
46
+ // Validate options object
47
+ if (!options) {
48
+ throw new Error("VID initialization failed: options object is required");
49
+ }
50
+ /**
51
+ * Validate secret presence
52
+ */
53
+ if (options.secret === undefined || options.secret === null) {
54
+ throw new Error("VID initialization failed: secret is required");
55
+ }
56
+ /**
57
+ * Validate secret type
58
+ */
59
+ if (typeof options.secret !== "string") {
60
+ throw new Error("VID initialization failed: secret must be a string");
61
+ }
62
+ /**
63
+ * Validate secret length
64
+ */
65
+ if (options.secret.trim().length === 0) {
66
+ throw new Error("VID initialization failed: secret must not be empty");
67
+ }
68
+ if (options.secret.length < 8) {
69
+ throw new Error("VID initialization failed: secret must be at least 8 characters");
70
+ }
71
+ /**
72
+ * Validate keyVersion presence
73
+ */
74
+ if (options.keyVersion === undefined || options.keyVersion === null) {
75
+ throw new Error("VID initialization failed: keyVersion is required");
76
+ }
77
+ /**
78
+ * Validate keyVersion type
79
+ */
80
+ if (!Number.isInteger(options.keyVersion)) {
81
+ throw new Error("VID initialization failed: keyVersion must be an integer");
82
+ }
83
+ /**
84
+ * Validate keyVersion range
85
+ */
86
+ if (options.keyVersion < 0 || options.keyVersion > 255) {
87
+ throw new Error("VID initialization failed: keyVersion must be between 0 and 255");
88
+ }
89
+ /**
90
+ * Validate nodeId if provided
91
+ */
92
+ if (options.nodeId !== undefined) {
93
+ if (!Number.isInteger(options.nodeId)) {
94
+ throw new Error("VID initialization failed: nodeId must be an integer");
95
+ }
96
+ if (options.nodeId < 0 || options.nodeId > 65535) {
97
+ throw new Error("VID initialization failed: nodeId must be between 0 and 65535");
98
+ }
99
+ this.nodeId = options.nodeId;
100
+ }
101
+ else {
102
+ /**
103
+ * Auto-generate nodeId safely
104
+ *
105
+ * Uses process and time entropy to reduce collision risk.
106
+ */
107
+ this.nodeId = ((process.pid ^ Date.now()) & 0xffff);
108
+ }
109
+ /**
110
+ * Convert secret string to byte array
111
+ */
112
+ this.secret =
113
+ new TextEncoder().encode(options.secret);
114
+ this.keyVersion = options.keyVersion;
115
+ }
116
+ /**
117
+ * Initializes VID engine instance.
118
+ *
119
+ * This must be called before generating identifiers.
120
+ *
121
+ * @param options.secret Cryptographic secret string (required)
122
+ * @param options.keyVersion Secret version number (required)
123
+ * @param options.nodeId Optional node identifier
124
+ *
125
+ * @returns VID instance
126
+ *
127
+ * Throws error if configuration invalid.
128
+ */
129
+ static initialize(options) {
130
+ return new VID(options);
131
+ }
132
+ /**
133
+ * Generates a new VID.
134
+ *
135
+ * @returns VIDValue object
136
+ *
137
+ * Thread-safe within Node.js event loop.
138
+ */
139
+ generate() {
140
+ return VIDGenerator_1.VIDGenerator.generate({
141
+ secret: this.secret,
142
+ keyVersion: this.keyVersion,
143
+ nodeId: this.nodeId
144
+ });
145
+ }
146
+ /**
147
+ * Verifies VID authenticity.
148
+ *
149
+ * Ensures identifier was generated using correct secret.
150
+ *
151
+ * @param id VIDValue instance
152
+ *
153
+ * @returns true if valid, false otherwise
154
+ */
155
+ verify(input) {
156
+ return VIDVerifier_1.VIDVerifier.verify(input, this.secret);
157
+ }
158
+ /**
159
+ * Parses VID metadata.
160
+ *
161
+ * Extracts timestamp, nodeId, sequence, and keyVersion.
162
+ *
163
+ * @param id VIDValue instance
164
+ *
165
+ * @returns VIDMetadata
166
+ */
167
+ parse(input) {
168
+ return VIDParser_1.VIDParser.parse(input);
169
+ }
170
+ }
171
+ exports.VID = VID;
@@ -0,0 +1,53 @@
1
+ import { VIDValue } from "./VIDValue";
2
+ /**
3
+ * VIDGenerator is responsible for constructing VID binary identifiers.
4
+ *
5
+ * This class is INTERNAL and should never be used directly by library consumers.
6
+ *
7
+ * It assumes all inputs have already been validated by the VID class.
8
+ *
9
+ * Responsibilities:
10
+ *
11
+ * - Construct VID payload
12
+ * - Ensure per-millisecond uniqueness using sequence counter
13
+ * - Generate cryptographic signature
14
+ * - Combine payload and signature into final VID binary
15
+ *
16
+ * VID binary layout (18 bytes total):
17
+ *
18
+ * Byte 0 → keyVersion (1 byte)
19
+ *
20
+ * Bytes 1–6 → timestamp (6 bytes, milliseconds)
21
+ *
22
+ * Bytes 7–8 → nodeId (2 bytes)
23
+ *
24
+ * Bytes 9–10 → sequence (2 bytes)
25
+ *
26
+ * Bytes 11–17 → signature (7 bytes, HMAC truncated)
27
+ */
28
+ export declare class VIDGenerator {
29
+ /**
30
+ * Generates a new VIDValue instance.
31
+ *
32
+ * This method is called internally by VID.generate().
33
+ *
34
+ * @param config.secret Secret key (Uint8Array)
35
+ * @param config.keyVersion Secret version identifier
36
+ * @param config.nodeId Unique node identifier
37
+ *
38
+ * @returns VIDValue instance containing binary identifier
39
+ *
40
+ * Internal assumptions:
41
+ *
42
+ * - secret is valid Uint8Array
43
+ * - keyVersion is valid uint8
44
+ * - nodeId is valid uint16
45
+ *
46
+ * These guarantees are enforced by VID.initialize().
47
+ */
48
+ static generate(config: {
49
+ secret: Uint8Array;
50
+ keyVersion: number;
51
+ nodeId: number;
52
+ }): VIDValue;
53
+ }
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VIDGenerator = void 0;
4
+ const ByteUtils_1 = require("../utils/ByteUtils");
5
+ const HMACSigner_1 = require("../crypto/HMACSigner");
6
+ const VIDValue_1 = require("./VIDValue");
7
+ /**
8
+ * Internal timestamp tracker.
9
+ *
10
+ * Used to detect multiple ID generation events within the same millisecond.
11
+ *
12
+ * Ensures monotonic uniqueness when generating high volumes of IDs.
13
+ */
14
+ let lastTimestamp = 0;
15
+ /**
16
+ * Per-millisecond sequence counter.
17
+ *
18
+ * Prevents collisions when multiple identifiers are generated within the same millisecond.
19
+ *
20
+ * Range: 0–65535 (uint16)
21
+ */
22
+ let sequence = 0;
23
+ /**
24
+ * VIDGenerator is responsible for constructing VID binary identifiers.
25
+ *
26
+ * This class is INTERNAL and should never be used directly by library consumers.
27
+ *
28
+ * It assumes all inputs have already been validated by the VID class.
29
+ *
30
+ * Responsibilities:
31
+ *
32
+ * - Construct VID payload
33
+ * - Ensure per-millisecond uniqueness using sequence counter
34
+ * - Generate cryptographic signature
35
+ * - Combine payload and signature into final VID binary
36
+ *
37
+ * VID binary layout (18 bytes total):
38
+ *
39
+ * Byte 0 → keyVersion (1 byte)
40
+ *
41
+ * Bytes 1–6 → timestamp (6 bytes, milliseconds)
42
+ *
43
+ * Bytes 7–8 → nodeId (2 bytes)
44
+ *
45
+ * Bytes 9–10 → sequence (2 bytes)
46
+ *
47
+ * Bytes 11–17 → signature (7 bytes, HMAC truncated)
48
+ */
49
+ class VIDGenerator {
50
+ /**
51
+ * Generates a new VIDValue instance.
52
+ *
53
+ * This method is called internally by VID.generate().
54
+ *
55
+ * @param config.secret Secret key (Uint8Array)
56
+ * @param config.keyVersion Secret version identifier
57
+ * @param config.nodeId Unique node identifier
58
+ *
59
+ * @returns VIDValue instance containing binary identifier
60
+ *
61
+ * Internal assumptions:
62
+ *
63
+ * - secret is valid Uint8Array
64
+ * - keyVersion is valid uint8
65
+ * - nodeId is valid uint16
66
+ *
67
+ * These guarantees are enforced by VID.initialize().
68
+ */
69
+ static generate(config) {
70
+ /**
71
+ * Get current timestamp in milliseconds.
72
+ */
73
+ let timestamp = Date.now();
74
+ /**
75
+ * Handle same-millisecond generation.
76
+ *
77
+ * If generating multiple IDs within same millisecond,
78
+ * increment sequence counter.
79
+ */
80
+ if (timestamp === lastTimestamp) {
81
+ sequence++;
82
+ /**
83
+ * Prevent uint16 overflow.
84
+ *
85
+ * More than 65,536 IDs per millisecond is extremely unlikely.
86
+ */
87
+ if (sequence > 65535) {
88
+ throw new Error("VID generation overflow: too many IDs generated in same millisecond");
89
+ }
90
+ }
91
+ else {
92
+ sequence = 0;
93
+ lastTimestamp = timestamp;
94
+ }
95
+ /**
96
+ * Construct payload buffer (11 bytes).
97
+ *
98
+ * Payload contains core identifier data excluding signature.
99
+ */
100
+ const payload = new Uint8Array(11);
101
+ const view = new DataView(payload.buffer);
102
+ /**
103
+ * Byte 0 → keyVersion
104
+ */
105
+ view.setUint8(0, config.keyVersion);
106
+ /**
107
+ * Bytes 1–6 → timestamp (48-bit)
108
+ *
109
+ * Split into:
110
+ *
111
+ * high 32 bits → bytes 1–4
112
+ * low 16 bits → bytes 5–6
113
+ */
114
+ view.setUint32(1, Math.floor(timestamp / 65536));
115
+ view.setUint16(5, timestamp % 65536);
116
+ /**
117
+ * Bytes 7–8 → nodeId
118
+ */
119
+ view.setUint16(7, config.nodeId);
120
+ /**
121
+ * Bytes 9–10 → sequence
122
+ */
123
+ view.setUint16(9, sequence);
124
+ /**
125
+ * Generate cryptographic signature.
126
+ *
127
+ * Signature ensures identifier authenticity.
128
+ */
129
+ const signature = HMACSigner_1.HMACSigner.sign(payload, config.secret);
130
+ /**
131
+ * Combine payload and signature into final binary identifier.
132
+ */
133
+ const binary = ByteUtils_1.ByteUtils.concat(payload, signature);
134
+ /**
135
+ * Return VIDValue instance.
136
+ */
137
+ return new VIDValue_1.VIDValue(binary);
138
+ }
139
+ }
140
+ exports.VIDGenerator = VIDGenerator;
@@ -0,0 +1,49 @@
1
+ import { VIDMetadata } from "../types";
2
+ /**
3
+ * VIDParser
4
+ *
5
+ * Responsible for extracting metadata from a VID identifier.
6
+ *
7
+ * This class does NOT perform cryptographic verification.
8
+ * It only decodes structural fields embedded in the VID.
9
+ *
10
+ * Supported input formats:
11
+ *
12
+ * - Base32 string
13
+ * - Uint8Array
14
+ * - Buffer (Node.js)
15
+ * - ArrayBuffer
16
+ *
17
+ * VID binary layout (18 bytes total):
18
+ *
19
+ * Byte 0 → keyVersion (1 byte)
20
+ * Bytes 1–6 → timestamp (6 bytes, 48-bit)
21
+ * Bytes 7–8 → nodeId (2 bytes)
22
+ * Bytes 9–10 → sequence (2 bytes)
23
+ * Bytes 11–17 → signature (7 bytes)
24
+ *
25
+ * Returned metadata does NOT include signature.
26
+ */
27
+ export declare class VIDParser {
28
+ /**
29
+ * Parses VID and extracts metadata fields.
30
+ *
31
+ * @param input VID in string or binary format
32
+ *
33
+ * @returns VIDMetadata object containing:
34
+ *
35
+ * - keyVersion → secret version used
36
+ * - timestamp → creation timestamp (ms)
37
+ * - nodeId → generator node identifier
38
+ * - sequence → per-ms sequence counter
39
+ *
40
+ * Throws error for invalid input structure.
41
+ */
42
+ static parse(input: string | Uint8Array | Buffer | ArrayBuffer): VIDMetadata;
43
+ /**
44
+ * Normalizes input into canonical Uint8Array.
45
+ *
46
+ * Accepts string, Buffer, Uint8Array, ArrayBuffer.
47
+ */
48
+ private static normalizeToBinary;
49
+ }
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VIDParser = void 0;
4
+ const Base32Decoder_1 = require("../encoding/Base32Decoder");
5
+ /**
6
+ * VIDParser
7
+ *
8
+ * Responsible for extracting metadata from a VID identifier.
9
+ *
10
+ * This class does NOT perform cryptographic verification.
11
+ * It only decodes structural fields embedded in the VID.
12
+ *
13
+ * Supported input formats:
14
+ *
15
+ * - Base32 string
16
+ * - Uint8Array
17
+ * - Buffer (Node.js)
18
+ * - ArrayBuffer
19
+ *
20
+ * VID binary layout (18 bytes total):
21
+ *
22
+ * Byte 0 → keyVersion (1 byte)
23
+ * Bytes 1–6 → timestamp (6 bytes, 48-bit)
24
+ * Bytes 7–8 → nodeId (2 bytes)
25
+ * Bytes 9–10 → sequence (2 bytes)
26
+ * Bytes 11–17 → signature (7 bytes)
27
+ *
28
+ * Returned metadata does NOT include signature.
29
+ */
30
+ class VIDParser {
31
+ /**
32
+ * Parses VID and extracts metadata fields.
33
+ *
34
+ * @param input VID in string or binary format
35
+ *
36
+ * @returns VIDMetadata object containing:
37
+ *
38
+ * - keyVersion → secret version used
39
+ * - timestamp → creation timestamp (ms)
40
+ * - nodeId → generator node identifier
41
+ * - sequence → per-ms sequence counter
42
+ *
43
+ * Throws error for invalid input structure.
44
+ */
45
+ static parse(input) {
46
+ const binary = this.normalizeToBinary(input);
47
+ if (binary.length !== 18) {
48
+ throw new Error("VID parse failed: invalid VID length");
49
+ }
50
+ const view = new DataView(binary.buffer, binary.byteOffset, binary.byteLength);
51
+ /**
52
+ * Extract keyVersion (1 byte)
53
+ */
54
+ const keyVersion = view.getUint8(0);
55
+ /**
56
+ * Extract timestamp (48-bit)
57
+ *
58
+ * Recombine:
59
+ *
60
+ * high 32 bits → bytes 1–4
61
+ * low 16 bits → bytes 5–6
62
+ */
63
+ const timestamp = view.getUint32(1) * 65536 +
64
+ view.getUint16(5);
65
+ /**
66
+ * Extract nodeId (2 bytes)
67
+ */
68
+ const nodeId = view.getUint16(7);
69
+ /**
70
+ * Extract sequence (2 bytes)
71
+ */
72
+ const sequence = view.getUint16(9);
73
+ /**
74
+ * Optional derived fields for usability
75
+ */
76
+ const date = new Date(timestamp);
77
+ const iso = date.toISOString();
78
+ return {
79
+ keyVersion,
80
+ timestamp,
81
+ nodeId,
82
+ sequence,
83
+ /**
84
+ * Helpful derived values
85
+ */
86
+ date,
87
+ iso
88
+ };
89
+ }
90
+ /**
91
+ * Normalizes input into canonical Uint8Array.
92
+ *
93
+ * Accepts string, Buffer, Uint8Array, ArrayBuffer.
94
+ */
95
+ static normalizeToBinary(input) {
96
+ if (input === null || input === undefined) {
97
+ throw new Error("VID parse failed: input is required");
98
+ }
99
+ /**
100
+ * Handle Base32 string
101
+ */
102
+ if (typeof input === "string") {
103
+ const trimmed = input.trim();
104
+ if (trimmed.length === 0) {
105
+ throw new Error("VID parse failed: empty string");
106
+ }
107
+ try {
108
+ return Base32Decoder_1.Base32Decoder.decode(trimmed);
109
+ }
110
+ catch {
111
+ throw new Error("VID parse failed: invalid string encoding");
112
+ }
113
+ }
114
+ /**
115
+ * Handle Uint8Array
116
+ */
117
+ if (input instanceof Uint8Array) {
118
+ return input;
119
+ }
120
+ /**
121
+ * Handle Node.js Buffer
122
+ */
123
+ if (typeof Buffer !== "undefined" &&
124
+ Buffer.isBuffer(input)) {
125
+ return new Uint8Array(input);
126
+ }
127
+ /**
128
+ * Handle ArrayBuffer
129
+ */
130
+ if (input instanceof ArrayBuffer) {
131
+ return new Uint8Array(input);
132
+ }
133
+ throw new Error("VID parse failed: unsupported input type");
134
+ }
135
+ }
136
+ exports.VIDParser = VIDParser;
@@ -0,0 +1,25 @@
1
+ export declare class VIDValue {
2
+ private readonly binary;
3
+ constructor(binary: Uint8Array);
4
+ /**
5
+ * Returns Base32 string representation.
6
+ *
7
+ * Recommended for:
8
+ * - APIs
9
+ * - logging
10
+ * - debugging
11
+ * - external communication
12
+ */
13
+ toString(): string;
14
+ /**
15
+ * Returns binary representation.
16
+ *
17
+ * Recommended for:
18
+ * - MongoDB Binary
19
+ * - PostgreSQL BYTEA
20
+ * - Redis
21
+ *
22
+ * Saves database space and improves index performance.
23
+ */
24
+ toBinary(): Uint8Array;
25
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VIDValue = void 0;
4
+ const Base32Encoder_1 = require("../encoding/Base32Encoder");
5
+ class VIDValue {
6
+ constructor(binary) {
7
+ if (!binary || binary.length !== 18) {
8
+ throw new Error("Invalid VID binary");
9
+ }
10
+ this.binary = binary;
11
+ }
12
+ /**
13
+ * Returns Base32 string representation.
14
+ *
15
+ * Recommended for:
16
+ * - APIs
17
+ * - logging
18
+ * - debugging
19
+ * - external communication
20
+ */
21
+ toString() {
22
+ return Base32Encoder_1.Base32Encoder.encode(this.binary);
23
+ }
24
+ /**
25
+ * Returns binary representation.
26
+ *
27
+ * Recommended for:
28
+ * - MongoDB Binary
29
+ * - PostgreSQL BYTEA
30
+ * - Redis
31
+ *
32
+ * Saves database space and improves index performance.
33
+ */
34
+ toBinary() {
35
+ return this.binary;
36
+ }
37
+ }
38
+ exports.VIDValue = VIDValue;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * VIDVerifier
3
+ *
4
+ * Central verification engine for VID identifiers.
5
+ *
6
+ * Responsibilities:
7
+ *
8
+ * - Accept user input in multiple formats
9
+ * - Normalize input into canonical binary form
10
+ * - Validate VID structure
11
+ * - Verify cryptographic authenticity
12
+ *
13
+ * Supported input formats:
14
+ *
15
+ * - Base32 string
16
+ * - Uint8Array
17
+ * - Node.js Buffer
18
+ * - ArrayBuffer
19
+ *
20
+ * VID binary layout (18 bytes):
21
+ *
22
+ * Bytes 0–10 → payload
23
+ * Bytes 11–17 → signature
24
+ */
25
+ export declare class VIDVerifier {
26
+ /**
27
+ * Public verification method.
28
+ *
29
+ * Accepts flexible input formats and verifies VID authenticity.
30
+ *
31
+ * @param input VID in string or binary format
32
+ * @param secret secret key used for signing
33
+ *
34
+ * @returns true if valid
35
+ * @returns false if invalid or tampered
36
+ */
37
+ static verify(input: string | Uint8Array | Buffer | ArrayBuffer, secret: Uint8Array): boolean;
38
+ /**
39
+ * Converts user input into Uint8Array.
40
+ *
41
+ * Handles all supported transport formats.
42
+ */
43
+ private static normalizeToBinary;
44
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VIDVerifier = void 0;
4
+ const HMACSigner_1 = require("../crypto/HMACSigner");
5
+ const Base32Decoder_1 = require("../encoding/Base32Decoder");
6
+ /**
7
+ * VIDVerifier
8
+ *
9
+ * Central verification engine for VID identifiers.
10
+ *
11
+ * Responsibilities:
12
+ *
13
+ * - Accept user input in multiple formats
14
+ * - Normalize input into canonical binary form
15
+ * - Validate VID structure
16
+ * - Verify cryptographic authenticity
17
+ *
18
+ * Supported input formats:
19
+ *
20
+ * - Base32 string
21
+ * - Uint8Array
22
+ * - Node.js Buffer
23
+ * - ArrayBuffer
24
+ *
25
+ * VID binary layout (18 bytes):
26
+ *
27
+ * Bytes 0–10 → payload
28
+ * Bytes 11–17 → signature
29
+ */
30
+ class VIDVerifier {
31
+ /**
32
+ * Public verification method.
33
+ *
34
+ * Accepts flexible input formats and verifies VID authenticity.
35
+ *
36
+ * @param input VID in string or binary format
37
+ * @param secret secret key used for signing
38
+ *
39
+ * @returns true if valid
40
+ * @returns false if invalid or tampered
41
+ */
42
+ static verify(input, secret) {
43
+ if (!secret || !(secret instanceof Uint8Array)) {
44
+ throw new Error("VID verification failed: valid secret is required");
45
+ }
46
+ const binary = this.normalizeToBinary(input);
47
+ if (binary.length !== 18) {
48
+ return false;
49
+ }
50
+ const payload = binary.slice(0, 11);
51
+ const signature = binary.slice(11, 18);
52
+ return HMACSigner_1.HMACSigner.verify(payload, signature, secret);
53
+ }
54
+ /**
55
+ * Converts user input into Uint8Array.
56
+ *
57
+ * Handles all supported transport formats.
58
+ */
59
+ static normalizeToBinary(input) {
60
+ if (input === null || input === undefined) {
61
+ throw new Error("VID verification failed: input is required");
62
+ }
63
+ /**
64
+ * String input (Base32)
65
+ */
66
+ if (typeof input === "string") {
67
+ const trimmed = input.trim();
68
+ if (trimmed.length === 0) {
69
+ throw new Error("VID verification failed: empty string");
70
+ }
71
+ try {
72
+ return Base32Decoder_1.Base32Decoder.decode(trimmed);
73
+ }
74
+ catch {
75
+ throw new Error("VID verification failed: invalid string encoding");
76
+ }
77
+ }
78
+ /**
79
+ * Uint8Array input
80
+ */
81
+ if (input instanceof Uint8Array) {
82
+ return input;
83
+ }
84
+ /**
85
+ * Buffer input
86
+ */
87
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(input)) {
88
+ return new Uint8Array(input);
89
+ }
90
+ /**
91
+ * ArrayBuffer input
92
+ */
93
+ if (input instanceof ArrayBuffer) {
94
+ return new Uint8Array(input);
95
+ }
96
+ throw new Error("VID verification failed: unsupported input type");
97
+ }
98
+ }
99
+ exports.VIDVerifier = VIDVerifier;
@@ -0,0 +1,5 @@
1
+ export declare class HMACSigner {
2
+ private static SIGNATURE_LENGTH;
3
+ static sign(payload: Uint8Array, secret: Uint8Array): Uint8Array;
4
+ static verify(payload: Uint8Array, signature: Uint8Array, secret: Uint8Array): boolean;
5
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HMACSigner = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ class HMACSigner {
9
+ static sign(payload, secret) {
10
+ const hmac = crypto_1.default.createHmac("sha256", secret);
11
+ hmac.update(payload);
12
+ const fullSignature = hmac.digest();
13
+ return new Uint8Array(fullSignature.slice(0, this.SIGNATURE_LENGTH));
14
+ }
15
+ static verify(payload, signature, secret) {
16
+ if (!payload ||
17
+ !signature ||
18
+ !secret) {
19
+ return false;
20
+ }
21
+ if (signature.length !== this.SIGNATURE_LENGTH) {
22
+ return false;
23
+ }
24
+ const expected = this.sign(payload, secret);
25
+ const expectedBuffer = Buffer.from(expected);
26
+ const signatureBuffer = Buffer.from(signature);
27
+ if (expectedBuffer.length !== signatureBuffer.length) {
28
+ return false;
29
+ }
30
+ return crypto_1.default.timingSafeEqual(expectedBuffer, signatureBuffer);
31
+ }
32
+ }
33
+ exports.HMACSigner = HMACSigner;
34
+ HMACSigner.SIGNATURE_LENGTH = 7;
@@ -0,0 +1,3 @@
1
+ export declare class Base32Decoder {
2
+ static decode(str: string): Uint8Array;
3
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Base32Decoder = void 0;
4
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
5
+ class Base32Decoder {
6
+ static decode(str) {
7
+ let bits = 0;
8
+ let value = 0;
9
+ const out = [];
10
+ for (const c of str) {
11
+ const idx = alphabet.indexOf(c);
12
+ if (idx === -1)
13
+ throw new Error("Invalid Base32");
14
+ value = (value << 5) | idx;
15
+ bits += 5;
16
+ if (bits >= 8) {
17
+ out.push((value >>> (bits - 8)) & 255);
18
+ bits -= 8;
19
+ }
20
+ }
21
+ return new Uint8Array(out);
22
+ }
23
+ }
24
+ exports.Base32Decoder = Base32Decoder;
@@ -0,0 +1,3 @@
1
+ export declare class Base32Encoder {
2
+ static encode(data: Uint8Array): string;
3
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Base32Encoder = void 0;
4
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
5
+ class Base32Encoder {
6
+ static encode(data) {
7
+ let bits = 0;
8
+ let value = 0;
9
+ let output = "";
10
+ for (const byte of data) {
11
+ value = (value << 8) | byte;
12
+ bits += 8;
13
+ while (bits >= 5) {
14
+ output += alphabet[(value >>> (bits - 5)) & 31];
15
+ bits -= 5;
16
+ }
17
+ }
18
+ if (bits > 0) {
19
+ output += alphabet[(value << (5 - bits)) & 31];
20
+ }
21
+ return output;
22
+ }
23
+ }
24
+ exports.Base32Encoder = Base32Encoder;
@@ -0,0 +1 @@
1
+ export { VID } from "./core/VID";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VID = void 0;
4
+ var VID_1 = require("./core/VID");
5
+ Object.defineProperty(exports, "VID", { enumerable: true, get: function () { return VID_1.VID; } });
@@ -0,0 +1,13 @@
1
+ export interface VIDOptions {
2
+ secret: string;
3
+ keyVersion: number;
4
+ nodeId?: number;
5
+ }
6
+ export interface VIDMetadata {
7
+ keyVersion: number;
8
+ timestamp: number;
9
+ date: Date;
10
+ nodeId: number;
11
+ sequence: number;
12
+ iso: string;
13
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ export declare class ByteUtils {
2
+ static concat(a: Uint8Array, b: Uint8Array): Uint8Array;
3
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ByteUtils = void 0;
4
+ class ByteUtils {
5
+ static concat(a, b) {
6
+ const out = new Uint8Array(a.length + b.length);
7
+ out.set(a, 0);
8
+ out.set(b, a.length);
9
+ return out;
10
+ }
11
+ }
12
+ exports.ByteUtils = ByteUtils;
@@ -0,0 +1,3 @@
1
+ export declare class TimeUtils {
2
+ static now(): number;
3
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimeUtils = void 0;
4
+ class TimeUtils {
5
+ static now() {
6
+ return Date.now();
7
+ }
8
+ }
9
+ exports.TimeUtils = TimeUtils;
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@veridjs/core",
3
+ "version": "1.0.0",
4
+ "description": "Verifiable Identifier for distributed systems",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": "./dist/index.js",
9
+ "./postgres": "./dist/adapters/VIDPostgresAdapter.js",
10
+ "./mongo": "./dist/adapters/VIDMongoAdapter.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc"
19
+ },
20
+ "keywords": [
21
+ "identifier",
22
+ "uuid",
23
+ "vid",
24
+ "distributed"
25
+ ],
26
+ "author": "Kishan Kumar",
27
+ "license": "MIT",
28
+ "devDependencies": {
29
+ "@types/node": "^25.2.3",
30
+ "@types/pg": "^8.16.0",
31
+ "ts-node": "^10.9.2",
32
+ "typescript": "^5.9.3"
33
+ },
34
+ "dependencies": {}
35
+ }