@chainfuse/helpers 3.5.5 → 3.6.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 +10 -0
- package/dist/buffers.d.mts +19 -1
- package/dist/buffers.mjs +93 -2
- package/dist/crypto.mjs +3 -1
- package/dist/net.d.mts +12 -12
- package/dist/uuid8.d.mts +37 -0
- package/dist/uuid8.mjs +100 -0
- package/package.json +13 -9
package/README.md
CHANGED
|
@@ -15,3 +15,13 @@ import helpers from '@chainfuse/helpers';
|
|
|
15
15
|
|
|
16
16
|
// TODO: DEMONSTRATE API
|
|
17
17
|
```
|
|
18
|
+
|
|
19
|
+
## UUIDv8
|
|
20
|
+
|
|
21
|
+
Based on UUIDv7 but with added values to prevent unnecessary lookups
|
|
22
|
+
|
|
23
|
+
`01f3ffff-fc18-8bb7-9120-cabc55668d92`
|
|
24
|
+
|
|
25
|
+
| 01f3ffff-fc18 | 8 | bb7 | 9 | 12 | 0 | cabc55668d92 |
|
|
26
|
+
| ----------------------------------------- | ------------ | --------------------------------- | -------------------------------- | ---------------------------------------- | ----------- | -------------- |
|
|
27
|
+
| 48bit Timestamp (Unix epoch milliseconds) | UUID Version | Suffix random (`000` if director) | variant (2 bits) + 2 random bits | `DOCombinedLocations` (`00` if anywhere) | `ShardType` | 48 random bits |
|
package/dist/buffers.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { UndefinedProperties } from '@chainfuse/types';
|
|
2
|
-
import type { PrefixedUuid, UuidExport } from '@chainfuse/types/d1';
|
|
2
|
+
import type { PrefixedUuid, UuidExport, UUIDExtract } from '@chainfuse/types/d1';
|
|
3
|
+
import type { z } from 'zod/v4';
|
|
4
|
+
import type { Version8Options } from './uuid8.mjs';
|
|
3
5
|
export type UuidExportBlobInput = Buffer | UuidExport['blob'];
|
|
4
6
|
export declare class BufferHelpers {
|
|
5
7
|
static bigintToBuffer(number: bigint): Promise<ArrayBuffer>;
|
|
@@ -9,7 +11,16 @@ export declare class BufferHelpers {
|
|
|
9
11
|
static bufferToHex(buffer: UuidExportBlobInput): Promise<string>;
|
|
10
12
|
static base64ToBuffer(rawBase64: string): Promise<ArrayBuffer>;
|
|
11
13
|
static bufferToBase64(buffer: UuidExportBlobInput, urlSafe: boolean): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Use `BufferHelpers.generateUuid7` instead
|
|
16
|
+
*/
|
|
12
17
|
static get generateUuid(): Promise<UuidExport>;
|
|
18
|
+
static get v7OptionsBase(): Promise<z.ZodObject<{
|
|
19
|
+
msecs: z.ZodOptional<z.ZodUnion<readonly [z.ZodInt, z.ZodPipe<z.ZodDate, z.ZodTransform<number, Date>>]>>;
|
|
20
|
+
seq: z.ZodOptional<z.ZodInt>;
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
|
+
static generateUuid7(_options?: z.input<Awaited<typeof this.v7OptionsBase>>): Promise<UuidExport>;
|
|
23
|
+
static generateUuid8(options?: Omit<Version8Options, 'random' | 'rng'>): Promise<UuidExport>;
|
|
13
24
|
static uuidConvert(input: undefined): Promise<UndefinedProperties<UuidExport>>;
|
|
14
25
|
static uuidConvert(prefixedUtf: PrefixedUuid): Promise<UuidExport>;
|
|
15
26
|
static uuidConvert(input: UuidExport['utf8']): Promise<UuidExport>;
|
|
@@ -17,4 +28,11 @@ export declare class BufferHelpers {
|
|
|
17
28
|
static uuidConvert(input: UuidExportBlobInput): Promise<UuidExport>;
|
|
18
29
|
static uuidConvert(input: UuidExport['base64']): Promise<UuidExport>;
|
|
19
30
|
static uuidConvert(input: UuidExport['base64url']): Promise<UuidExport>;
|
|
31
|
+
static uuidExtractor(input: undefined): Promise<UUIDExtract>;
|
|
32
|
+
static uuidExtractor(prefixedUtf: PrefixedUuid): Promise<UUIDExtract>;
|
|
33
|
+
static uuidExtractor(input: UuidExport['utf8']): Promise<UUIDExtract>;
|
|
34
|
+
static uuidExtractor(input: UuidExport['hex']): Promise<UUIDExtract>;
|
|
35
|
+
static uuidExtractor(input: UuidExportBlobInput): Promise<UUIDExtract>;
|
|
36
|
+
static uuidExtractor(input: UuidExport['base64']): Promise<UUIDExtract>;
|
|
37
|
+
static uuidExtractor(input: UuidExport['base64url']): Promise<UUIDExtract>;
|
|
20
38
|
}
|
package/dist/buffers.mjs
CHANGED
|
@@ -36,9 +36,55 @@ export class BufferHelpers {
|
|
|
36
36
|
static bufferToBase64(buffer, urlSafe) {
|
|
37
37
|
return BufferHelpersInternals.node_bufferToBase64(buffer, urlSafe).catch(() => BufferHelpersInternals.browser_bufferToBase64(buffer, urlSafe));
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated Use `BufferHelpers.generateUuid7` instead
|
|
41
|
+
*/
|
|
39
42
|
static get generateUuid() {
|
|
40
|
-
return
|
|
41
|
-
|
|
43
|
+
return this.generateUuid7();
|
|
44
|
+
}
|
|
45
|
+
static get v7OptionsBase() {
|
|
46
|
+
return import('zod/v4').then(({ z }) => z.object({
|
|
47
|
+
/**
|
|
48
|
+
* RFC "timestamp" field
|
|
49
|
+
*/
|
|
50
|
+
msecs: z
|
|
51
|
+
.union([
|
|
52
|
+
z.int().nonnegative(),
|
|
53
|
+
// Allow converting from Date object
|
|
54
|
+
z.date().transform((date) => date.getTime()),
|
|
55
|
+
])
|
|
56
|
+
.optional(),
|
|
57
|
+
/**
|
|
58
|
+
* 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.
|
|
59
|
+
*/
|
|
60
|
+
seq: z.int().min(0).max(0xffffffff).optional(),
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
static generateUuid7(_options) {
|
|
64
|
+
return Promise.all([
|
|
65
|
+
//
|
|
66
|
+
import('uuid'),
|
|
67
|
+
this.v7OptionsBase.then((schema) => schema.parseAsync(_options ?? {})),
|
|
68
|
+
CryptoHelpers.secretBytes(16),
|
|
69
|
+
]).then(([{ v7: uuidv7 }, options, random]) => {
|
|
70
|
+
const uuid = uuidv7({ msecs: options.msecs, random, seq: options.seq });
|
|
71
|
+
const uuidHex = uuid.replaceAll('-', '');
|
|
72
|
+
return this.hexToBuffer(uuidHex).then((blob) => Promise.all([this.bufferToBase64(blob, false), this.bufferToBase64(blob, true)]).then(([base64, base64url]) => ({
|
|
73
|
+
utf8: uuid,
|
|
74
|
+
hex: uuidHex,
|
|
75
|
+
blob,
|
|
76
|
+
base64,
|
|
77
|
+
base64url,
|
|
78
|
+
})));
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
static generateUuid8(options) {
|
|
82
|
+
return Promise.all([import('./uuid8.mjs'), CryptoHelpers.secretBytes(16)]).then(([{ v8: uuidv8 }, random]) => {
|
|
83
|
+
const uuid = uuidv8({
|
|
84
|
+
// @ts-expect-error they're the exact same
|
|
85
|
+
random,
|
|
86
|
+
...options,
|
|
87
|
+
});
|
|
42
88
|
const uuidHex = uuid.replaceAll('-', '');
|
|
43
89
|
return this.hexToBuffer(uuidHex).then((blob) => Promise.all([this.bufferToBase64(blob, false), this.bufferToBase64(blob, true)]).then(([base64, base64url]) => ({
|
|
44
90
|
utf8: uuid,
|
|
@@ -134,4 +180,49 @@ export class BufferHelpers {
|
|
|
134
180
|
base64url: undefined,
|
|
135
181
|
}))();
|
|
136
182
|
}
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
|
184
|
+
static uuidExtractor(input) {
|
|
185
|
+
return Promise.all([
|
|
186
|
+
import('zod/v4'),
|
|
187
|
+
this.uuidConvert(
|
|
188
|
+
// @ts-expect-error it's the same type
|
|
189
|
+
input),
|
|
190
|
+
]).then(async ([{ z }, { utf8, hex: _hex }]) => {
|
|
191
|
+
const { success: hexSuccess, data: hex } = z.hex().length(32).safeParse(_hex);
|
|
192
|
+
if (hexSuccess) {
|
|
193
|
+
const { success: utf8v7Success } = z.uuid({ version: 'v7' }).safeParse(utf8);
|
|
194
|
+
const { success: utf8v8Success } = z.uuid({ version: 'v8' }).safeParse(utf8);
|
|
195
|
+
if (utf8v7Success || utf8v8Success) {
|
|
196
|
+
const date = new Date(Number(BigInt(`0x${hex.substring(0, 12)}`)));
|
|
197
|
+
if (utf8v8Success) {
|
|
198
|
+
const suffix_hex = hex.substring(13, 16);
|
|
199
|
+
const suffix_buffer = await BufferHelpers.hexToBuffer(suffix_hex);
|
|
200
|
+
return {
|
|
201
|
+
date,
|
|
202
|
+
location: parseInt(hex.slice(17, 19), 16),
|
|
203
|
+
shardType: parseInt(hex.slice(19, 20), 16),
|
|
204
|
+
suffix: suffix_hex === '000'
|
|
205
|
+
? undefined
|
|
206
|
+
: {
|
|
207
|
+
hex: suffix_hex,
|
|
208
|
+
base64: await BufferHelpers.bufferToBase64(suffix_buffer, false),
|
|
209
|
+
base64url: await BufferHelpers.bufferToBase64(suffix_buffer, true),
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
return {
|
|
215
|
+
date,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
throw new Error('Unsupported UUID version provided');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
throw new Error('Invalid UUID provided');
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
137
228
|
}
|
package/dist/crypto.mjs
CHANGED
|
@@ -5,7 +5,9 @@ export class CryptoHelpers {
|
|
|
5
5
|
return CryptoHelpersInternals.node_secretBytes(byteSize).catch(() => CryptoHelpersInternals.browser_secretBytes(byteSize));
|
|
6
6
|
}
|
|
7
7
|
static base16secret(secretLength) {
|
|
8
|
-
return this.secretBytes(secretLength / 2)
|
|
8
|
+
return this.secretBytes(Math.ceil(secretLength / 2))
|
|
9
|
+
.then((bytes) => BufferHelpers.bufferToHex(bytes.buffer))
|
|
10
|
+
.then((hex) => hex.substring(0, secretLength));
|
|
9
11
|
}
|
|
10
12
|
static base62secret(secretLength) {
|
|
11
13
|
const LOWER_CHAR_SET = 'abcdefghijklmnopqrstuvwxyz';
|
package/dist/net.d.mts
CHANGED
|
@@ -89,26 +89,26 @@ export declare class NetHelpers {
|
|
|
89
89
|
*/
|
|
90
90
|
webp: z3.ZodOptional<z3.ZodBoolean>;
|
|
91
91
|
}, "strip", z3.ZodTypeAny, {
|
|
92
|
-
apps: boolean;
|
|
93
92
|
cacheEverything: boolean;
|
|
94
|
-
mirage: boolean;
|
|
95
93
|
scrapeShield: boolean;
|
|
94
|
+
apps: boolean;
|
|
95
|
+
mirage: boolean;
|
|
96
96
|
cacheKey?: string | undefined;
|
|
97
97
|
cacheTags?: [string, ...string[]] | undefined;
|
|
98
98
|
cacheTtl?: number | undefined;
|
|
99
99
|
cacheTtlByStatus?: Record<string, number> | undefined;
|
|
100
|
-
polish?: "
|
|
100
|
+
polish?: "off" | "lossy" | "lossless" | undefined;
|
|
101
101
|
webp?: boolean | undefined;
|
|
102
102
|
}, {
|
|
103
|
-
apps?: boolean | undefined;
|
|
104
103
|
cacheEverything?: boolean | undefined;
|
|
105
104
|
cacheKey?: string | undefined;
|
|
106
105
|
cacheTags?: [string, ...string[]] | undefined;
|
|
107
106
|
cacheTtl?: number | undefined;
|
|
108
107
|
cacheTtlByStatus?: Record<string, number> | undefined;
|
|
109
|
-
mirage?: boolean | undefined;
|
|
110
|
-
polish?: "lossy" | "lossless" | "off" | undefined;
|
|
111
108
|
scrapeShield?: boolean | undefined;
|
|
109
|
+
apps?: boolean | undefined;
|
|
110
|
+
mirage?: boolean | undefined;
|
|
111
|
+
polish?: "off" | "lossy" | "lossless" | undefined;
|
|
112
112
|
webp?: boolean | undefined;
|
|
113
113
|
}>>;
|
|
114
114
|
}, "strip", z3.ZodTypeAny, {
|
|
@@ -119,15 +119,15 @@ export declare class NetHelpers {
|
|
|
119
119
|
custom?: ((...args: unknown[]) => void | Promise<void>) | undefined;
|
|
120
120
|
};
|
|
121
121
|
cf: {
|
|
122
|
-
apps: boolean;
|
|
123
122
|
cacheEverything: boolean;
|
|
124
|
-
mirage: boolean;
|
|
125
123
|
scrapeShield: boolean;
|
|
124
|
+
apps: boolean;
|
|
125
|
+
mirage: boolean;
|
|
126
126
|
cacheKey?: string | undefined;
|
|
127
127
|
cacheTags?: [string, ...string[]] | undefined;
|
|
128
128
|
cacheTtl?: number | undefined;
|
|
129
129
|
cacheTtlByStatus?: Record<string, number> | undefined;
|
|
130
|
-
polish?: "
|
|
130
|
+
polish?: "off" | "lossy" | "lossless" | undefined;
|
|
131
131
|
webp?: boolean | undefined;
|
|
132
132
|
};
|
|
133
133
|
}, {
|
|
@@ -138,15 +138,15 @@ export declare class NetHelpers {
|
|
|
138
138
|
color?: boolean | undefined;
|
|
139
139
|
} | undefined;
|
|
140
140
|
cf?: {
|
|
141
|
-
apps?: boolean | undefined;
|
|
142
141
|
cacheEverything?: boolean | undefined;
|
|
143
142
|
cacheKey?: string | undefined;
|
|
144
143
|
cacheTags?: [string, ...string[]] | undefined;
|
|
145
144
|
cacheTtl?: number | undefined;
|
|
146
145
|
cacheTtlByStatus?: Record<string, number> | undefined;
|
|
147
|
-
mirage?: boolean | undefined;
|
|
148
|
-
polish?: "lossy" | "lossless" | "off" | undefined;
|
|
149
146
|
scrapeShield?: boolean | undefined;
|
|
147
|
+
apps?: boolean | undefined;
|
|
148
|
+
mirage?: boolean | undefined;
|
|
149
|
+
polish?: "off" | "lossy" | "lossless" | undefined;
|
|
150
150
|
webp?: boolean | undefined;
|
|
151
151
|
} | undefined;
|
|
152
152
|
}>>>;
|
package/dist/uuid8.d.mts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DOCombinedLocations } from '@chainfuse/types';
|
|
2
|
+
import { ShardType } from '@chainfuse/types/d0';
|
|
3
|
+
import { z } from 'zod/v4';
|
|
4
|
+
export declare const v8Options: z.ZodUnion<readonly [z.ZodObject<{
|
|
5
|
+
msecs: z.ZodOptional<z.ZodUnion<readonly [z.ZodInt, z.ZodPipe<z.ZodDate, z.ZodTransform<number, Date>>]>>;
|
|
6
|
+
seq: z.ZodOptional<z.ZodInt>;
|
|
7
|
+
location: z.ZodUnion<readonly [z.ZodDefault<z.ZodCustomStringFormat<"hex">>, z.ZodPipe<z.ZodDefault<z.ZodEnum<typeof DOCombinedLocations>>, z.ZodTransform<string, DOCombinedLocations>>]>;
|
|
8
|
+
shardType: z.ZodUnion<readonly [z.ZodDefault<z.ZodCustomStringFormat<"hex">>, z.ZodPipe<z.ZodDefault<z.ZodEnum<typeof ShardType>>, z.ZodTransform<string, ShardType>>]>;
|
|
9
|
+
suffix: z.ZodUnion<readonly [z.ZodDefault<z.ZodCustomStringFormat<"hex">>, z.ZodPipe<z.ZodDefault<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>, z.ZodTransform<string, Uint8Array<ArrayBuffer>>>]>;
|
|
10
|
+
random: z.ZodOptional<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
|
|
11
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
12
|
+
msecs: z.ZodOptional<z.ZodUnion<readonly [z.ZodInt, z.ZodPipe<z.ZodDate, z.ZodTransform<number, Date>>]>>;
|
|
13
|
+
seq: z.ZodOptional<z.ZodInt>;
|
|
14
|
+
location: z.ZodUnion<readonly [z.ZodDefault<z.ZodCustomStringFormat<"hex">>, z.ZodPipe<z.ZodDefault<z.ZodEnum<typeof DOCombinedLocations>>, z.ZodTransform<string, DOCombinedLocations>>]>;
|
|
15
|
+
shardType: z.ZodUnion<readonly [z.ZodDefault<z.ZodCustomStringFormat<"hex">>, z.ZodPipe<z.ZodDefault<z.ZodEnum<typeof ShardType>>, z.ZodTransform<string, ShardType>>]>;
|
|
16
|
+
suffix: z.ZodUnion<readonly [z.ZodDefault<z.ZodCustomStringFormat<"hex">>, z.ZodPipe<z.ZodDefault<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>, z.ZodTransform<string, Uint8Array<ArrayBuffer>>>]>;
|
|
17
|
+
rng: z.ZodOptional<z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>>;
|
|
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
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { DOCombinedLocations } from '@chainfuse/types';
|
|
2
|
+
import { ShardType } from '@chainfuse/types/d0';
|
|
3
|
+
import { v7 } from 'uuid';
|
|
4
|
+
import { z } from 'zod/v4';
|
|
5
|
+
import { BufferHelpersInternals } from "./bufferInternals.mjs";
|
|
6
|
+
const v8OptionsBase = z.object({
|
|
7
|
+
/**
|
|
8
|
+
* RFC "timestamp" field
|
|
9
|
+
*/
|
|
10
|
+
msecs: z
|
|
11
|
+
.union([
|
|
12
|
+
z.int().nonnegative(),
|
|
13
|
+
// Allow converting from Date object
|
|
14
|
+
z.date().transform((date) => date.getTime()),
|
|
15
|
+
])
|
|
16
|
+
.optional(),
|
|
17
|
+
/**
|
|
18
|
+
* 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.
|
|
19
|
+
*/
|
|
20
|
+
seq: z.int().min(0).max(0xffffffff).optional(),
|
|
21
|
+
location: z.union([
|
|
22
|
+
//
|
|
23
|
+
z.hex().length(2).default('00'),
|
|
24
|
+
z
|
|
25
|
+
.enum(DOCombinedLocations)
|
|
26
|
+
.default(DOCombinedLocations.none)
|
|
27
|
+
.transform((r) => r.toString(16).padStart(2, '0').slice(-2)),
|
|
28
|
+
]),
|
|
29
|
+
shardType: z.union([
|
|
30
|
+
//
|
|
31
|
+
z.hex().length(1).default('0'),
|
|
32
|
+
z
|
|
33
|
+
.enum(ShardType)
|
|
34
|
+
.default(ShardType.Director)
|
|
35
|
+
.transform((st) => st.toString(16).padStart(1, '0')),
|
|
36
|
+
]),
|
|
37
|
+
suffix: z.union([
|
|
38
|
+
z.hex().length(3).default('000'),
|
|
39
|
+
// It's technically 1.5 bytes, but we round up to nearest integer
|
|
40
|
+
z
|
|
41
|
+
.instanceof(Uint8Array)
|
|
42
|
+
.refine((arr) => arr.byteLength === 2, { message: 'suffix must be a Uint8Array of 2 bytes' })
|
|
43
|
+
.default(new Uint8Array(2))
|
|
44
|
+
.transform((arr) => BufferHelpersInternals.browser_bufferToHex(arr.buffer).padStart(3, '0').slice(-3)),
|
|
45
|
+
]),
|
|
46
|
+
});
|
|
47
|
+
export const v8Options = z.union([
|
|
48
|
+
v8OptionsBase.extend({
|
|
49
|
+
/**
|
|
50
|
+
* Array of 16 random bytes (0-255) used to generate other fields
|
|
51
|
+
*/
|
|
52
|
+
random: z
|
|
53
|
+
.instanceof(Uint8Array)
|
|
54
|
+
.refine((arr) => arr.byteLength === 16, { message: '`random` must be a Uint8Array of 16 random bytes' })
|
|
55
|
+
.optional(),
|
|
56
|
+
}),
|
|
57
|
+
v8OptionsBase.extend({
|
|
58
|
+
/**
|
|
59
|
+
* Alternative to options.random, a Function that returns an Array of 16 random bytes (0-255)
|
|
60
|
+
*/
|
|
61
|
+
rng: z
|
|
62
|
+
.function({
|
|
63
|
+
input: [],
|
|
64
|
+
output: z.instanceof(Uint8Array).refine((arr) => arr.byteLength === 16, { message: '`random` must be a Uint8Array of 16 random bytes' }),
|
|
65
|
+
})
|
|
66
|
+
.optional(),
|
|
67
|
+
}),
|
|
68
|
+
]);
|
|
69
|
+
function replaceByIndex(input, start, end, replacement) {
|
|
70
|
+
return input.slice(0, start) + replacement + input.slice(end);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Generates a UUID version 8 with custom fields for location, shard type, and suffix.
|
|
74
|
+
*
|
|
75
|
+
* 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.
|
|
76
|
+
*
|
|
77
|
+
* @param options - Configuration options for UUID generation
|
|
78
|
+
* @param options.msecs - RFC "timestamp" field - milliseconds since epoch or Date object
|
|
79
|
+
* @param options.seq - 32-bit sequence number (0 - 0xffffffff) for uniqueness within same millisecond
|
|
80
|
+
* @param options.location - Location identifier as hex string or DOCombinedLocations enum
|
|
81
|
+
* @param options.shardType - Shard type as hex string or ShardType enum
|
|
82
|
+
* @param options.suffix - Custom suffix as hex string or Uint8Array of 2 bytes
|
|
83
|
+
* @param options.random - Array of 16 random bytes for UUID generation
|
|
84
|
+
* @param options.rng - Alternative random number generator function
|
|
85
|
+
*
|
|
86
|
+
* @returns A UUID v8 string with embedded location, shard type, and suffix information
|
|
87
|
+
*/
|
|
88
|
+
export function v8(_options) {
|
|
89
|
+
const options = v8Options.parse(_options ?? {});
|
|
90
|
+
// 36 character string including hyphens
|
|
91
|
+
const uuid7 = v7(options);
|
|
92
|
+
// Swap version
|
|
93
|
+
const uuid8 = replaceByIndex(uuid7, 14, 15, '8');
|
|
94
|
+
// Inject
|
|
95
|
+
const uuid8Suffix = replaceByIndex(uuid8, 15, 18, options.suffix);
|
|
96
|
+
const uuid8SuffixLocation = replaceByIndex(uuid8Suffix, 20, 22, options.location);
|
|
97
|
+
const uuid8SuffixLocationShard = replaceByIndex(uuid8SuffixLocation, 22, 23, options.shardType);
|
|
98
|
+
return uuid8SuffixLocationShard;
|
|
99
|
+
}
|
|
100
|
+
export default v8;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainfuse/helpers",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "ChainFuse",
|
|
6
6
|
"homepage": "https://github.com/ChainFuse/packages/tree/main/packages/helpers#readme",
|
|
@@ -72,22 +72,26 @@
|
|
|
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"
|
|
75
79
|
}
|
|
76
80
|
},
|
|
77
81
|
"prettier": "@demosjarco/prettier-config",
|
|
78
82
|
"dependencies": {
|
|
79
|
-
"@chainfuse/types": "^2.
|
|
83
|
+
"@chainfuse/types": "^2.12.0",
|
|
80
84
|
"@discordjs/rest": "^2.6.0",
|
|
81
|
-
"chalk": "^5.6.
|
|
82
|
-
"cloudflare": "^
|
|
85
|
+
"chalk": "^5.6.2",
|
|
86
|
+
"cloudflare": "^5.0.0",
|
|
83
87
|
"drizzle-orm": "^0.44.5",
|
|
84
|
-
"strip-ansi": "^7.1.
|
|
85
|
-
"uuid": "^
|
|
88
|
+
"strip-ansi": "^7.1.2",
|
|
89
|
+
"uuid": "^13.0.0",
|
|
86
90
|
"zod": "^4.1.5"
|
|
87
91
|
},
|
|
88
92
|
"devDependencies": {
|
|
89
|
-
"@cloudflare/workers-types": "^4.
|
|
90
|
-
"@types/node": "^22.18.
|
|
93
|
+
"@cloudflare/workers-types": "^4.20250909.0",
|
|
94
|
+
"@types/node": "^22.18.1"
|
|
91
95
|
},
|
|
92
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "fe95f7c82786f19dda1e465f38b19be98613f981"
|
|
93
97
|
}
|