@astarship/subsecond-id 0.0.0-stage → 0.5.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.
- package/LICENSE +24 -0
- package/README.md +240 -3
- package/dist/index.d.mts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +892 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +759 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +79 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
PostgreSQL License
|
|
2
|
+
|
|
3
|
+
Portions Copyright (c) 1996-2024, The PostgreSQL Global Development Group
|
|
4
|
+
|
|
5
|
+
Portions Copyright (c) 2024-2026, AStarship <https://astarship.net>
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in
|
|
15
|
+
all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, INCLUDING ANY CLAIM FOR INCIDENTAL, SPECIAL, DIRECT, INDIRECT,
|
|
22
|
+
OR CONSEQUENTIAL DAMAGES, OR ANY OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
23
|
+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
24
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,240 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
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
|
+

|
|
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.
|
package/dist/index.d.mts
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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 };
|