@ewanc26/tid 1.0.3 → 1.1.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/dist/index.cjs CHANGED
@@ -20,11 +20,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ InvalidTidError: () => InvalidTidError,
24
+ areMonotonic: () => areMonotonic,
23
25
  compareTids: () => compareTids,
24
26
  decodeTid: () => decodeTid,
27
+ decodeTidClockId: () => decodeTidClockId,
28
+ decodeTidTimestamp: () => decodeTidTimestamp,
29
+ ensureValidTid: () => ensureValidTid,
25
30
  generateNextTID: () => generateNextTID,
26
31
  generateTID: () => generateTID,
32
+ getTidClockState: () => getTidClockState,
27
33
  resetTidClock: () => resetTidClock,
34
+ seedTidClock: () => seedTidClock,
28
35
  validateTid: () => validateTid
29
36
  });
30
37
  module.exports = __toCommonJS(index_exports);
@@ -50,25 +57,45 @@ var TID_RE = /^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/;
50
57
  function validateTid(tid) {
51
58
  return TID_RE.test(tid);
52
59
  }
60
+ var InvalidTidError = class extends Error {
61
+ constructor(message, tid) {
62
+ super(message);
63
+ this.tid = tid;
64
+ this.name = "InvalidTidError";
65
+ }
66
+ };
67
+ function ensureValidTid(tid) {
68
+ if (!validateTid(tid)) {
69
+ throw new InvalidTidError(`Invalid TID format: "${tid}"`, tid);
70
+ }
71
+ }
53
72
  function decodeTid(tid) {
54
73
  if (!validateTid(tid)) throw new TypeError(`Invalid TID: "${tid}"`);
55
74
  const timestampUs = s32decode(tid.slice(0, 11));
56
- const clockId = s32decode(tid.slice(11));
57
- return { timestampUs, clockId, date: new Date(Math.floor(timestampUs / 1e3)) };
75
+ const decodedClockId = s32decode(tid.slice(11));
76
+ return { timestampUs, clockId: decodedClockId, date: new Date(Math.floor(timestampUs / 1e3)) };
77
+ }
78
+ function decodeTidTimestamp(tid) {
79
+ return decodeTid(tid).timestampUs;
80
+ }
81
+ function decodeTidClockId(tid) {
82
+ return decodeTid(tid).clockId;
58
83
  }
59
84
  var lastUs = 0;
60
- var CLOCK_ID = (() => {
85
+ var clockId = (() => {
61
86
  const buf = new Uint8Array(1);
62
87
  (globalThis.crypto ?? globalThis.webcrypto).getRandomValues(buf);
63
88
  return buf[0] % 32;
64
89
  })();
90
+ var generatedCount = 0;
65
91
  function nextUs(targetUs) {
66
92
  const us = targetUs <= lastUs ? lastUs + 1 : targetUs;
67
93
  lastUs = us;
94
+ generatedCount++;
68
95
  return us;
69
96
  }
70
97
  function makeTid(us) {
71
- return s32encode(us).padStart(11, "2") + s32encode(CLOCK_ID).padStart(2, "2");
98
+ return s32encode(us).padStart(11, "2") + s32encode(clockId).padStart(2, "2");
72
99
  }
73
100
  function generateTID(source) {
74
101
  const ms = typeof source === "string" ? new Date(source).getTime() : source.getTime();
@@ -82,15 +109,37 @@ function compareTids(a, b) {
82
109
  if (a > b) return 1;
83
110
  return 0;
84
111
  }
112
+ function areMonotonic(tids) {
113
+ for (let i = 1; i < tids.length; i++) {
114
+ if (tids[i] <= tids[i - 1]) return false;
115
+ }
116
+ return true;
117
+ }
118
+ function getTidClockState() {
119
+ return { lastTimestampUs: lastUs, clockId, generatedCount };
120
+ }
85
121
  function resetTidClock() {
86
122
  lastUs = 0;
123
+ generatedCount = 0;
124
+ }
125
+ function seedTidClock(startUs = 0, newClockId = 0) {
126
+ lastUs = startUs;
127
+ clockId = newClockId % 32;
128
+ generatedCount = 0;
87
129
  }
88
130
  // Annotate the CommonJS export names for ESM import in node:
89
131
  0 && (module.exports = {
132
+ InvalidTidError,
133
+ areMonotonic,
90
134
  compareTids,
91
135
  decodeTid,
136
+ decodeTidClockId,
137
+ decodeTidTimestamp,
138
+ ensureValidTid,
92
139
  generateNextTID,
93
140
  generateTID,
141
+ getTidClockState,
94
142
  resetTidClock,
143
+ seedTidClock,
95
144
  validateTid
96
145
  });
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @malachite/tid — AT Protocol TID generation
2
+ * @ewanc26/tid — AT Protocol TID generation
3
3
  *
4
4
  * Zero-dependency, spec-compliant TID (Timestamp Identifier) generation for
5
5
  * the AT Protocol. Works in Node.js 20+ and all modern browsers.
@@ -10,6 +10,18 @@
10
10
  * Returns `true` if `tid` is a well-formed AT Protocol TID.
11
11
  */
12
12
  declare function validateTid(tid: string): boolean;
13
+ /**
14
+ * Error thrown by `ensureValidTid` when a TID fails validation.
15
+ */
16
+ declare class InvalidTidError extends Error {
17
+ readonly tid?: string | undefined;
18
+ constructor(message: string, tid?: string | undefined);
19
+ }
20
+ /**
21
+ * Assert that `tid` is a valid AT Protocol TID.
22
+ * Throws `InvalidTidError` if the format check fails.
23
+ */
24
+ declare function ensureValidTid(tid: string): asserts tid is string;
13
25
  interface DecodedTid {
14
26
  /** Microseconds since the Unix epoch. */
15
27
  timestampUs: number;
@@ -23,6 +35,16 @@ interface DecodedTid {
23
35
  * Throws a `TypeError` if the TID is malformed.
24
36
  */
25
37
  declare function decodeTid(tid: string): DecodedTid;
38
+ /**
39
+ * Decode a TID and return only the microsecond timestamp.
40
+ * Prefer `decodeTid` for new code.
41
+ */
42
+ declare function decodeTidTimestamp(tid: string): number;
43
+ /**
44
+ * Decode a TID and return only the clock identifier.
45
+ * Prefer `decodeTid` for new code.
46
+ */
47
+ declare function decodeTidClockId(tid: string): number;
26
48
  /**
27
49
  * Generate a TID for a historical timestamp.
28
50
  *
@@ -51,12 +73,50 @@ declare function generateNextTID(): string;
51
73
  * Returns `-1`, `0`, or `1` (suitable as a `Array.prototype.sort` comparator).
52
74
  */
53
75
  declare function compareTids(a: string, b: string): -1 | 0 | 1;
76
+ /**
77
+ * Returns `true` if every TID in the array is strictly greater than the one
78
+ * before it (lexicographic / chronological order).
79
+ */
80
+ declare function areMonotonic(tids: string[]): boolean;
81
+ /**
82
+ * Snapshot of the module-level clock state.
83
+ * Intended for debugging and test assertions.
84
+ */
85
+ interface TidClockState {
86
+ lastTimestampUs: number;
87
+ clockId: number;
88
+ generatedCount: number;
89
+ }
90
+ /**
91
+ * Return a snapshot of the current clock state.
92
+ * Useful for asserting counts in tests.
93
+ */
94
+ declare function getTidClockState(): TidClockState;
54
95
  /**
55
96
  * Reset the module-level monotonic clock to zero.
97
+ * Resets `lastTimestampUs` and `generatedCount` but preserves `clockId`.
56
98
  *
57
99
  * **Only use this in tests.** Calling it in production risks generating
58
100
  * duplicate or non-monotonic TIDs.
59
101
  */
60
102
  declare function resetTidClock(): void;
103
+ /**
104
+ * Seed the clock with a fixed starting timestamp and clock identifier,
105
+ * making all subsequent TID generation deterministic.
106
+ *
107
+ * - `startUs` becomes the floor for the next generated timestamp (µs).
108
+ * - `newClockId` overrides the random clock identifier (0–31, default 0).
109
+ * - `generatedCount` is reset to 0.
110
+ *
111
+ * **Only use this in tests.**
112
+ *
113
+ * @example
114
+ * seedTidClock(1_000_000_000_000_000, 0);
115
+ * const tid1 = generateNextTID();
116
+ * seedTidClock(1_000_000_000_000_000, 0);
117
+ * const tid2 = generateNextTID();
118
+ * // tid1 === tid2
119
+ */
120
+ declare function seedTidClock(startUs?: number, newClockId?: number): void;
61
121
 
62
- export { type DecodedTid, compareTids, decodeTid, generateNextTID, generateTID, resetTidClock, validateTid };
122
+ export { type DecodedTid, InvalidTidError, type TidClockState, areMonotonic, compareTids, decodeTid, decodeTidClockId, decodeTidTimestamp, ensureValidTid, generateNextTID, generateTID, getTidClockState, resetTidClock, seedTidClock, validateTid };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @malachite/tid — AT Protocol TID generation
2
+ * @ewanc26/tid — AT Protocol TID generation
3
3
  *
4
4
  * Zero-dependency, spec-compliant TID (Timestamp Identifier) generation for
5
5
  * the AT Protocol. Works in Node.js 20+ and all modern browsers.
@@ -10,6 +10,18 @@
10
10
  * Returns `true` if `tid` is a well-formed AT Protocol TID.
11
11
  */
12
12
  declare function validateTid(tid: string): boolean;
13
+ /**
14
+ * Error thrown by `ensureValidTid` when a TID fails validation.
15
+ */
16
+ declare class InvalidTidError extends Error {
17
+ readonly tid?: string | undefined;
18
+ constructor(message: string, tid?: string | undefined);
19
+ }
20
+ /**
21
+ * Assert that `tid` is a valid AT Protocol TID.
22
+ * Throws `InvalidTidError` if the format check fails.
23
+ */
24
+ declare function ensureValidTid(tid: string): asserts tid is string;
13
25
  interface DecodedTid {
14
26
  /** Microseconds since the Unix epoch. */
15
27
  timestampUs: number;
@@ -23,6 +35,16 @@ interface DecodedTid {
23
35
  * Throws a `TypeError` if the TID is malformed.
24
36
  */
25
37
  declare function decodeTid(tid: string): DecodedTid;
38
+ /**
39
+ * Decode a TID and return only the microsecond timestamp.
40
+ * Prefer `decodeTid` for new code.
41
+ */
42
+ declare function decodeTidTimestamp(tid: string): number;
43
+ /**
44
+ * Decode a TID and return only the clock identifier.
45
+ * Prefer `decodeTid` for new code.
46
+ */
47
+ declare function decodeTidClockId(tid: string): number;
26
48
  /**
27
49
  * Generate a TID for a historical timestamp.
28
50
  *
@@ -51,12 +73,50 @@ declare function generateNextTID(): string;
51
73
  * Returns `-1`, `0`, or `1` (suitable as a `Array.prototype.sort` comparator).
52
74
  */
53
75
  declare function compareTids(a: string, b: string): -1 | 0 | 1;
76
+ /**
77
+ * Returns `true` if every TID in the array is strictly greater than the one
78
+ * before it (lexicographic / chronological order).
79
+ */
80
+ declare function areMonotonic(tids: string[]): boolean;
81
+ /**
82
+ * Snapshot of the module-level clock state.
83
+ * Intended for debugging and test assertions.
84
+ */
85
+ interface TidClockState {
86
+ lastTimestampUs: number;
87
+ clockId: number;
88
+ generatedCount: number;
89
+ }
90
+ /**
91
+ * Return a snapshot of the current clock state.
92
+ * Useful for asserting counts in tests.
93
+ */
94
+ declare function getTidClockState(): TidClockState;
54
95
  /**
55
96
  * Reset the module-level monotonic clock to zero.
97
+ * Resets `lastTimestampUs` and `generatedCount` but preserves `clockId`.
56
98
  *
57
99
  * **Only use this in tests.** Calling it in production risks generating
58
100
  * duplicate or non-monotonic TIDs.
59
101
  */
60
102
  declare function resetTidClock(): void;
103
+ /**
104
+ * Seed the clock with a fixed starting timestamp and clock identifier,
105
+ * making all subsequent TID generation deterministic.
106
+ *
107
+ * - `startUs` becomes the floor for the next generated timestamp (µs).
108
+ * - `newClockId` overrides the random clock identifier (0–31, default 0).
109
+ * - `generatedCount` is reset to 0.
110
+ *
111
+ * **Only use this in tests.**
112
+ *
113
+ * @example
114
+ * seedTidClock(1_000_000_000_000_000, 0);
115
+ * const tid1 = generateNextTID();
116
+ * seedTidClock(1_000_000_000_000_000, 0);
117
+ * const tid2 = generateNextTID();
118
+ * // tid1 === tid2
119
+ */
120
+ declare function seedTidClock(startUs?: number, newClockId?: number): void;
61
121
 
62
- export { type DecodedTid, compareTids, decodeTid, generateNextTID, generateTID, resetTidClock, validateTid };
122
+ export { type DecodedTid, InvalidTidError, type TidClockState, areMonotonic, compareTids, decodeTid, decodeTidClockId, decodeTidTimestamp, ensureValidTid, generateNextTID, generateTID, getTidClockState, resetTidClock, seedTidClock, validateTid };
package/dist/index.js CHANGED
@@ -21,25 +21,45 @@ var TID_RE = /^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/;
21
21
  function validateTid(tid) {
22
22
  return TID_RE.test(tid);
23
23
  }
24
+ var InvalidTidError = class extends Error {
25
+ constructor(message, tid) {
26
+ super(message);
27
+ this.tid = tid;
28
+ this.name = "InvalidTidError";
29
+ }
30
+ };
31
+ function ensureValidTid(tid) {
32
+ if (!validateTid(tid)) {
33
+ throw new InvalidTidError(`Invalid TID format: "${tid}"`, tid);
34
+ }
35
+ }
24
36
  function decodeTid(tid) {
25
37
  if (!validateTid(tid)) throw new TypeError(`Invalid TID: "${tid}"`);
26
38
  const timestampUs = s32decode(tid.slice(0, 11));
27
- const clockId = s32decode(tid.slice(11));
28
- return { timestampUs, clockId, date: new Date(Math.floor(timestampUs / 1e3)) };
39
+ const decodedClockId = s32decode(tid.slice(11));
40
+ return { timestampUs, clockId: decodedClockId, date: new Date(Math.floor(timestampUs / 1e3)) };
41
+ }
42
+ function decodeTidTimestamp(tid) {
43
+ return decodeTid(tid).timestampUs;
44
+ }
45
+ function decodeTidClockId(tid) {
46
+ return decodeTid(tid).clockId;
29
47
  }
30
48
  var lastUs = 0;
31
- var CLOCK_ID = (() => {
49
+ var clockId = (() => {
32
50
  const buf = new Uint8Array(1);
33
51
  (globalThis.crypto ?? globalThis.webcrypto).getRandomValues(buf);
34
52
  return buf[0] % 32;
35
53
  })();
54
+ var generatedCount = 0;
36
55
  function nextUs(targetUs) {
37
56
  const us = targetUs <= lastUs ? lastUs + 1 : targetUs;
38
57
  lastUs = us;
58
+ generatedCount++;
39
59
  return us;
40
60
  }
41
61
  function makeTid(us) {
42
- return s32encode(us).padStart(11, "2") + s32encode(CLOCK_ID).padStart(2, "2");
62
+ return s32encode(us).padStart(11, "2") + s32encode(clockId).padStart(2, "2");
43
63
  }
44
64
  function generateTID(source) {
45
65
  const ms = typeof source === "string" ? new Date(source).getTime() : source.getTime();
@@ -53,14 +73,36 @@ function compareTids(a, b) {
53
73
  if (a > b) return 1;
54
74
  return 0;
55
75
  }
76
+ function areMonotonic(tids) {
77
+ for (let i = 1; i < tids.length; i++) {
78
+ if (tids[i] <= tids[i - 1]) return false;
79
+ }
80
+ return true;
81
+ }
82
+ function getTidClockState() {
83
+ return { lastTimestampUs: lastUs, clockId, generatedCount };
84
+ }
56
85
  function resetTidClock() {
57
86
  lastUs = 0;
87
+ generatedCount = 0;
88
+ }
89
+ function seedTidClock(startUs = 0, newClockId = 0) {
90
+ lastUs = startUs;
91
+ clockId = newClockId % 32;
92
+ generatedCount = 0;
58
93
  }
59
94
  export {
95
+ InvalidTidError,
96
+ areMonotonic,
60
97
  compareTids,
61
98
  decodeTid,
99
+ decodeTidClockId,
100
+ decodeTidTimestamp,
101
+ ensureValidTid,
62
102
  generateNextTID,
63
103
  generateTID,
104
+ getTidClockState,
64
105
  resetTidClock,
106
+ seedTidClock,
65
107
  validateTid
66
108
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ewanc26/tid",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Zero-dependency AT Protocol TID generation for Node.js and browsers",
5
5
  "type": "module",
6
6
  "exports": {