@astarship/subsecond-id 0.0.0-stage → 0.5.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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 AStarship <https://astarship.net>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,240 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # SubsecondId
2
+
3
+ SubsecondId is a blazing fast 64-bit and 128-bit superset monotonically increasing UUID library with cryptographically-secure client-side number generator to optimize SQL-like primary key search, Postgres, hot-to-archive databases like [SubsecondDb Postgres Extension](https://github.com/AStarStarship/SubsecondDb), distributed systems, sharded SQL databases like PlanetScale, key-value stores like Redis, etc. SubsecondId is part of the [ASCII Data Specification](https://github.com/AStarStarship/Crabs). Please read [this ReadMe file on GitHub](https://github.com/AStarStarship/Crabs/blob/master/TS/) for the most up to date instructions.
4
+
5
+ ![example workflow](https://github.com/AStarStarship/SubsecondId/actions/workflows/test.yml/badge.svg)
6
+
7
+ This is the TypeScript/JavaScript/NPM version. These are other versions:
8
+
9
+ * [C++/Crabs](https://github.com/AStarStarship/Crabs)
10
+ * [Python](https://github.com/AStarStarship/Crabs/blob/master/Python/)
11
+
12
+ ## Bit Patterns
13
+
14
+ The authoritative bit layouts are in the [ASCII Crabs Clock spec](https://github.com/AStarStarship/Crabs). The
15
+ diagrams below match the implemented TypeScript.
16
+
17
+ ### 64-bit Hot Unique Id (the primary key you mint)
18
+
19
+ ```AsciiArt
20
+ v--MSb (always 1) LSb--v
21
+ +--------------------------------------------------------------------------+
22
+ | 1-bit MSb | 27-bit unsigned seconds | 8-bit subsecond ticker | 28-bit source id |
23
+ +--------------------------------------------------------------------------+
24
+ ```
25
+
26
+ The 27-bit `seconds` field counts seconds elapsed from the start of the current
27
+ **4-year calendar window** (year floored to a multiple of 4), so it resets to 0 at
28
+ the top of each window (2024, 2028, 2032, ...) and stays sortable. The 28-bit
29
+ `source id` is the issuing server's stable identity (provenance / anti-fraud).
30
+ The 8-bit `ticker` (0..255) provides intra-second uniqueness and caps the mint
31
+ rate per server.
32
+
33
+ ### 64-bit Cold Unique Id (archive form)
34
+
35
+ ```AsciiArt
36
+ v--MSb (0) LSb--v
37
+ +----------------------------------------------------------+
38
+ | 36-bit unsigned seconds | 28-bit subsecond ticker | |
39
+ +----------------------------------------------------------+
40
+ ```
41
+
42
+ A Hot id is converted to Cold before its 4-year window rolls over (the normal
43
+ archive path). Cold ids sort purely by time and carry no source id (provenance
44
+ lives in the record metadata).
45
+
46
+ ### 64-bit Eternally Hot Anonymous Unique Id
47
+
48
+ ```AsciiArt
49
+ v--MSb (1, bits 35:34 = 0b11) LSb--v
50
+ +------------------------------------------------------------+
51
+ | 1-bit MSb | 27-bit unsigned seconds | 34-bit anonymous id |
52
+ +------------------------------------------------------------+
53
+ ```
54
+
55
+ ### 128-bit Universally Unique Id
56
+
57
+ ```AsciiArt
58
+ v--MSb LSb--v
59
+ +--------------------------------------------------------------------------+
60
+ | 36-bit unsigned seconds | 16-bit subsecond ticker | 76-bit random source |
61
+ +--------------------------------------------------------------------------+
62
+ ```
63
+
64
+ ## Common Design
65
+
66
+ There is no one format that is going to be perfect for everyone, so it's more important that it work for the most number of people possible without much waste, and be good enough that you may never need to upgrade your database. Generating random numbers at run-time is EXTREMELY expensive and will bring your server to it's knees. It's best if the system requesting a UUID was trustworthy, but it's a zero-trust environment world, so we need a clever way to protect against UUID hacking.
67
+
68
+ Ideally, we want conversion between hex TUID and UUID strings and timestamp, subsecond tick, and random source id must be as fast as possible, requiring the bit counts to be multiples of 4.
69
+
70
+ 32-bit Unix seconds timestamps are the industry norm for disk storage and inode based SQL databases that use 64-bit primary keys. There isn't much use for humans to know time beyond the second level for database purpose so it's better to use subsecond ticker over a milliseconds timestamp which requires an expensive division instruction to convert back to 32-bit seconds timestamp 1/256 is 3.90625ms so it's good enough precision. Almost all data on the internet gets cold quickly and don't need multiple decade timestamps. The Subsecond ticker allows us to cap the number of SubsecondIds a thread can generate because database calls are expensive, and this helps prevent DoS attacks. If a thread has to generate more UUIDs per second there are multiple strategies to get more such a source id server or blockchain or generating another random number and possibly waiting for a resolved UID collision.
71
+
72
+ On the client's side you aren't going to save any noticeable amount of power when you generate a random number each time you generate a UUID. The problem is that we don't want the web server or database to have to generate these expensive random numbers, and you can't trust the client either.
73
+
74
+ ## 64-bit design
75
+
76
+ To [optimize for SQL and other database searches](https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-index-design-guide).
77
+
78
+ By using 27.5 bits we only lose a very small amount of the epoch seconds but because the timestamp is in the MSb, we can use the length of the string to determine if the id is packed contiguous IDs. 27.875 bits is `2^27 + 2^26`, which is 234,881,024, which has a 7.44 year timestamp epoch, and literally no one will have a webpage open that long, so it's okay if the primary key changes after half an epoch, not a single person would complain about that.
79
+
80
+ To generate random numbers you use double-precision floating-point math, so you will always result with a 52-bit mantissa, and 28-bit bits is half of that and provides 268M random numbers, so if an database operation must be redone with a new random id once a day it's not an issue, but we can also assign 28-bit UUIDs with a server. The 8-bit (64 value) sub-second ticker limits the number of database writes from each server.
81
+
82
+ ### Design
83
+
84
+ When you query SQL rows you search by primary id. When you search through a key-value store like Redis the system will hash a string, search, and compare. When you shard an SQL database, you will use a 64-bit SQL database specific row index, and a 64-bit shard id. The vast majority of the time servers will not be generating large numbers of UUIDs per second. All web sites start off with one server that gets scaled vertically or horizontally to server more users, and as this server grows, the number of UUIDs generated per second will be very small, then grow.
85
+
86
+ ## 128-bit SubsecondIds
87
+
88
+ ## 128-bit Design
89
+
90
+ 128-bit UUIDs are useful for distributed systems where we can't bother checking if the random number source id is unique, which is important when you have millions of threads, so we use a 78-bit random number because it's enough that the chance of a collision is exponentially less than the chance of a network error. SQL and other inode-based databases use a 64-bit primary key integer with a 32-bit Unix timestamp. Databases just can't take thousands of operations per second from thousands of threads.
91
+
92
+ When your website grows to a large number of users, you need to shard the database and use multiple SQL servers. When that the database is copied the autoincrement primary key isn't valid anymore. PlanetScale automatically shards the database to scale to more users, so this is why there are no foreign keys with PlanetScale. While you might be tempted to use UUID, it does not generate values that always increase (i.e. monotonically increasing), which is not good for doing binary searches with. Binary searches require monotonically increasing search indexes, and the SQL database engine uses the inode structure in your data drives to search for SQL table rows.
93
+
94
+ Another solution is to use [Universally Unique Lexicographically Sortable Identifier (USubsecondId)](https://github.com/ulid/spec), but it uses a 48-bit millisecond timestamp MSB and 80-byte random number in the LSB. There are two problems with this design approach. First is that the x86 CPU doesn't have a sub-second timestamp, so databases do not use them. This means that to translate the milliseconds to seconds when you want to work with the database and you will have to divide and multiple by 1000, which is slow and error prone. To get a sub-second timestamp on an x86 server will require a dedicated thread to do a spin clock with an inter-process pipe, which is complex and unnecessary. We want an approach that doesn't have to generate any random numbers at runtime and we work in seconds and it will work for almost everything for thousands of years.
95
+
96
+ 128-bit SubsecondId (SubsecondId16) use a 33-bit Unix second timestamp in the Most-Significant Bits (MSB) followed by a 22-bit sub-second spin ticker and 73-bit Cryptographically-Secure Generated-Upon-Boot Random Number (CSGUBRN):
97
+
98
+ Statistically this means that when you have two web servers active, the probability that both servers generate the same random number is 7.12e-41%. If you had 1,000 servers running then the probability would be 1.06e-22%, which is a 1 in 9,444,732,965,739,290,427,392 chance. If you had 1,000,000 servers running, the probability would be 1.06e-16%, which is a 1 in 9,444,732,965,739,290 chance and is a 53-bit number. If there ever is actually is more than one server with the same source id, this means that the server will have to regenerate a 73-bit random source id upon boot, which will result in the first database write from that server to have to be performed one. This makes this bit pattern statistically acceptable to use for military and banking applications.
99
+
100
+ The 22-bit sub-second spin ticker caps out the number of calls you can make to per second to 2^22, which is 4,194,304. If you make more calls than this per second than the algorithm will spin wait until the next second and then reset the sub-second ticker. Assuming the upper limit of a normal computer, which is no more than 4,294,967,296Hz (4.3GHz) and just so happens to be 2^32 or 32-bits, making the math easy. This would give you about 1024 instructions between when you can call SubsecondId. Given not all CPU instructions are single-cycle, you're usually waiting for memory, and you're going to be creating a data structure, it's highly unlikely you'll ever hit this cap and if you ever did you'll probably have no problem with the delay. This is an edge case.
101
+
102
+ The 36-bit timestamp has an epoch span of 2,177.6 years. By that time everything we know including your software and hardware will be long gone and forgotten. The above characteristics make the 22-bit spin ticker and 70-bit CSGUBRN a sweet spot that will work for almost every computer and last not be outdated for thousands of years.
103
+
104
+ The benefit of SubsecondId is that you don't need a naming server. You can use a 32-bit timestamp, a 22-bit sub-second ticker, and 10-bit server id if you use a naming server and that will give you an optimized 64-bit index, but each thread that uses SubsecondId will have to have it's own source, so you can quickly run out of source ids.
105
+
106
+ To [optimize for SQL and other database searches](https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-index-design-guide), we need to take advantage of the 64-bit index in the inode data structure used by all in-disk database engines. Indexing can be very complicated and you can index your database tables different ways at runtime to optimize your lookups. You don't just want to XOR the SubsecondId LSW and MSW together because you'll get clustering, the result will be non-monotonic, and as the database grows you will get collisions. For this reason it's better to create new database rows using 128-indexes that you then index contiguously.
107
+
108
+ For users of your websites using SubsecondId, they will get HTML where the items with SubsecondIds will show up with an HTML property uid that will be a string. When this string is 32-characters long (in hex so that is 16-bytes) that means it's a 128-bit SubsecondId that has not been compacted to a 64-bit UID. In the OS filesystem, inodes have timestamps, so when you see these 32-character UIDs you will need to extract the seconds from the timestamp and search for the database row by timestamp and UID.
109
+
110
+ ## Quickstart
111
+
112
+ The package is **dual CJS/ESM** — it loads under both `require()` (CommonJS,
113
+ including Jest) and `import` (ESM, including Next.js and browsers). No
114
+ `"type": "module"` gymnastics required on your side.
115
+
116
+ **1.** Install:
117
+
118
+ ```BASH
119
+ npm install @astarship/subsecond-id
120
+ ```
121
+
122
+ **2.** Import (ESM):
123
+
124
+ ```TypeScript
125
+ import {
126
+ SsIdSetSource, SsIdNext, SsIdNextHex,
127
+ SsIdUnpack, SsIdTimestamp, SsIdTicker, SsIdSource, SsIdMsb,
128
+ SsIdWindowStart, SsIdWindowCount,
129
+ } from '@astarship/subsecond-id'
130
+ ```
131
+
132
+ **2b.** Import (CommonJS):
133
+
134
+ ```JavaScript
135
+ const {
136
+ SsIdSetSource, SsIdNext, SsIdNextHex,
137
+ SsIdUnpack, SsIdTimestamp, SsIdTicker, SsIdSource, SsIdMsb,
138
+ SsIdWindowStart, SsIdWindowCount,
139
+ } = require('@astarship/subsecond-id')
140
+ ```
141
+
142
+ **3.** Configure your server's identity (call once at startup).
143
+
144
+ The 28-bit **source id** is a stable per-server identity that is embedded in
145
+ every id you mint — it is your anti-fraud provenance (from the id alone you can
146
+ tell which server produced a record). Derive it from a secret so the same server
147
+ always mints with the same identity, and an attacker without the secret cannot
148
+ forge that server's ids:
149
+
150
+ ```TypeScript
151
+ import { createHash } from 'node:crypto'
152
+
153
+ // 28-bit stable server identity from a secret (env / config / file).
154
+ function serverIdFromSecret(secret: string): number {
155
+ return createHash('sha256').update(secret).digest().readUInt32BE(0) >>> 4
156
+ }
157
+
158
+ SsIdSetSource(serverIdFromSecret(process.env.SUBSECOND_SERVER_ID!))
159
+ ```
160
+
161
+ **4.** Add to your Drizzle schema (Postgres example). The 64-bit value is the
162
+ `bigint` primary key — the fastest SQL lookup — and doubles as a
163
+ self-authenticating timestamp.
164
+
165
+ ```TypeScript
166
+ import { bigint, pgTable } from 'drizzle-orm/pg-core'
167
+
168
+ export const CourtCases = pgTable('court_cases', {
169
+ uidx: bigint('uidx').primaryKey(), // the 64-bit SubsecondId
170
+ })
171
+ ```
172
+
173
+ **5.** Mint and store (TypeScript, Postgres):
174
+
175
+ ```TypeScript
176
+ // Mint the next id. No RNG argument needed — the source identity is
177
+ // configured via SsIdSetSource() and the timestamp/ticker are derived from the
178
+ // system clock, so there is no expensive random-number generation per call.
179
+ const uidx = SsIdNext() // bigint
180
+ const uidxHex = uidx.toString(16).padStart(16, '0') // 16-char hex (or SsIdNextHex())
181
+
182
+ // Inspect the embedded fields (provenance + time):
183
+ const [windowSeconds, ticker, source] = SsIdUnpack(uidx)
184
+ const absoluteSeconds = windowSeconds + SsIdWindowStart() // ~filing time
185
+
186
+ await db.insert(CourtCases).values({ uidx })
187
+
188
+ // Look up by primary key (the whole point of a 64-bit index):
189
+ const row = await db.select().from(CourtCases).where(eq(CourtCases.uidx, uidx))
190
+ ```
191
+
192
+ ### The 4-year window
193
+
194
+ The 27-bit `seconds` field is **not** absolute Unix time. It counts seconds
195
+ elapsed from the start of the current **4-year calendar window** (year floored
196
+ to a multiple of 4: 2024, 2028, 2032, ...), and resets to 0 at the top of each
197
+ window. That is what makes a 27-bit field sortable and time-ordered. Recover the
198
+ absolute filing time with `SsIdTimestamp(id) + SsIdWindowStart()`; use
199
+ `SsIdWindowCount()` to tell which 4-year window an id belongs to (needed only
200
+ when an id outlives its window, e.g. for archival).
201
+
202
+ ### 64-bit Local SubsecondId (no source)
203
+
204
+ For client-side UIDs / React refs that never touch a database, use the 64-bit
205
+ **Local** id — same monotonic design but no source id field, so no server
206
+ identity is needed:
207
+
208
+ ```TypeScript
209
+ import { SsLIdNextHex } from '@astarship/subsecond-id'
210
+
211
+ const ExampleItems = ['Foo', 'Bar']
212
+ export function ExampleList() {
213
+ return <ul>{ExampleItems.map((item) =>
214
+ <li key={SsLIdNextHex()}>{item}</li>
215
+ )}</ul>
216
+ }
217
+ ```
218
+
219
+ ### 128-bit Universally Unique Id
220
+
221
+ For distributed systems with many threads where checking source uniqueness is
222
+ too expensive, use the 128-bit `SsUId` (36-bit seconds + 16-bit ticker +
223
+ 76-bit random source). It mints without a naming server:
224
+
225
+ ```TypeScript
226
+ import { SsUIdNextHex, SsUIdSourceNext } from '@astarship/subsecond-id'
227
+
228
+ SsUIdSourceNext() // (re)roll this server's 76-bit source id
229
+ const uid128 = SsUIdNextHex() // 32-char hex string
230
+ ```
231
+
232
+ ## License
233
+
234
+ Copyright [AStarship](https://astarship.net); rights reserved under MIT License.
235
+
236
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
237
+
238
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
239
+
240
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,121 @@
1
+ declare let SsIdTicker_: number;
2
+ declare let SsIdLastId_: SsId;
3
+ declare let SsIdSource_: number;
4
+ declare function SsIdSetSource(source: number): void;
5
+ declare function SsIdGetSource(): number;
6
+ declare const SsIdSecondsPerYear: number;
7
+ declare const SsIdFourYearSeconds: number;
8
+ declare function SsIdWindowStart(now?: number): number;
9
+ declare function SsIdWindowCount(now?: number): number;
10
+ declare function SsIdNext(_rng?: RNG): SsId;
11
+ declare function SsIdResetTicker(): number;
12
+ declare function SsIdPack(timestamp: number, ticker: number, source: number): SsId;
13
+ declare function SsIdUnpack(id: SsId): [number, number, number];
14
+ declare function SsIdTimestamp(id: SsId): number;
15
+ declare function SsIdTicker(id: SsId): number;
16
+ declare function SsIdSource(id: SsId): number;
17
+ declare function SsIdMsb(id: SsId): number;
18
+ declare function SsIdNextHex(rng?: RNG): string;
19
+ declare function SsIdPrint(id: SsId): string;
20
+
21
+ declare function SsLIdTimestamp(id: SsLUId): number;
22
+ declare function SsLIdTicker(id: SsLUId): number;
23
+ declare function SsLIdUnpack(id: SsLUId): [number, number];
24
+ declare function SsLIdPack(timestamp: number, ticker: number): SsLUId;
25
+ declare function SsLIdPrint(id: SsLUId): string;
26
+ declare function SsLIdNext(): SsLUId;
27
+ declare function SsLIdNextHex(): string;
28
+
29
+ declare function SsUIdTimestamp(subsec_id: SsUUId): bigint;
30
+ declare function SsUIdTicker(subsec_id: SsUUId): bigint;
31
+ declare function SsUIdSource(subsec_id: SsUUId): bigint;
32
+ declare function SsUIdPack(timestamp: bigint | number, ticker: bigint | number, source: bigint): SsUUId;
33
+ declare function SsUIdUnpack(subsec_id: SsUUId): [bigint, bigint, bigint];
34
+ declare function SsUIdPrint(subsec_id: SsUUId): string;
35
+ declare function SsUIdSourceId(): bigint;
36
+ declare function SsUIdSourceNext(rng?: RNG): void;
37
+ declare function SsUIdSourceIncrement(): void;
38
+ declare function SsUIdNext(rng?: RNG): SsUUId;
39
+ declare function SsUIdNextHex(rng?: RNG, dest?: string): string;
40
+ declare function SsUIdNextBuffer(rng?: RNG): Buffer;
41
+
42
+ type SsId = bigint;
43
+ type SsLUId = bigint;
44
+ type SsUUId = bigint;
45
+ type NumberIOFun = (a: number) => number;
46
+ type RNG = (min: number, max: number) => number;
47
+ declare let SsIdRng: RNG;
48
+ declare function SsIdSetRng(rng: RNG): void;
49
+ type Chance = {
50
+ u: number;
51
+ v: number;
52
+ };
53
+ declare const NumberMantissaBits = 53;
54
+ declare const SsIdSourceBits = 28;
55
+ declare const SsIdTickerBits = 8;
56
+ declare const SsIdHotTimestampBits = 27;
57
+ declare const SsIdHotMsb = 1;
58
+ declare const SsIdTickerSourceBits: number;
59
+ declare const SsIdHotTimestampMax: number;
60
+ declare const SsIdColdTimestampBits = 34;
61
+ declare const SsIdColdTickerBits = 29;
62
+ declare const SsIdColdMsb = 0;
63
+ declare const SsIdAnonymousTimestampBits = 27;
64
+ declare const SsIdAnonymousRandomBits = 31;
65
+ declare const SsIdAnonymousSecondsMin = 126230400;
66
+ declare const SsIdAnonymousSecondsMax = 130424704;
67
+ declare const SsIdTickerMax: number;
68
+ declare const SubsecondIdSourceMax: number;
69
+ declare const TmtTimestampBits = 32;
70
+ declare const TmtTickerBits = 32;
71
+ declare const TmtTickerMax: number;
72
+ declare const SsUIdSourceBits = 76;
73
+ declare const SsUIdTickerBits = 16;
74
+ declare const SsUIdTimestampBits = 36;
75
+ declare const SsUIdTickerMax: bigint;
76
+ declare function NumberToHex(value: number, dest?: string): string;
77
+ declare function PrintHexByte(input: number, dest?: string): string;
78
+ declare function ByteCountBits(value: number): 8 | 1 | 0 | 2 | 4 | 3 | 5 | 6 | 7;
79
+ declare function CountAssertedBits(value: number): number;
80
+ declare function CountLeadingOnes(value: number): number;
81
+ declare function CountLeadingZeros(value: number): number;
82
+ declare function NumberCountBytes(value: number): number;
83
+ declare function NumberCountBits(value: number): number;
84
+ declare function NumberPrint(value: number, char_count: number, pad?: string): string;
85
+ declare function BigIntPrint(value: number | bigint, char_count: number, pad?: string): string;
86
+ declare function BinaryCount(value: bigint | number): number;
87
+ declare function BigIntCountBytes(value: bigint): number;
88
+ declare function BigIntCountBits(value: bigint): number;
89
+ declare function NumberCountDecimals(value: number): number;
90
+ declare function NumberPad(value: number, digit_count: number, pad?: string): string;
91
+ declare function CountDecimals(value: bigint | number | string): number;
92
+ declare function BigIntCountDecimals(value: bigint): number;
93
+ declare function BigIntToBuffer(value: bigint): Buffer;
94
+ declare function NumberToBuffer(value: number): Buffer;
95
+ declare function BigIntPad(value: bigint, decimals_max: number, pad?: string): string;
96
+ declare function BinaryPad(value: string | number | bigint | undefined, bit_count?: number, prefix?: string, pad?: string): string;
97
+ declare function BinaryPadBits(value: string | number | bigint | undefined, bit_count?: number, prefix?: string): string;
98
+ declare function BufferToBigInt(buf: Buffer): bigint;
99
+ declare function BufferToHex(buf: Buffer): string;
100
+ declare function HexPad(value: string | number | bigint | undefined, bit_count?: number, prefix?: string, pad?: string): string;
101
+ declare function HexPadBits(value: string | number | bigint | undefined, bit_count?: number, prefix?: string): string;
102
+ declare function HexToNibble(input: string | undefined): number;
103
+ declare function HexToBigInt(hex: string): bigint;
104
+ declare function HexToNumber(hex: string): number;
105
+ declare function HexToBuffer(hex: string): Buffer;
106
+ declare function BigIntInRange(rng: RNG, min?: bigint | number, max?: bigint | number): bigint;
107
+ declare function NumberInRange(rng: RNG, min?: number, max?: number): number;
108
+ declare function BigIntInBitRange(rng: RNG, bit_min?: bigint | number, bit_max?: bigint | number): bigint;
109
+ declare function NumberInBitRange(rng: RNG, bit_min: number, bit_max: number): number;
110
+ declare function BitRangeMinMax(bit_min?: bigint | number, bit_max?: bigint | number): [number, number];
111
+ declare function BigIntIsInBitRange(value: bigint | number, bit_min?: bigint | number, bit_max?: bigint | number): boolean;
112
+ declare function BigIntRandom(rng: RNG, bit_count?: bigint | number): bigint;
113
+ declare function NumberRandom(rng: RNG): number;
114
+ declare function NumberNZ(rng: RNG, min?: number, max?: number): number;
115
+ declare function NumberNZFromNeg1To1(rng: RNG): number;
116
+ declare function TimestampSeconds(): number;
117
+ declare function TimestampSecondsNext(): number;
118
+ declare function TimestampSecondsNextBigInt(): bigint;
119
+ declare function TimestampSecondsAsBigInt(): bigint;
120
+
121
+ export { BigIntCountBits, BigIntCountBytes, BigIntCountDecimals, BigIntInBitRange, BigIntInRange, BigIntIsInBitRange, BigIntPad, BigIntPrint, BigIntRandom, BigIntToBuffer, BinaryCount, BinaryPad, BinaryPadBits, BitRangeMinMax, BufferToBigInt, BufferToHex, ByteCountBits, type Chance, CountAssertedBits, CountDecimals, CountLeadingOnes, CountLeadingZeros, HexPad, HexPadBits, HexToBigInt, HexToBuffer, HexToNibble, HexToNumber, NumberCountBits, NumberCountBytes, NumberCountDecimals, type NumberIOFun, NumberInBitRange, NumberInRange, NumberMantissaBits, NumberNZ, NumberNZFromNeg1To1, NumberPad, NumberPrint, NumberRandom, NumberToBuffer, NumberToHex, PrintHexByte, type RNG, type SsId, SsIdAnonymousRandomBits, SsIdAnonymousSecondsMax, SsIdAnonymousSecondsMin, SsIdAnonymousTimestampBits, SsIdColdMsb, SsIdColdTickerBits, SsIdColdTimestampBits, SsIdFourYearSeconds, SsIdGetSource, SsIdHotMsb, SsIdHotTimestampBits, SsIdHotTimestampMax, SsIdLastId_, SsIdMsb, SsIdNext, SsIdNextHex, SsIdPack, SsIdPrint, SsIdResetTicker, SsIdRng, SsIdSecondsPerYear, SsIdSetRng, SsIdSetSource, SsIdSource, SsIdSourceBits, SsIdSource_, SsIdTicker, SsIdTickerBits, SsIdTickerMax, SsIdTickerSourceBits, SsIdTicker_, SsIdTimestamp, SsIdUnpack, SsIdWindowCount, SsIdWindowStart, SsLIdNext, SsLIdNextHex, SsLIdPack, SsLIdPrint, SsLIdTicker, SsLIdTimestamp, SsLIdUnpack, type SsLUId, SsUIdNext, SsUIdNextBuffer, SsUIdNextHex, SsUIdPack, SsUIdPrint, SsUIdSource, SsUIdSourceBits, SsUIdSourceId, SsUIdSourceIncrement, SsUIdSourceNext, SsUIdTicker, SsUIdTickerBits, SsUIdTickerMax, SsUIdTimestamp, SsUIdTimestampBits, SsUIdUnpack, type SsUUId, SubsecondIdSourceMax, TimestampSeconds, TimestampSecondsAsBigInt, TimestampSecondsNext, TimestampSecondsNextBigInt, TmtTickerBits, TmtTickerMax, TmtTimestampBits };
@@ -0,0 +1,121 @@
1
+ declare let SsIdTicker_: number;
2
+ declare let SsIdLastId_: SsId;
3
+ declare let SsIdSource_: number;
4
+ declare function SsIdSetSource(source: number): void;
5
+ declare function SsIdGetSource(): number;
6
+ declare const SsIdSecondsPerYear: number;
7
+ declare const SsIdFourYearSeconds: number;
8
+ declare function SsIdWindowStart(now?: number): number;
9
+ declare function SsIdWindowCount(now?: number): number;
10
+ declare function SsIdNext(_rng?: RNG): SsId;
11
+ declare function SsIdResetTicker(): number;
12
+ declare function SsIdPack(timestamp: number, ticker: number, source: number): SsId;
13
+ declare function SsIdUnpack(id: SsId): [number, number, number];
14
+ declare function SsIdTimestamp(id: SsId): number;
15
+ declare function SsIdTicker(id: SsId): number;
16
+ declare function SsIdSource(id: SsId): number;
17
+ declare function SsIdMsb(id: SsId): number;
18
+ declare function SsIdNextHex(rng?: RNG): string;
19
+ declare function SsIdPrint(id: SsId): string;
20
+
21
+ declare function SsLIdTimestamp(id: SsLUId): number;
22
+ declare function SsLIdTicker(id: SsLUId): number;
23
+ declare function SsLIdUnpack(id: SsLUId): [number, number];
24
+ declare function SsLIdPack(timestamp: number, ticker: number): SsLUId;
25
+ declare function SsLIdPrint(id: SsLUId): string;
26
+ declare function SsLIdNext(): SsLUId;
27
+ declare function SsLIdNextHex(): string;
28
+
29
+ declare function SsUIdTimestamp(subsec_id: SsUUId): bigint;
30
+ declare function SsUIdTicker(subsec_id: SsUUId): bigint;
31
+ declare function SsUIdSource(subsec_id: SsUUId): bigint;
32
+ declare function SsUIdPack(timestamp: bigint | number, ticker: bigint | number, source: bigint): SsUUId;
33
+ declare function SsUIdUnpack(subsec_id: SsUUId): [bigint, bigint, bigint];
34
+ declare function SsUIdPrint(subsec_id: SsUUId): string;
35
+ declare function SsUIdSourceId(): bigint;
36
+ declare function SsUIdSourceNext(rng?: RNG): void;
37
+ declare function SsUIdSourceIncrement(): void;
38
+ declare function SsUIdNext(rng?: RNG): SsUUId;
39
+ declare function SsUIdNextHex(rng?: RNG, dest?: string): string;
40
+ declare function SsUIdNextBuffer(rng?: RNG): Buffer;
41
+
42
+ type SsId = bigint;
43
+ type SsLUId = bigint;
44
+ type SsUUId = bigint;
45
+ type NumberIOFun = (a: number) => number;
46
+ type RNG = (min: number, max: number) => number;
47
+ declare let SsIdRng: RNG;
48
+ declare function SsIdSetRng(rng: RNG): void;
49
+ type Chance = {
50
+ u: number;
51
+ v: number;
52
+ };
53
+ declare const NumberMantissaBits = 53;
54
+ declare const SsIdSourceBits = 28;
55
+ declare const SsIdTickerBits = 8;
56
+ declare const SsIdHotTimestampBits = 27;
57
+ declare const SsIdHotMsb = 1;
58
+ declare const SsIdTickerSourceBits: number;
59
+ declare const SsIdHotTimestampMax: number;
60
+ declare const SsIdColdTimestampBits = 34;
61
+ declare const SsIdColdTickerBits = 29;
62
+ declare const SsIdColdMsb = 0;
63
+ declare const SsIdAnonymousTimestampBits = 27;
64
+ declare const SsIdAnonymousRandomBits = 31;
65
+ declare const SsIdAnonymousSecondsMin = 126230400;
66
+ declare const SsIdAnonymousSecondsMax = 130424704;
67
+ declare const SsIdTickerMax: number;
68
+ declare const SubsecondIdSourceMax: number;
69
+ declare const TmtTimestampBits = 32;
70
+ declare const TmtTickerBits = 32;
71
+ declare const TmtTickerMax: number;
72
+ declare const SsUIdSourceBits = 76;
73
+ declare const SsUIdTickerBits = 16;
74
+ declare const SsUIdTimestampBits = 36;
75
+ declare const SsUIdTickerMax: bigint;
76
+ declare function NumberToHex(value: number, dest?: string): string;
77
+ declare function PrintHexByte(input: number, dest?: string): string;
78
+ declare function ByteCountBits(value: number): 8 | 1 | 0 | 2 | 4 | 3 | 5 | 6 | 7;
79
+ declare function CountAssertedBits(value: number): number;
80
+ declare function CountLeadingOnes(value: number): number;
81
+ declare function CountLeadingZeros(value: number): number;
82
+ declare function NumberCountBytes(value: number): number;
83
+ declare function NumberCountBits(value: number): number;
84
+ declare function NumberPrint(value: number, char_count: number, pad?: string): string;
85
+ declare function BigIntPrint(value: number | bigint, char_count: number, pad?: string): string;
86
+ declare function BinaryCount(value: bigint | number): number;
87
+ declare function BigIntCountBytes(value: bigint): number;
88
+ declare function BigIntCountBits(value: bigint): number;
89
+ declare function NumberCountDecimals(value: number): number;
90
+ declare function NumberPad(value: number, digit_count: number, pad?: string): string;
91
+ declare function CountDecimals(value: bigint | number | string): number;
92
+ declare function BigIntCountDecimals(value: bigint): number;
93
+ declare function BigIntToBuffer(value: bigint): Buffer;
94
+ declare function NumberToBuffer(value: number): Buffer;
95
+ declare function BigIntPad(value: bigint, decimals_max: number, pad?: string): string;
96
+ declare function BinaryPad(value: string | number | bigint | undefined, bit_count?: number, prefix?: string, pad?: string): string;
97
+ declare function BinaryPadBits(value: string | number | bigint | undefined, bit_count?: number, prefix?: string): string;
98
+ declare function BufferToBigInt(buf: Buffer): bigint;
99
+ declare function BufferToHex(buf: Buffer): string;
100
+ declare function HexPad(value: string | number | bigint | undefined, bit_count?: number, prefix?: string, pad?: string): string;
101
+ declare function HexPadBits(value: string | number | bigint | undefined, bit_count?: number, prefix?: string): string;
102
+ declare function HexToNibble(input: string | undefined): number;
103
+ declare function HexToBigInt(hex: string): bigint;
104
+ declare function HexToNumber(hex: string): number;
105
+ declare function HexToBuffer(hex: string): Buffer;
106
+ declare function BigIntInRange(rng: RNG, min?: bigint | number, max?: bigint | number): bigint;
107
+ declare function NumberInRange(rng: RNG, min?: number, max?: number): number;
108
+ declare function BigIntInBitRange(rng: RNG, bit_min?: bigint | number, bit_max?: bigint | number): bigint;
109
+ declare function NumberInBitRange(rng: RNG, bit_min: number, bit_max: number): number;
110
+ declare function BitRangeMinMax(bit_min?: bigint | number, bit_max?: bigint | number): [number, number];
111
+ declare function BigIntIsInBitRange(value: bigint | number, bit_min?: bigint | number, bit_max?: bigint | number): boolean;
112
+ declare function BigIntRandom(rng: RNG, bit_count?: bigint | number): bigint;
113
+ declare function NumberRandom(rng: RNG): number;
114
+ declare function NumberNZ(rng: RNG, min?: number, max?: number): number;
115
+ declare function NumberNZFromNeg1To1(rng: RNG): number;
116
+ declare function TimestampSeconds(): number;
117
+ declare function TimestampSecondsNext(): number;
118
+ declare function TimestampSecondsNextBigInt(): bigint;
119
+ declare function TimestampSecondsAsBigInt(): bigint;
120
+
121
+ export { BigIntCountBits, BigIntCountBytes, BigIntCountDecimals, BigIntInBitRange, BigIntInRange, BigIntIsInBitRange, BigIntPad, BigIntPrint, BigIntRandom, BigIntToBuffer, BinaryCount, BinaryPad, BinaryPadBits, BitRangeMinMax, BufferToBigInt, BufferToHex, ByteCountBits, type Chance, CountAssertedBits, CountDecimals, CountLeadingOnes, CountLeadingZeros, HexPad, HexPadBits, HexToBigInt, HexToBuffer, HexToNibble, HexToNumber, NumberCountBits, NumberCountBytes, NumberCountDecimals, type NumberIOFun, NumberInBitRange, NumberInRange, NumberMantissaBits, NumberNZ, NumberNZFromNeg1To1, NumberPad, NumberPrint, NumberRandom, NumberToBuffer, NumberToHex, PrintHexByte, type RNG, type SsId, SsIdAnonymousRandomBits, SsIdAnonymousSecondsMax, SsIdAnonymousSecondsMin, SsIdAnonymousTimestampBits, SsIdColdMsb, SsIdColdTickerBits, SsIdColdTimestampBits, SsIdFourYearSeconds, SsIdGetSource, SsIdHotMsb, SsIdHotTimestampBits, SsIdHotTimestampMax, SsIdLastId_, SsIdMsb, SsIdNext, SsIdNextHex, SsIdPack, SsIdPrint, SsIdResetTicker, SsIdRng, SsIdSecondsPerYear, SsIdSetRng, SsIdSetSource, SsIdSource, SsIdSourceBits, SsIdSource_, SsIdTicker, SsIdTickerBits, SsIdTickerMax, SsIdTickerSourceBits, SsIdTicker_, SsIdTimestamp, SsIdUnpack, SsIdWindowCount, SsIdWindowStart, SsLIdNext, SsLIdNextHex, SsLIdPack, SsLIdPrint, SsLIdTicker, SsLIdTimestamp, SsLIdUnpack, type SsLUId, SsUIdNext, SsUIdNextBuffer, SsUIdNextHex, SsUIdPack, SsUIdPrint, SsUIdSource, SsUIdSourceBits, SsUIdSourceId, SsUIdSourceIncrement, SsUIdSourceNext, SsUIdTicker, SsUIdTickerBits, SsUIdTickerMax, SsUIdTimestamp, SsUIdTimestampBits, SsUIdUnpack, type SsUUId, SubsecondIdSourceMax, TimestampSeconds, TimestampSecondsAsBigInt, TimestampSecondsNext, TimestampSecondsNextBigInt, TmtTickerBits, TmtTickerMax, TmtTimestampBits };