@chainfuse/helpers 4.0.6 → 4.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/README.md +25 -9
- package/dist/buffers.d.mts +0 -3
- package/dist/buffers.mjs +10 -84
- package/dist/suru.d.mts +88 -0
- package/dist/suru.mjs +390 -0
- package/package.json +6 -10
- package/dist/uuid8.d.mts +0 -37
- package/dist/uuid8.mjs +0 -78
package/README.md
CHANGED
|
@@ -16,12 +16,28 @@ import helpers from '@chainfuse/helpers';
|
|
|
16
16
|
// TODO: DEMONSTRATE API
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
19
|
+
## SuruID
|
|
20
|
+
|
|
21
|
+
In Japanese, する (suru) is a versatile, irregular verb meaning "to do"
|
|
22
|
+
|
|
23
|
+
| Format | Example |
|
|
24
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
25
|
+
| hex | `11f3fffffc18001000004522706e3aa036a0ea9c0d7d27581ebf4876defd304469119f0f4cfc41b0fb96d6b1e18900ec` |
|
|
26
|
+
| SQLite Blob | `1724325525525224016006934112110581605416023415613125398830191721182222534868105171591576252651762511502141772251370236` |
|
|
27
|
+
| JS Buffer Array | `[17,243,255,255,252,24,0,16,0,0,69,34,112,110,58,160,54,160,234,156,13,125,39,88,30,191,72,118,222,253,48,68,105,17,159,15,76,252,65,176,251,150,214,177,225,137,0,236]` |
|
|
28
|
+
| base64 | `EfP///wYABAAAEUicG46oDag6pwNfSdYHr9Idt79MERpEZ8PTPxBsPuW1rHhiQDs` |
|
|
29
|
+
| base64url | `EfP___wYABAAAEUicG46oDag6pwNfSdYHr9Idt79MERpEZ8PTPxBsPuW1rHhiQDs` |
|
|
30
|
+
|
|
31
|
+
### Breakdown
|
|
32
|
+
|
|
33
|
+
| Offset (bits) | Size (bits) | Field | (Hex) Example | Notes |
|
|
34
|
+
| ------------- | ----------- | ------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
|
|
35
|
+
| 0 | 4 | Version | `1` | Masked into timestamp's top nibble |
|
|
36
|
+
| 4 | 44 | Timestamp | ~~`0`~~`1f3fffffc18` | Lower 44 bits of 48bit epoch milliseconds (max date value `2527-06-23T06:20:44.415Z`) |
|
|
37
|
+
| 48 | 12 | System Type | `001` | `D0SystemType` TS Enum |
|
|
38
|
+
| 60 | 12 | Location | `000` | `D0CombinedLocations` TS Enum |
|
|
39
|
+
| 72 | 8 | Shard Type | `00` | `D0ShardType` TS Enum |
|
|
40
|
+
| 80 | 44 | Suffix random | `4522706e3aa` | Fresh entropy per ID to ensure uniqueness even if other fields match |
|
|
41
|
+
| 124 | 4 | Environment | `0` | `D0Environment` TS Enum |
|
|
42
|
+
| 128 | 256 | Stable random | `36a0ea9c0d7d27581ebf4876defd304469119f0f4cfc41b0fb96d6b1e18900ec` | Stable per logical entity; correlates related IDs without DB lookups |
|
|
43
|
+
| **Total** | **384** |
|
package/dist/buffers.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { UndefinedProperties } from '@chainfuse/types';
|
|
2
2
|
import { type PrefixedUuid, type UuidExport, type UUIDExtract } from '@chainfuse/types/d1';
|
|
3
3
|
import * as z from 'zod/mini';
|
|
4
|
-
import type { Version8Options } from './uuid8.mjs';
|
|
5
4
|
export type UuidExportBlobInput = Buffer | UuidExport['blob'];
|
|
6
5
|
export declare class BufferHelpers {
|
|
7
6
|
static bigintToBuffer(number: bigint): Promise<ArrayBuffer>;
|
|
@@ -30,8 +29,6 @@ export declare class BufferHelpers {
|
|
|
30
29
|
}, z.core.$strip>;
|
|
31
30
|
static generateUuid7(_options?: z.input<Awaited<typeof this.v7OptionsBase>>): Promise<UuidExport>;
|
|
32
31
|
static generateUuid7Sync(_options?: z.input<Awaited<typeof this.v7OptionsBase>>): UuidExport;
|
|
33
|
-
static generateUuid8(options?: Omit<Version8Options, 'random' | 'rng'>): Promise<UuidExport>;
|
|
34
|
-
static generateUuid8Sync(options?: Omit<Version8Options, 'random' | 'rng'>): UuidExport;
|
|
35
32
|
static uuidConvert(input: undefined): Promise<UndefinedProperties<UuidExport>>;
|
|
36
33
|
static uuidConvert(prefixedUtf: PrefixedUuid): Promise<UuidExport>;
|
|
37
34
|
static uuidConvert(input: UuidExport['utf8']): Promise<UuidExport>;
|
package/dist/buffers.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { UUIDExtract7
|
|
1
|
+
import { UUIDExtract7 } from '@chainfuse/types/d1';
|
|
2
2
|
import { PrefixedUuidRaw } from '@chainfuse/types/zod-mini';
|
|
3
3
|
import { v7 as uuidv7 } from 'uuid';
|
|
4
4
|
import * as z from 'zod/mini';
|
|
5
5
|
import { BufferHelpersInternals } from "./bufferInternals.mjs";
|
|
6
6
|
import { CryptoHelpers } from './crypto.mjs';
|
|
7
|
-
import { v8 as uuidv8 } from './uuid8.mjs';
|
|
8
7
|
export class BufferHelpers {
|
|
9
8
|
static bigintToBuffer(number) {
|
|
10
9
|
const hexString = number.toString(16);
|
|
@@ -116,42 +115,6 @@ export class BufferHelpers {
|
|
|
116
115
|
base64url,
|
|
117
116
|
};
|
|
118
117
|
}
|
|
119
|
-
static generateUuid8(options) {
|
|
120
|
-
return Promise.all([import('./uuid8.mjs'), CryptoHelpers.secretBytes(16)]).then(([{ v8: uuidv8 }, random]) => {
|
|
121
|
-
const uuid = uuidv8({
|
|
122
|
-
// @ts-expect-error they're the exact same
|
|
123
|
-
random,
|
|
124
|
-
...options,
|
|
125
|
-
});
|
|
126
|
-
const uuidHex = uuid.replaceAll('-', '');
|
|
127
|
-
return this.hexToBuffer(uuidHex).then((blob) => Promise.all([this.bufferToBase64(blob, false), this.bufferToBase64(blob, true)]).then(([base64, base64url]) => ({
|
|
128
|
-
utf8: uuid,
|
|
129
|
-
hex: uuidHex,
|
|
130
|
-
blob,
|
|
131
|
-
base64,
|
|
132
|
-
base64url,
|
|
133
|
-
})));
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
static generateUuid8Sync(options) {
|
|
137
|
-
const random = CryptoHelpers.secretBytesSync(16);
|
|
138
|
-
const uuid = uuidv8({
|
|
139
|
-
// @ts-expect-error they're the exact same
|
|
140
|
-
random,
|
|
141
|
-
...options,
|
|
142
|
-
});
|
|
143
|
-
const uuidHex = uuid.replaceAll('-', '');
|
|
144
|
-
const blob = this.hexToBufferSync(uuidHex);
|
|
145
|
-
const base64 = this.bufferToBase64Sync(blob, false);
|
|
146
|
-
const base64url = this.bufferToBase64Sync(blob, true);
|
|
147
|
-
return {
|
|
148
|
-
utf8: uuid,
|
|
149
|
-
hex: uuidHex,
|
|
150
|
-
blob,
|
|
151
|
-
base64,
|
|
152
|
-
base64url,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
118
|
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
|
156
119
|
static uuidConvert(input) {
|
|
157
120
|
if (input) {
|
|
@@ -328,29 +291,11 @@ export class BufferHelpers {
|
|
|
328
291
|
.safeParseAsync(_hex)
|
|
329
292
|
.then(async ({ success: hexSuccess, data: hex }) => {
|
|
330
293
|
if (hexSuccess) {
|
|
331
|
-
const
|
|
332
|
-
if (utf8v7Success
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
return UUIDExtract8.parseAsync({
|
|
337
|
-
date: Number(BigInt(`0x${hex.substring(0, 12)}`)),
|
|
338
|
-
location: parseInt(hex.slice(17, 19), 16),
|
|
339
|
-
shardType: parseInt(hex.slice(19, 20), 16),
|
|
340
|
-
suffix: suffix_hex === '000'
|
|
341
|
-
? undefined
|
|
342
|
-
: {
|
|
343
|
-
hex: suffix_hex,
|
|
344
|
-
base64: await BufferHelpers.bufferToBase64(suffix_buffer, false),
|
|
345
|
-
base64url: await BufferHelpers.bufferToBase64(suffix_buffer, true),
|
|
346
|
-
},
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
return UUIDExtract7.parseAsync({
|
|
351
|
-
date: Number(BigInt(`0x${hex.substring(0, 12)}`)),
|
|
352
|
-
});
|
|
353
|
-
}
|
|
294
|
+
const { success: utf8v7Success } = await z.uuid({ version: 'v7' }).safeParseAsync(utf8);
|
|
295
|
+
if (utf8v7Success) {
|
|
296
|
+
return UUIDExtract7.parseAsync({
|
|
297
|
+
date: Number(BigInt(`0x${hex.substring(0, 12)}`)),
|
|
298
|
+
});
|
|
354
299
|
}
|
|
355
300
|
else {
|
|
356
301
|
throw new Error('Unsupported UUID version provided');
|
|
@@ -369,29 +314,10 @@ export class BufferHelpers {
|
|
|
369
314
|
const { success: hexSuccess, data: hex } = z.hex().check(z.length(32)).safeParse(_hex);
|
|
370
315
|
if (hexSuccess) {
|
|
371
316
|
const { success: utf8v7Success } = z.uuid({ version: 'v7' }).safeParse(utf8);
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
const suffix_buffer = BufferHelpers.hexToBufferSync(suffix_hex);
|
|
377
|
-
return UUIDExtract8.parse({
|
|
378
|
-
date: Number(BigInt(`0x${hex.substring(0, 12)}`)),
|
|
379
|
-
location: parseInt(hex.slice(17, 19), 16),
|
|
380
|
-
shardType: parseInt(hex.slice(19, 20), 16),
|
|
381
|
-
suffix: suffix_hex === '000'
|
|
382
|
-
? undefined
|
|
383
|
-
: {
|
|
384
|
-
hex: suffix_hex,
|
|
385
|
-
base64: BufferHelpers.bufferToBase64Sync(suffix_buffer, false),
|
|
386
|
-
base64url: BufferHelpers.bufferToBase64Sync(suffix_buffer, true),
|
|
387
|
-
},
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
else {
|
|
391
|
-
return UUIDExtract7.parse({
|
|
392
|
-
date: Number(BigInt(`0x${hex.substring(0, 12)}`)),
|
|
393
|
-
});
|
|
394
|
-
}
|
|
317
|
+
if (utf8v7Success) {
|
|
318
|
+
return UUIDExtract7.parse({
|
|
319
|
+
date: Number(BigInt(`0x${hex.substring(0, 12)}`)),
|
|
320
|
+
});
|
|
395
321
|
}
|
|
396
322
|
else {
|
|
397
323
|
throw new Error('Unsupported UUID version provided');
|
package/dist/suru.d.mts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { DOJurisdictions, DOLocations } from '@chainfuse/types';
|
|
2
|
+
import { D0Environment, D0ShardType, D0SystemType, D0Version } from '@chainfuse/types/d0';
|
|
3
|
+
import { type ZodPartial, type ZodSuruId } from '@chainfuse/types/zod-mini';
|
|
4
|
+
import * as z from 'zod/mini';
|
|
5
|
+
export declare class SuruId {
|
|
6
|
+
static extractOutputBase: z.ZodMiniObject<{
|
|
7
|
+
version: z.ZodMiniEnum<typeof D0Version>;
|
|
8
|
+
date: z.ZodMiniDate<Date>;
|
|
9
|
+
systemType: z.ZodMiniEnum<typeof D0SystemType>;
|
|
10
|
+
shardType: z.ZodMiniEnum<typeof D0ShardType>;
|
|
11
|
+
suffixRandom: z.ZodMiniObject<{
|
|
12
|
+
hex: z.ZodMiniCustomStringFormat<"hex">;
|
|
13
|
+
base64: z.ZodMiniBase64;
|
|
14
|
+
base64url: z.ZodMiniBase64URL;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
environment: z.ZodMiniEnum<typeof D0Environment>;
|
|
17
|
+
stableRandom: z.ZodMiniObject<{
|
|
18
|
+
hex: z.ZodMiniCustomStringFormat<"hex">;
|
|
19
|
+
base64: z.ZodMiniBase64;
|
|
20
|
+
base64url: z.ZodMiniBase64URL;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
static extractOutput: z.ZodMiniObject<{
|
|
24
|
+
version: z.ZodMiniEnum<typeof D0Version>;
|
|
25
|
+
date: z.ZodMiniDate<Date>;
|
|
26
|
+
systemType: z.ZodMiniEnum<typeof D0SystemType>;
|
|
27
|
+
shardType: z.ZodMiniEnum<typeof D0ShardType>;
|
|
28
|
+
suffixRandom: z.ZodMiniObject<{
|
|
29
|
+
hex: z.ZodMiniCustomStringFormat<"hex">;
|
|
30
|
+
base64: z.ZodMiniBase64;
|
|
31
|
+
base64url: z.ZodMiniBase64URL;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
environment: z.ZodMiniEnum<typeof D0Environment>;
|
|
34
|
+
stableRandom: z.ZodMiniObject<{
|
|
35
|
+
hex: z.ZodMiniCustomStringFormat<"hex">;
|
|
36
|
+
base64: z.ZodMiniBase64;
|
|
37
|
+
base64url: z.ZodMiniBase64URL;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
locationJurisdiction: z.ZodMiniNullable<z.ZodMiniEnum<typeof DOJurisdictions>>;
|
|
40
|
+
locationHint: z.ZodMiniNullable<z.ZodMiniEnum<typeof DOLocations>>;
|
|
41
|
+
}, z.core.$strip>;
|
|
42
|
+
static convertOutput: z.ZodMiniObject<{
|
|
43
|
+
hex: z.ZodMiniCustomStringFormat<"hex">;
|
|
44
|
+
blob: z.ZodMiniTuple<readonly [z.ZodMiniNumberFormat], z.ZodMiniNumberFormat>;
|
|
45
|
+
base64: z.ZodMiniBase64;
|
|
46
|
+
base64url: z.ZodMiniBase64URL;
|
|
47
|
+
}, z.core.$strip>;
|
|
48
|
+
static createInputBase: z.ZodMiniObject<{
|
|
49
|
+
version: z.ZodMiniDefault<z.ZodMiniEnum<typeof D0Version>>;
|
|
50
|
+
date: z.ZodMiniDefault<z.ZodMiniDate<Date>>;
|
|
51
|
+
shardType: z.ZodMiniDefault<z.ZodMiniEnum<typeof D0ShardType>>;
|
|
52
|
+
suffixRandom: z.ZodMiniDefault<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Buffer<ArrayBufferLike>>>, z.ZodMiniPipe<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBuffer>>>, z.ZodMiniPipe<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<ArrayBuffer, ArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, ArrayBuffer>>, z.ZodMiniPipe<z.ZodMiniCustom<SharedArrayBuffer, SharedArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, SharedArrayBuffer>>]>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, ArrayBufferLike>>, z.ZodMiniPipe<z.ZodMiniTuple<readonly [z.ZodMiniNumberFormat], z.ZodMiniNumberFormat>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, [number, ...number[]]>>]>>;
|
|
53
|
+
stableRandom: z.ZodMiniDefault<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Buffer<ArrayBufferLike>>>, z.ZodMiniPipe<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBuffer>>>, z.ZodMiniPipe<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<ArrayBuffer, ArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, ArrayBuffer>>, z.ZodMiniPipe<z.ZodMiniCustom<SharedArrayBuffer, SharedArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, SharedArrayBuffer>>]>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, ArrayBufferLike>>, z.ZodMiniPipe<z.ZodMiniTuple<readonly [z.ZodMiniNumberFormat], z.ZodMiniNumberFormat>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, [number, ...number[]]>>]>>;
|
|
54
|
+
systemType: z.ZodMiniEnum<typeof D0SystemType>;
|
|
55
|
+
environment: z.ZodMiniEnum<typeof D0Environment>;
|
|
56
|
+
}, z.core.$strip>;
|
|
57
|
+
static createInput: z.ZodMiniUnion<readonly [z.ZodMiniObject<{
|
|
58
|
+
version: z.ZodMiniDefault<z.ZodMiniEnum<typeof D0Version>>;
|
|
59
|
+
date: z.ZodMiniDefault<z.ZodMiniDate<Date>>;
|
|
60
|
+
shardType: z.ZodMiniDefault<z.ZodMiniEnum<typeof D0ShardType>>;
|
|
61
|
+
suffixRandom: z.ZodMiniDefault<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Buffer<ArrayBufferLike>>>, z.ZodMiniPipe<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBuffer>>>, z.ZodMiniPipe<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<ArrayBuffer, ArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, ArrayBuffer>>, z.ZodMiniPipe<z.ZodMiniCustom<SharedArrayBuffer, SharedArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, SharedArrayBuffer>>]>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, ArrayBufferLike>>, z.ZodMiniPipe<z.ZodMiniTuple<readonly [z.ZodMiniNumberFormat], z.ZodMiniNumberFormat>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, [number, ...number[]]>>]>>;
|
|
62
|
+
stableRandom: z.ZodMiniDefault<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Buffer<ArrayBufferLike>>>, z.ZodMiniPipe<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBuffer>>>, z.ZodMiniPipe<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<ArrayBuffer, ArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, ArrayBuffer>>, z.ZodMiniPipe<z.ZodMiniCustom<SharedArrayBuffer, SharedArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, SharedArrayBuffer>>]>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, ArrayBufferLike>>, z.ZodMiniPipe<z.ZodMiniTuple<readonly [z.ZodMiniNumberFormat], z.ZodMiniNumberFormat>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, [number, ...number[]]>>]>>;
|
|
63
|
+
systemType: z.ZodMiniEnum<typeof D0SystemType>;
|
|
64
|
+
environment: z.ZodMiniEnum<typeof D0Environment>;
|
|
65
|
+
locationJurisdiction: z.ZodMiniDefault<z.ZodMiniNullable<z.ZodMiniEnum<typeof DOJurisdictions>>>;
|
|
66
|
+
locationHint: z.ZodMiniDefault<z.ZodMiniNull>;
|
|
67
|
+
}, z.core.$strip>, z.ZodMiniObject<{
|
|
68
|
+
version: z.ZodMiniDefault<z.ZodMiniEnum<typeof D0Version>>;
|
|
69
|
+
date: z.ZodMiniDefault<z.ZodMiniDate<Date>>;
|
|
70
|
+
shardType: z.ZodMiniDefault<z.ZodMiniEnum<typeof D0ShardType>>;
|
|
71
|
+
suffixRandom: z.ZodMiniDefault<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Buffer<ArrayBufferLike>>>, z.ZodMiniPipe<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBuffer>>>, z.ZodMiniPipe<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<ArrayBuffer, ArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, ArrayBuffer>>, z.ZodMiniPipe<z.ZodMiniCustom<SharedArrayBuffer, SharedArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, SharedArrayBuffer>>]>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, ArrayBufferLike>>, z.ZodMiniPipe<z.ZodMiniTuple<readonly [z.ZodMiniNumberFormat], z.ZodMiniNumberFormat>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, [number, ...number[]]>>]>>;
|
|
72
|
+
stableRandom: z.ZodMiniDefault<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Buffer<ArrayBufferLike>>>, z.ZodMiniPipe<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBuffer>>>, z.ZodMiniPipe<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniCustom<ArrayBuffer, ArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, ArrayBuffer>>, z.ZodMiniPipe<z.ZodMiniCustom<SharedArrayBuffer, SharedArrayBuffer>, z.ZodMiniTransform<ArrayBufferLike, SharedArrayBuffer>>]>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, ArrayBufferLike>>, z.ZodMiniPipe<z.ZodMiniTuple<readonly [z.ZodMiniNumberFormat], z.ZodMiniNumberFormat>, z.ZodMiniTransform<Uint8Array<ArrayBufferLike>, [number, ...number[]]>>]>>;
|
|
73
|
+
systemType: z.ZodMiniEnum<typeof D0SystemType>;
|
|
74
|
+
environment: z.ZodMiniEnum<typeof D0Environment>;
|
|
75
|
+
locationJurisdiction: z.ZodMiniDefault<z.ZodMiniNull>;
|
|
76
|
+
locationHint: z.ZodMiniDefault<z.ZodMiniNullable<z.ZodMiniEnum<typeof DOLocations>>>;
|
|
77
|
+
}, z.core.$strip>]>;
|
|
78
|
+
static suruCreate(_input: z.input<typeof this.createInput>): Promise<z.output<typeof this.convertOutput>>;
|
|
79
|
+
static suruCreateSync(_input: z.input<typeof this.createInput>): z.output<typeof this.convertOutput>;
|
|
80
|
+
static suruConvert<O extends typeof this.convertOutput = typeof this.convertOutput>(_input: undefined): Promise<z.output<ZodPartial<O>>>;
|
|
81
|
+
static suruConvert<I extends z.input<typeof ZodSuruId> = z.input<typeof ZodSuruId>, O extends typeof this.convertOutput = typeof this.convertOutput>(_input: I): Promise<z.output<O>>;
|
|
82
|
+
static suruConvertSync<O extends typeof this.convertOutput = typeof this.convertOutput>(_input: undefined): z.output<ZodPartial<O>>;
|
|
83
|
+
static suruConvertSync<I extends z.input<typeof ZodSuruId> = z.input<typeof ZodSuruId>, O extends typeof this.convertOutput = typeof this.convertOutput>(_input: I): z.output<O>;
|
|
84
|
+
static suruExtract<O extends typeof this.extractOutput = typeof this.extractOutput, UO extends z.output<ZodPartial<O>> = z.output<ZodPartial<O>>>(_input: undefined): Promise<UO>;
|
|
85
|
+
static suruExtract<I extends z.input<typeof ZodSuruId> = z.input<typeof ZodSuruId>, O extends typeof this.extractOutput = typeof this.extractOutput>(_input: I): Promise<z.output<O>>;
|
|
86
|
+
static suruExtractSync<O extends typeof this.extractOutput = typeof this.extractOutput, UO extends z.output<ZodPartial<O>> = z.output<ZodPartial<O>>>(_input: undefined): UO;
|
|
87
|
+
static suruExtractSync<I extends z.input<typeof ZodSuruId> = z.input<typeof ZodSuruId>, O extends typeof this.extractOutput = typeof this.extractOutput>(_input: I): z.output<O>;
|
|
88
|
+
}
|
package/dist/suru.mjs
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { DOJurisdictions, DOLocations } from '@chainfuse/types';
|
|
2
|
+
import { D0CombinedLocations, D0Environment, D0ShardType, D0SystemType, D0Version } from '@chainfuse/types/d0';
|
|
3
|
+
import { ZodBlob, ZodBlobExport } from '@chainfuse/types/zod-mini';
|
|
4
|
+
import * as z from 'zod/mini';
|
|
5
|
+
import { BufferHelpers } from "./buffers.mjs";
|
|
6
|
+
import { CryptoHelpers } from "./crypto.mjs";
|
|
7
|
+
export class SuruId {
|
|
8
|
+
static extractOutputBase = z.object({
|
|
9
|
+
version: z.enum(D0Version),
|
|
10
|
+
date: z.date().check(z.minimum(new Date(0)), z.maximum(new Date(Number(BigInt('0x0fffffffffff'))))),
|
|
11
|
+
systemType: z.enum(D0SystemType),
|
|
12
|
+
shardType: z.enum(D0ShardType),
|
|
13
|
+
// Location
|
|
14
|
+
suffixRandom: z.object({
|
|
15
|
+
hex: z.hex().check(z.trim(), z.toLowerCase(), z.length(11)),
|
|
16
|
+
base64: z.base64().check(z.trim(), z.maxLength(Math.ceil((11 * (4 / 6)) / 4) * 4)),
|
|
17
|
+
base64url: z.base64url().check(z.trim(), z.maxLength(Math.round(11 * (4 / 6)))),
|
|
18
|
+
}),
|
|
19
|
+
environment: z.enum(D0Environment),
|
|
20
|
+
stableRandom: z.object({
|
|
21
|
+
hex: z.hex().check(z.trim(), z.toLowerCase(), z.length(64)),
|
|
22
|
+
base64: z.base64().check(z.trim(), z.maxLength(Math.ceil((64 * (4 / 6)) / 4) * 4)),
|
|
23
|
+
base64url: z.base64url().check(z.trim(), z.maxLength(Math.round(64 * (4 / 6)))),
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
static extractOutput = z.extend(SuruId.extractOutputBase, {
|
|
27
|
+
locationJurisdiction: z.nullable(z.enum(DOJurisdictions)),
|
|
28
|
+
locationHint: z.nullable(z.enum(DOLocations)),
|
|
29
|
+
});
|
|
30
|
+
static convertOutput = z.object({
|
|
31
|
+
hex: z.hex().check(z.trim(), z.toLowerCase(), z.length(96)),
|
|
32
|
+
blob: ZodBlobExport,
|
|
33
|
+
base64: z.base64().check(z.trim(), z.maxLength(64)),
|
|
34
|
+
base64url: z.base64url().check(z.trim(), z.maxLength(64)),
|
|
35
|
+
});
|
|
36
|
+
static createInputBase = z.object({
|
|
37
|
+
...this.extractOutputBase.def.shape,
|
|
38
|
+
version: z._default(this.extractOutputBase.def.shape.version, D0Version.v1),
|
|
39
|
+
date: z._default(this.extractOutputBase.def.shape.date, () => new Date()),
|
|
40
|
+
// systemType
|
|
41
|
+
shardType: z._default(this.extractOutputBase.def.shape.shardType, D0ShardType.None),
|
|
42
|
+
// Location
|
|
43
|
+
suffixRandom: z._default(ZodBlob, () => CryptoHelpers.secretBytesSync(Math.ceil(44 / 8))).check(z.refine((b) => b.byteLength === Math.ceil(44 / 8))),
|
|
44
|
+
// environment
|
|
45
|
+
stableRandom: z._default(ZodBlob, () => CryptoHelpers.secretBytesSync(256 / 8)).check(z.refine((b) => b.byteLength === 256 / 8)),
|
|
46
|
+
});
|
|
47
|
+
static createInput = z.union([
|
|
48
|
+
z.extend(SuruId.createInputBase, {
|
|
49
|
+
locationJurisdiction: z._default(z.nullable(z.enum(DOJurisdictions)), null),
|
|
50
|
+
locationHint: z._default(z.null(), null),
|
|
51
|
+
}),
|
|
52
|
+
z.extend(SuruId.createInputBase, {
|
|
53
|
+
locationJurisdiction: z._default(z.null(), null),
|
|
54
|
+
locationHint: z._default(z.nullable(z.enum(DOLocations)), null),
|
|
55
|
+
}),
|
|
56
|
+
]);
|
|
57
|
+
static suruCreate(_input) {
|
|
58
|
+
return SuruId.createInput.parseAsync(_input).then(async (input) => {
|
|
59
|
+
// Pack fields into hex
|
|
60
|
+
let hex = '';
|
|
61
|
+
// Version (4 bytes)
|
|
62
|
+
hex += Number(input.version).toString(16);
|
|
63
|
+
// Timestamp (11 bytes, pad to 12 chars, mask top nibble for version)
|
|
64
|
+
hex += input.date.getTime().toString(16).padStart(12, '0').slice(-11);
|
|
65
|
+
// System Type (3 bytes)
|
|
66
|
+
hex += input.systemType.toString(16).padStart(3, '0').slice(-3);
|
|
67
|
+
// Location (3 bytes)
|
|
68
|
+
hex += (input.locationJurisdiction ? D0CombinedLocations[input.locationJurisdiction] : input.locationHint ? D0CombinedLocations[input.locationHint] : D0CombinedLocations.none).toString(16).padStart(3, '0').slice(-3);
|
|
69
|
+
// Shard Type (2 bytes)
|
|
70
|
+
hex += input.shardType.toString(16).padStart(2, '0').slice(-2);
|
|
71
|
+
// Suffix random (11 bytes)
|
|
72
|
+
hex += (await BufferHelpers.bufferToHex(input.suffixRandom.buffer)).padStart(11, '0').slice(-11);
|
|
73
|
+
// Environment (1 byte)
|
|
74
|
+
hex += input.environment.toString(16).slice(-3);
|
|
75
|
+
// Stable random (32 bytes)
|
|
76
|
+
hex += (await BufferHelpers.bufferToHex(input.stableRandom.buffer)).padStart(64, '0').slice(-64);
|
|
77
|
+
const blob = await BufferHelpers.hexToBuffer(hex);
|
|
78
|
+
const [base64, base64url] = await Promise.all([BufferHelpers.bufferToBase64(blob, false), BufferHelpers.bufferToBase64(blob, true)]);
|
|
79
|
+
return this.convertOutput.parseAsync({
|
|
80
|
+
hex,
|
|
81
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
82
|
+
base64,
|
|
83
|
+
base64url,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
static suruCreateSync(_input) {
|
|
88
|
+
const input = SuruId.createInput.parse(_input);
|
|
89
|
+
// Pack fields into hex
|
|
90
|
+
let hex = '';
|
|
91
|
+
// Version (4 bytes)
|
|
92
|
+
hex += Number(input.version).toString(16);
|
|
93
|
+
// Timestamp (11 bytes, pad to 12 chars, mask top nibble for version)
|
|
94
|
+
hex += input.date.getTime().toString(16).padStart(12, '0').slice(-11);
|
|
95
|
+
// System Type (3 bytes)
|
|
96
|
+
hex += input.systemType.toString(16).padStart(3, '0').slice(-3);
|
|
97
|
+
// Location (3 bytes)
|
|
98
|
+
hex += (input.locationJurisdiction ? D0CombinedLocations[input.locationJurisdiction] : input.locationHint ? D0CombinedLocations[input.locationHint] : D0CombinedLocations.none).toString(16).padStart(3, '0').slice(-3);
|
|
99
|
+
// Shard Type (2 bytes)
|
|
100
|
+
hex += input.shardType.toString(16).padStart(2, '0').slice(-2);
|
|
101
|
+
// Suffix random (11 bytes)
|
|
102
|
+
hex += BufferHelpers.bufferToHexSync(input.suffixRandom.buffer).padStart(11, '0').slice(-11);
|
|
103
|
+
// Environment (1 byte)
|
|
104
|
+
hex += input.environment.toString(16).slice(-3);
|
|
105
|
+
// Stable random (32 bytes)
|
|
106
|
+
hex += BufferHelpers.bufferToHexSync(input.stableRandom.buffer).padStart(64, '0').slice(-64);
|
|
107
|
+
const blob = BufferHelpers.hexToBufferSync(hex);
|
|
108
|
+
return this.convertOutput.parse({
|
|
109
|
+
hex,
|
|
110
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
111
|
+
base64: BufferHelpers.bufferToBase64Sync(blob, false),
|
|
112
|
+
base64url: BufferHelpers.bufferToBase64Sync(blob, true),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
static suruConvert(_input) {
|
|
116
|
+
if (_input) {
|
|
117
|
+
// hex
|
|
118
|
+
return Promise.any([
|
|
119
|
+
SuruId.convertOutput.def.shape.hex.parseAsync(_input).then((hex) => BufferHelpers.hexToBuffer(hex).then((blob) => Promise.all([BufferHelpers.bufferToBase64(blob, false), BufferHelpers.bufferToBase64(blob, true)]).then(([base64, base64url]) => this.convertOutput.parseAsync({
|
|
120
|
+
hex,
|
|
121
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
122
|
+
base64,
|
|
123
|
+
base64url,
|
|
124
|
+
})))),
|
|
125
|
+
ZodBlob.parseAsync(_input).then((blob) => Promise.all([BufferHelpers.bufferToHex(blob.buffer), BufferHelpers.bufferToBase64(blob.buffer, false), BufferHelpers.bufferToBase64(blob.buffer, true)]).then(([hex, base64, base64url]) => this.convertOutput.parseAsync({
|
|
126
|
+
hex,
|
|
127
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
128
|
+
base64,
|
|
129
|
+
base64url,
|
|
130
|
+
}))),
|
|
131
|
+
]).catch(() => Promise.any([
|
|
132
|
+
SuruId.convertOutput.def.shape.base64.parseAsync(_input).then((base64) => BufferHelpers.base64ToBuffer(base64).then((blob) => Promise.all([BufferHelpers.bufferToHex(blob), BufferHelpers.bufferToBase64(blob, true)]).then(([hex, base64url]) => this.convertOutput.parseAsync({
|
|
133
|
+
hex,
|
|
134
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
135
|
+
base64,
|
|
136
|
+
base64url,
|
|
137
|
+
})))),
|
|
138
|
+
SuruId.convertOutput.def.shape.base64url.parseAsync(_input).then((base64url) => BufferHelpers.base64ToBuffer(base64url).then((blob) => Promise.all([BufferHelpers.bufferToHex(blob), BufferHelpers.bufferToBase64(blob, false)]).then(([hex, base64]) => this.convertOutput.parseAsync({
|
|
139
|
+
hex,
|
|
140
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
141
|
+
base64,
|
|
142
|
+
base64url,
|
|
143
|
+
})))),
|
|
144
|
+
]));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
148
|
+
return (async () => ({
|
|
149
|
+
hex: undefined,
|
|
150
|
+
blob: undefined,
|
|
151
|
+
base64: undefined,
|
|
152
|
+
base64url: undefined,
|
|
153
|
+
}))();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
static suruConvertSync(_input) {
|
|
157
|
+
if (_input) {
|
|
158
|
+
try {
|
|
159
|
+
const hex = SuruId.convertOutput.def.shape.hex.parse(_input);
|
|
160
|
+
const blob = BufferHelpers.hexToBufferSync(hex);
|
|
161
|
+
const base64 = BufferHelpers.bufferToBase64Sync(blob, false);
|
|
162
|
+
const base64url = BufferHelpers.bufferToBase64Sync(blob, true);
|
|
163
|
+
return this.convertOutput.parse({
|
|
164
|
+
hex,
|
|
165
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
166
|
+
base64,
|
|
167
|
+
base64url,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
try {
|
|
172
|
+
const blob = ZodBlob.parse(_input);
|
|
173
|
+
const hex = BufferHelpers.bufferToHexSync(blob.buffer);
|
|
174
|
+
const base64 = BufferHelpers.bufferToBase64Sync(blob.buffer, false);
|
|
175
|
+
const base64url = BufferHelpers.bufferToBase64Sync(blob.buffer, true);
|
|
176
|
+
return this.convertOutput.parse({
|
|
177
|
+
hex,
|
|
178
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
179
|
+
base64,
|
|
180
|
+
base64url,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
try {
|
|
185
|
+
const base64 = SuruId.convertOutput.def.shape.base64.parse(_input);
|
|
186
|
+
const blob = BufferHelpers.base64ToBufferSync(base64);
|
|
187
|
+
const hex = BufferHelpers.bufferToHexSync(blob);
|
|
188
|
+
const base64url = BufferHelpers.bufferToBase64Sync(blob, true);
|
|
189
|
+
return this.convertOutput.parse({
|
|
190
|
+
hex,
|
|
191
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
192
|
+
base64,
|
|
193
|
+
base64url,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
const base64url = SuruId.convertOutput.def.shape.base64url.parse(_input);
|
|
198
|
+
const blob = BufferHelpers.base64ToBufferSync(base64url);
|
|
199
|
+
const hex = BufferHelpers.bufferToHexSync(blob);
|
|
200
|
+
const base64 = BufferHelpers.bufferToBase64Sync(blob, false);
|
|
201
|
+
return this.convertOutput.parse({
|
|
202
|
+
hex,
|
|
203
|
+
blob: Array.from(new Uint8Array(blob)),
|
|
204
|
+
base64,
|
|
205
|
+
base64url,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
return {
|
|
213
|
+
hex: undefined,
|
|
214
|
+
blob: undefined,
|
|
215
|
+
base64: undefined,
|
|
216
|
+
base64url: undefined,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
static suruExtract(_input) {
|
|
221
|
+
if (_input) {
|
|
222
|
+
return this.suruConvert(_input).then(async ({ hex }) => {
|
|
223
|
+
// Extract fields from hex string (96 chars total)
|
|
224
|
+
let offset = 0;
|
|
225
|
+
// Version (1 char = 4 bits)
|
|
226
|
+
const version = parseInt(hex.slice(offset, offset + 1), 16);
|
|
227
|
+
offset += 1;
|
|
228
|
+
// Timestamp (11 chars)
|
|
229
|
+
const timestamp = parseInt(hex.slice(offset, offset + 11), 16);
|
|
230
|
+
const date = new Date(timestamp);
|
|
231
|
+
offset += 11;
|
|
232
|
+
// System Type (3 chars)
|
|
233
|
+
const systemType = parseInt(hex.slice(offset, offset + 3), 16);
|
|
234
|
+
offset += 3;
|
|
235
|
+
// Location (3 chars)
|
|
236
|
+
const locationValue = parseInt(hex.slice(offset, offset + 3), 16);
|
|
237
|
+
offset += 3;
|
|
238
|
+
// Find jurisdiction and hint from location value
|
|
239
|
+
let locationJurisdiction = null;
|
|
240
|
+
let locationHint = null;
|
|
241
|
+
// Map D0CombinedLocations values to jurisdiction/location enums
|
|
242
|
+
// Find the location key that matches the value
|
|
243
|
+
const locationKey = Object.entries(D0CombinedLocations).find(([, enumValue]) => Number(enumValue) === locationValue)?.[0];
|
|
244
|
+
if (locationKey && locationKey !== 'none') {
|
|
245
|
+
// Check if it's a jurisdiction
|
|
246
|
+
if (Object.values(DOJurisdictions).includes(locationKey)) {
|
|
247
|
+
locationJurisdiction = locationKey;
|
|
248
|
+
}
|
|
249
|
+
// Check if it's a location hint
|
|
250
|
+
if (Object.values(DOLocations).includes(locationKey)) {
|
|
251
|
+
locationHint = locationKey;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Shard Type (2 chars)
|
|
255
|
+
const shardType = parseInt(hex.slice(offset, offset + 2), 16);
|
|
256
|
+
offset += 2;
|
|
257
|
+
// Suffix random (11 chars)
|
|
258
|
+
const suffixRandomHex = hex.slice(offset, offset + 11);
|
|
259
|
+
const suffixRandomBuffer = await BufferHelpers.hexToBuffer(suffixRandomHex);
|
|
260
|
+
const [suffixRandomBase64, suffixRandomBase64Url] = await Promise.all([BufferHelpers.bufferToBase64(suffixRandomBuffer, false), BufferHelpers.bufferToBase64(suffixRandomBuffer, true)]);
|
|
261
|
+
offset += 11;
|
|
262
|
+
// Environment (1 char)
|
|
263
|
+
const environment = parseInt(hex.slice(offset, offset + 1), 16);
|
|
264
|
+
offset += 1;
|
|
265
|
+
// Stable random (64 chars)
|
|
266
|
+
const stableRandomHex = hex.slice(offset, offset + 64);
|
|
267
|
+
const stableRandomBuffer = await BufferHelpers.hexToBuffer(stableRandomHex);
|
|
268
|
+
const [stableRandomBase64, stableRandomBase64Url] = await Promise.all([BufferHelpers.bufferToBase64(stableRandomBuffer, false), BufferHelpers.bufferToBase64(stableRandomBuffer, true)]);
|
|
269
|
+
return this.extractOutput.parseAsync({
|
|
270
|
+
version,
|
|
271
|
+
date,
|
|
272
|
+
systemType,
|
|
273
|
+
shardType,
|
|
274
|
+
locationJurisdiction,
|
|
275
|
+
locationHint,
|
|
276
|
+
suffixRandom: {
|
|
277
|
+
hex: suffixRandomHex,
|
|
278
|
+
base64: suffixRandomBase64,
|
|
279
|
+
base64url: suffixRandomBase64Url,
|
|
280
|
+
},
|
|
281
|
+
environment,
|
|
282
|
+
stableRandom: {
|
|
283
|
+
hex: stableRandomHex,
|
|
284
|
+
base64: stableRandomBase64,
|
|
285
|
+
base64url: stableRandomBase64Url,
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
292
|
+
return (async () => ({
|
|
293
|
+
version: undefined,
|
|
294
|
+
date: undefined,
|
|
295
|
+
systemType: undefined,
|
|
296
|
+
shardType: undefined,
|
|
297
|
+
locationJurisdiction: undefined,
|
|
298
|
+
locationHint: undefined,
|
|
299
|
+
suffixRandom: undefined,
|
|
300
|
+
environment: undefined,
|
|
301
|
+
stableRandom: undefined,
|
|
302
|
+
}))();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
static suruExtractSync(_input) {
|
|
306
|
+
if (_input) {
|
|
307
|
+
const { hex } = this.suruConvertSync(_input);
|
|
308
|
+
// Extract fields from hex string (96 chars total)
|
|
309
|
+
let offset = 0;
|
|
310
|
+
// Version (1 char = 4 bits)
|
|
311
|
+
const version = parseInt(hex.slice(offset, offset + 1), 16);
|
|
312
|
+
offset += 1;
|
|
313
|
+
// Timestamp (11 chars)
|
|
314
|
+
const timestamp = parseInt(hex.slice(offset, offset + 11), 16);
|
|
315
|
+
const date = new Date(timestamp);
|
|
316
|
+
offset += 11;
|
|
317
|
+
// System Type (3 chars)
|
|
318
|
+
const systemType = parseInt(hex.slice(offset, offset + 3), 16);
|
|
319
|
+
offset += 3;
|
|
320
|
+
// Location (3 chars)
|
|
321
|
+
const locationValue = parseInt(hex.slice(offset, offset + 3), 16);
|
|
322
|
+
offset += 3;
|
|
323
|
+
// Find jurisdiction and hint from location value
|
|
324
|
+
let locationJurisdiction = null;
|
|
325
|
+
let locationHint = null;
|
|
326
|
+
// Map D0CombinedLocations values to jurisdiction/location enums
|
|
327
|
+
// Find the location key that matches the value
|
|
328
|
+
const locationKey = Object.entries(D0CombinedLocations).find(([, enumValue]) => Number(enumValue) === locationValue)?.[0];
|
|
329
|
+
if (locationKey && locationKey !== 'none') {
|
|
330
|
+
// Check if it's a jurisdiction
|
|
331
|
+
if (Object.values(DOJurisdictions).includes(locationKey)) {
|
|
332
|
+
locationJurisdiction = locationKey;
|
|
333
|
+
}
|
|
334
|
+
// Check if it's a location hint
|
|
335
|
+
if (Object.values(DOLocations).includes(locationKey)) {
|
|
336
|
+
locationHint = locationKey;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Shard Type (2 chars)
|
|
340
|
+
const shardType = parseInt(hex.slice(offset, offset + 2), 16);
|
|
341
|
+
offset += 2;
|
|
342
|
+
// Suffix random (11 chars)
|
|
343
|
+
const suffixRandomHex = hex.slice(offset, offset + 11);
|
|
344
|
+
const suffixRandomBuffer = BufferHelpers.hexToBufferSync(suffixRandomHex);
|
|
345
|
+
const suffixRandomBase64 = BufferHelpers.bufferToBase64Sync(suffixRandomBuffer, false);
|
|
346
|
+
const suffixRandomBase64Url = BufferHelpers.bufferToBase64Sync(suffixRandomBuffer, true);
|
|
347
|
+
offset += 11;
|
|
348
|
+
// Environment (1 char)
|
|
349
|
+
const environment = parseInt(hex.slice(offset, offset + 1), 16);
|
|
350
|
+
offset += 1;
|
|
351
|
+
// Stable random (64 chars)
|
|
352
|
+
const stableRandomHex = hex.slice(offset, offset + 64);
|
|
353
|
+
const stableRandomBuffer = BufferHelpers.hexToBufferSync(stableRandomHex);
|
|
354
|
+
const stableRandomBase64 = BufferHelpers.bufferToBase64Sync(stableRandomBuffer, false);
|
|
355
|
+
const stableRandomBase64Url = BufferHelpers.bufferToBase64Sync(stableRandomBuffer, true);
|
|
356
|
+
return this.extractOutput.parse({
|
|
357
|
+
version,
|
|
358
|
+
date,
|
|
359
|
+
systemType,
|
|
360
|
+
shardType,
|
|
361
|
+
locationJurisdiction,
|
|
362
|
+
locationHint,
|
|
363
|
+
suffixRandom: {
|
|
364
|
+
hex: suffixRandomHex,
|
|
365
|
+
base64: suffixRandomBase64,
|
|
366
|
+
base64url: suffixRandomBase64Url,
|
|
367
|
+
},
|
|
368
|
+
environment,
|
|
369
|
+
stableRandom: {
|
|
370
|
+
hex: stableRandomHex,
|
|
371
|
+
base64: stableRandomBase64,
|
|
372
|
+
base64url: stableRandomBase64Url,
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
return {
|
|
378
|
+
version: undefined,
|
|
379
|
+
date: undefined,
|
|
380
|
+
systemType: undefined,
|
|
381
|
+
shardType: undefined,
|
|
382
|
+
locationJurisdiction: undefined,
|
|
383
|
+
locationHint: undefined,
|
|
384
|
+
suffixRandom: undefined,
|
|
385
|
+
environment: undefined,
|
|
386
|
+
stableRandom: undefined,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainfuse/helpers",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "ChainFuse",
|
|
6
6
|
"homepage": "https://github.com/ChainFuse/packages/tree/main/packages/helpers#readme",
|
|
@@ -72,26 +72,22 @@
|
|
|
72
72
|
"./net": {
|
|
73
73
|
"import": "./dist/net.mjs",
|
|
74
74
|
"types": "./dist/net.d.mts"
|
|
75
|
-
},
|
|
76
|
-
"./uuid8": {
|
|
77
|
-
"import": "./dist/uuid8.mjs",
|
|
78
|
-
"types": "./dist/uuid8.d.mts"
|
|
79
75
|
}
|
|
80
76
|
},
|
|
81
77
|
"prettier": "@demosjarco/prettier-config",
|
|
82
78
|
"dependencies": {
|
|
83
|
-
"@chainfuse/types": "^4.0.
|
|
79
|
+
"@chainfuse/types": "^4.0.1",
|
|
84
80
|
"@discordjs/rest": "^2.6.0",
|
|
85
81
|
"chalk": "^5.6.2",
|
|
86
82
|
"cloudflare": "^5.1.0",
|
|
87
83
|
"drizzle-orm": "^0.44.5",
|
|
88
84
|
"strip-ansi": "^7.1.2",
|
|
89
85
|
"uuid": "^13.0.0",
|
|
90
|
-
"zod": "^4.1.
|
|
86
|
+
"zod": "^4.1.11"
|
|
91
87
|
},
|
|
92
88
|
"devDependencies": {
|
|
93
|
-
"@cloudflare/workers-types": "^4.
|
|
94
|
-
"@types/node": "^22.18.
|
|
89
|
+
"@cloudflare/workers-types": "^4.20250923.0",
|
|
90
|
+
"@types/node": "^22.18.6"
|
|
95
91
|
},
|
|
96
|
-
"gitHead": "
|
|
92
|
+
"gitHead": "ab58de73242e411360ae80368ee2f69a5798c653"
|
|
97
93
|
}
|
package/dist/uuid8.d.mts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { DOCombinedLocations } from '@chainfuse/types';
|
|
2
|
-
import { ShardType } from '@chainfuse/types/d0';
|
|
3
|
-
import * as z from 'zod/mini';
|
|
4
|
-
export declare const v8Options: z.ZodMiniUnion<readonly [z.ZodMiniObject<{
|
|
5
|
-
msecs: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniNumberFormat, z.ZodMiniPipe<z.ZodMiniDate<Date>, z.ZodMiniTransform<number, Date>>]>>;
|
|
6
|
-
seq: z.ZodMiniOptional<z.ZodMiniNumberFormat>;
|
|
7
|
-
location: z.ZodMiniUnion<readonly [z.ZodMiniDefault<z.ZodMiniCustomStringFormat<"hex">>, z.ZodMiniPipe<z.ZodMiniDefault<z.ZodMiniEnum<typeof DOCombinedLocations>>, z.ZodMiniTransform<string, DOCombinedLocations>>]>;
|
|
8
|
-
shardType: z.ZodMiniUnion<readonly [z.ZodMiniDefault<z.ZodMiniCustomStringFormat<"hex">>, z.ZodMiniPipe<z.ZodMiniDefault<z.ZodMiniEnum<typeof ShardType>>, z.ZodMiniTransform<string, ShardType>>]>;
|
|
9
|
-
suffix: z.ZodMiniUnion<readonly [z.ZodMiniDefault<z.ZodMiniCustomStringFormat<"hex">>, z.ZodMiniPipe<z.ZodMiniDefault<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>, z.ZodMiniTransform<string, Uint8Array<ArrayBuffer>>>]>;
|
|
10
|
-
random: z.ZodMiniOptional<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
|
|
11
|
-
}, z.core.$strip>, z.ZodMiniObject<{
|
|
12
|
-
msecs: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniNumberFormat, z.ZodMiniPipe<z.ZodMiniDate<Date>, z.ZodMiniTransform<number, Date>>]>>;
|
|
13
|
-
seq: z.ZodMiniOptional<z.ZodMiniNumberFormat>;
|
|
14
|
-
location: z.ZodMiniUnion<readonly [z.ZodMiniDefault<z.ZodMiniCustomStringFormat<"hex">>, z.ZodMiniPipe<z.ZodMiniDefault<z.ZodMiniEnum<typeof DOCombinedLocations>>, z.ZodMiniTransform<string, DOCombinedLocations>>]>;
|
|
15
|
-
shardType: z.ZodMiniUnion<readonly [z.ZodMiniDefault<z.ZodMiniCustomStringFormat<"hex">>, z.ZodMiniPipe<z.ZodMiniDefault<z.ZodMiniEnum<typeof ShardType>>, z.ZodMiniTransform<string, ShardType>>]>;
|
|
16
|
-
suffix: z.ZodMiniUnion<readonly [z.ZodMiniDefault<z.ZodMiniCustomStringFormat<"hex">>, z.ZodMiniPipe<z.ZodMiniDefault<z.ZodMiniCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>, z.ZodMiniTransform<string, Uint8Array<ArrayBuffer>>>]>;
|
|
17
|
-
rng: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniUnknown, z.ZodMiniTransform<() => Uint8Array, unknown>>>;
|
|
18
|
-
}, z.core.$strip>]>;
|
|
19
|
-
export type Version8Options = z.input<typeof v8Options>;
|
|
20
|
-
/**
|
|
21
|
-
* Generates a UUID version 8 with custom fields for location, shard type, and suffix.
|
|
22
|
-
*
|
|
23
|
-
* This function creates a UUID v8 by starting with a UUID v7 and then injecting custom fields into specific positions to encode regional information, shard types, and additional suffixes for distributed system identification.
|
|
24
|
-
*
|
|
25
|
-
* @param options - Configuration options for UUID generation
|
|
26
|
-
* @param options.msecs - RFC "timestamp" field - milliseconds since epoch or Date object
|
|
27
|
-
* @param options.seq - 32-bit sequence number (0 - 0xffffffff) for uniqueness within same millisecond
|
|
28
|
-
* @param options.location - Location identifier as hex string or DOCombinedLocations enum
|
|
29
|
-
* @param options.shardType - Shard type as hex string or ShardType enum
|
|
30
|
-
* @param options.suffix - Custom suffix as hex string or Uint8Array of 2 bytes
|
|
31
|
-
* @param options.random - Array of 16 random bytes for UUID generation
|
|
32
|
-
* @param options.rng - Alternative random number generator function
|
|
33
|
-
*
|
|
34
|
-
* @returns A UUID v8 string with embedded location, shard type, and suffix information
|
|
35
|
-
*/
|
|
36
|
-
export declare function v8(_options?: Version8Options): string;
|
|
37
|
-
export default v8;
|
package/dist/uuid8.mjs
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { DOCombinedLocations } from '@chainfuse/types';
|
|
2
|
-
import { ShardType } from '@chainfuse/types/d0';
|
|
3
|
-
import { v7 } from 'uuid';
|
|
4
|
-
import * as z from 'zod/mini';
|
|
5
|
-
import { BufferHelpersInternals } from "./bufferInternals.mjs";
|
|
6
|
-
import { Helpers } from "./common.mjs";
|
|
7
|
-
const v8OptionsBase = z.object({
|
|
8
|
-
/**
|
|
9
|
-
* RFC "timestamp" field
|
|
10
|
-
*/
|
|
11
|
-
msecs: z.optional(z.union([
|
|
12
|
-
z.int().check(z.nonnegative()),
|
|
13
|
-
// Allow converting from Date object
|
|
14
|
-
z.pipe(z.date(), z.transform((date) => date.getTime())),
|
|
15
|
-
])),
|
|
16
|
-
/**
|
|
17
|
-
* 32-bit sequence Number between 0 - 0xffffffff. This may be provided to help ensure uniqueness for UUIDs generated within the same millisecond time interval. Default = random value.
|
|
18
|
-
*/
|
|
19
|
-
seq: z.optional(z.int().check(z.minimum(0), z.maximum(0xffffffff))),
|
|
20
|
-
location: z.union([
|
|
21
|
-
//
|
|
22
|
-
z._default(z.hex().check(z.length(2)), '00'),
|
|
23
|
-
z.pipe(z._default(z.enum(DOCombinedLocations), DOCombinedLocations.none), z.transform((l) => l.toString(16).padStart(2, '0').slice(-2))),
|
|
24
|
-
]),
|
|
25
|
-
shardType: z.union([
|
|
26
|
-
//
|
|
27
|
-
z._default(z.hex().check(z.length(1)), '0'),
|
|
28
|
-
z.pipe(z._default(z.enum(ShardType), ShardType.Director), z.transform((st) => st.toString(16).padStart(1, '0'))),
|
|
29
|
-
]),
|
|
30
|
-
suffix: z.union([
|
|
31
|
-
z._default(z.hex().check(z.length(3)), '000'),
|
|
32
|
-
// It's technically 1.5 bytes, but we round up to nearest integer
|
|
33
|
-
z.pipe(z._default(z.instanceof(Uint8Array).check(z.refine((arr) => arr.byteLength === 2, { message: 'suffix must be a Uint8Array of 2 bytes' })), new Uint8Array(2)), z.transform((arr) => BufferHelpersInternals.browser_bufferToHex(arr.buffer).padStart(3, '0').slice(-3))),
|
|
34
|
-
]),
|
|
35
|
-
});
|
|
36
|
-
export const v8Options = z.union([
|
|
37
|
-
z.extend(v8OptionsBase, {
|
|
38
|
-
/**
|
|
39
|
-
* Array of 16 random bytes (0-255) used to generate other fields
|
|
40
|
-
*/
|
|
41
|
-
random: z.optional(z.instanceof(Uint8Array).check(z.refine((arr) => arr.byteLength === 16, { message: '`random` must be a Uint8Array of 16 random bytes' }))),
|
|
42
|
-
}),
|
|
43
|
-
z.extend(v8OptionsBase, {
|
|
44
|
-
/**
|
|
45
|
-
* Alternative to options.random, a Function that returns an Array of 16 random bytes (0-255)
|
|
46
|
-
*/
|
|
47
|
-
rng: z.optional(z.pipe(z.unknown(), z.transform((fn) => fn))),
|
|
48
|
-
}),
|
|
49
|
-
]);
|
|
50
|
-
/**
|
|
51
|
-
* Generates a UUID version 8 with custom fields for location, shard type, and suffix.
|
|
52
|
-
*
|
|
53
|
-
* This function creates a UUID v8 by starting with a UUID v7 and then injecting custom fields into specific positions to encode regional information, shard types, and additional suffixes for distributed system identification.
|
|
54
|
-
*
|
|
55
|
-
* @param options - Configuration options for UUID generation
|
|
56
|
-
* @param options.msecs - RFC "timestamp" field - milliseconds since epoch or Date object
|
|
57
|
-
* @param options.seq - 32-bit sequence number (0 - 0xffffffff) for uniqueness within same millisecond
|
|
58
|
-
* @param options.location - Location identifier as hex string or DOCombinedLocations enum
|
|
59
|
-
* @param options.shardType - Shard type as hex string or ShardType enum
|
|
60
|
-
* @param options.suffix - Custom suffix as hex string or Uint8Array of 2 bytes
|
|
61
|
-
* @param options.random - Array of 16 random bytes for UUID generation
|
|
62
|
-
* @param options.rng - Alternative random number generator function
|
|
63
|
-
*
|
|
64
|
-
* @returns A UUID v8 string with embedded location, shard type, and suffix information
|
|
65
|
-
*/
|
|
66
|
-
export function v8(_options) {
|
|
67
|
-
const options = v8Options.parse(_options ?? {});
|
|
68
|
-
// 36 character string including hyphens
|
|
69
|
-
const uuid7 = v7(options);
|
|
70
|
-
// Swap version
|
|
71
|
-
const uuid8 = Helpers.replaceByIndex(uuid7, 14, 15, '8');
|
|
72
|
-
// Inject
|
|
73
|
-
const uuid8Suffix = Helpers.replaceByIndex(uuid8, 15, 18, options.suffix);
|
|
74
|
-
const uuid8SuffixLocation = Helpers.replaceByIndex(uuid8Suffix, 20, 22, options.location);
|
|
75
|
-
const uuid8SuffixLocationShard = Helpers.replaceByIndex(uuid8SuffixLocation, 22, 23, options.shardType);
|
|
76
|
-
return uuid8SuffixLocationShard;
|
|
77
|
-
}
|
|
78
|
-
export default v8;
|