@chainfuse/helpers 4.0.0 → 4.0.2

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.
@@ -5,12 +5,19 @@ import type { Version8Options } from './uuid8.mjs';
5
5
  export type UuidExportBlobInput = Buffer | UuidExport['blob'];
6
6
  export declare class BufferHelpers {
7
7
  static bigintToBuffer(number: bigint): Promise<ArrayBuffer>;
8
- static bigintToHex(number: bigint): string;
8
+ static bigintToBufferSync(number: bigint): ArrayBuffer;
9
+ static bigintToHex(number: bigint): Promise<string>;
10
+ static bigintToHexSync(number: bigint): string;
9
11
  static bufferToBigint(buffer: UuidExportBlobInput): Promise<bigint>;
12
+ static bufferToBigintSync(buffer: UuidExportBlobInput): bigint;
10
13
  static hexToBuffer(hex: UuidExport['hex']): Promise<ArrayBuffer>;
14
+ static hexToBufferSync(hex: UuidExport['hex']): ArrayBuffer;
11
15
  static bufferToHex(buffer: UuidExportBlobInput): Promise<string>;
16
+ static bufferToHexSync(buffer: UuidExportBlobInput): string;
12
17
  static base64ToBuffer(rawBase64: string): Promise<ArrayBuffer>;
18
+ static base64ToBufferSync(rawBase64: string): ArrayBuffer;
13
19
  static bufferToBase64(buffer: UuidExportBlobInput, urlSafe: boolean): Promise<string>;
20
+ static bufferToBase64Sync(buffer: UuidExportBlobInput, urlSafe: boolean): string;
14
21
  static v7OptionsBase: z.ZodMiniObject<{
15
22
  /**
16
23
  * RFC "timestamp" field
@@ -22,7 +29,9 @@ export declare class BufferHelpers {
22
29
  seq: z.ZodMiniOptional<z.ZodMiniNumberFormat>;
23
30
  }, z.core.$strip>;
24
31
  static generateUuid7(_options?: z.input<Awaited<typeof this.v7OptionsBase>>): Promise<UuidExport>;
32
+ static generateUuid7Sync(_options?: z.input<Awaited<typeof this.v7OptionsBase>>): UuidExport;
25
33
  static generateUuid8(options?: Omit<Version8Options, 'random' | 'rng'>): Promise<UuidExport>;
34
+ static generateUuid8Sync(options?: Omit<Version8Options, 'random' | 'rng'>): UuidExport;
26
35
  static uuidConvert(input: undefined): Promise<UndefinedProperties<UuidExport>>;
27
36
  static uuidConvert(prefixedUtf: PrefixedUuid): Promise<UuidExport>;
28
37
  static uuidConvert(input: UuidExport['utf8']): Promise<UuidExport>;
@@ -30,6 +39,13 @@ export declare class BufferHelpers {
30
39
  static uuidConvert(input: UuidExportBlobInput): Promise<UuidExport>;
31
40
  static uuidConvert(input: UuidExport['base64']): Promise<UuidExport>;
32
41
  static uuidConvert(input: UuidExport['base64url']): Promise<UuidExport>;
42
+ static uuidConvertSync(input: undefined): UndefinedProperties<UuidExport>;
43
+ static uuidConvertSync(prefixedUtf: PrefixedUuid): UuidExport;
44
+ static uuidConvertSync(input: UuidExport['utf8']): UuidExport;
45
+ static uuidConvertSync(input: UuidExport['hex']): UuidExport;
46
+ static uuidConvertSync(input: UuidExportBlobInput): UuidExport;
47
+ static uuidConvertSync(input: UuidExport['base64']): UuidExport;
48
+ static uuidConvertSync(input: UuidExport['base64url']): UuidExport;
33
49
  static uuidExtractor(input: undefined): Promise<UUIDExtract>;
34
50
  static uuidExtractor(prefixedUtf: PrefixedUuid): Promise<UUIDExtract>;
35
51
  static uuidExtractor(input: UuidExport['utf8']): Promise<UUIDExtract>;
@@ -37,4 +53,11 @@ export declare class BufferHelpers {
37
53
  static uuidExtractor(input: UuidExportBlobInput): Promise<UUIDExtract>;
38
54
  static uuidExtractor(input: UuidExport['base64']): Promise<UUIDExtract>;
39
55
  static uuidExtractor(input: UuidExport['base64url']): Promise<UUIDExtract>;
56
+ static uuidExtractorSync(input: undefined): UUIDExtract;
57
+ static uuidExtractorSync(prefixedUtf: PrefixedUuid): UUIDExtract;
58
+ static uuidExtractorSync(input: UuidExport['utf8']): UUIDExtract;
59
+ static uuidExtractorSync(input: UuidExport['hex']): UUIDExtract;
60
+ static uuidExtractorSync(input: UuidExportBlobInput): UUIDExtract;
61
+ static uuidExtractorSync(input: UuidExport['base64']): UUIDExtract;
62
+ static uuidExtractorSync(input: UuidExport['base64url']): UUIDExtract;
40
63
  }
package/dist/buffers.mjs CHANGED
@@ -1,24 +1,44 @@
1
1
  import { UUIDExtract7, UUIDExtract8 } from '@chainfuse/types/d1';
2
+ import { PrefixedUuidRaw } from '@chainfuse/types/zod';
3
+ import { v7 as uuidv7 } from 'uuid';
2
4
  import * as z from 'zod/mini';
3
5
  import { BufferHelpersInternals } from "./bufferInternals.mjs";
4
6
  import { CryptoHelpers } from './crypto.mjs';
7
+ import { v8 as uuidv8 } from './uuid8.mjs';
5
8
  export class BufferHelpers {
6
9
  static bigintToBuffer(number) {
7
10
  const hexString = number.toString(16);
8
11
  return this.hexToBuffer(hexString.length % 2 === 0 ? hexString : `0${hexString}`);
9
12
  }
10
- static bigintToHex(number) {
13
+ static bigintToBufferSync(number) {
14
+ const hexString = number.toString(16);
15
+ return this.hexToBufferSync(hexString.length % 2 === 0 ? hexString : `0${hexString}`);
16
+ }
17
+ // eslint-disable-next-line @typescript-eslint/require-await
18
+ static async bigintToHex(number) {
19
+ return number.toString(16).length % 2 === 0 ? number.toString(16) : `0${number.toString(16)}`;
20
+ }
21
+ static bigintToHexSync(number) {
11
22
  return number.toString(16).length % 2 === 0 ? number.toString(16) : `0${number.toString(16)}`;
12
23
  }
13
24
  static bufferToBigint(buffer) {
14
25
  return this.bufferToHex(buffer).then((hex) => BigInt(`0x${hex}`));
15
26
  }
27
+ static bufferToBigintSync(buffer) {
28
+ return BigInt(`0x${this.bufferToHexSync(buffer)}`);
29
+ }
16
30
  static hexToBuffer(hex) {
17
31
  return BufferHelpersInternals.node_hexToBuffer(hex).catch(() => BufferHelpersInternals.browser_hexToBuffer(hex));
18
32
  }
33
+ static hexToBufferSync(hex) {
34
+ return BufferHelpersInternals.browser_hexToBuffer(hex);
35
+ }
19
36
  static bufferToHex(buffer) {
20
37
  return BufferHelpersInternals.node_bufferToHex(buffer).catch(() => BufferHelpersInternals.browser_bufferToHex(buffer));
21
38
  }
39
+ static bufferToHexSync(buffer) {
40
+ return BufferHelpersInternals.browser_bufferToHex(buffer);
41
+ }
22
42
  static base64ToBuffer(rawBase64) {
23
43
  return Promise.any([
24
44
  z
@@ -33,9 +53,22 @@ export class BufferHelpers {
33
53
  .then((base64url) => BufferHelpersInternals.node_base64ToBuffer(base64url, true).catch(() => BufferHelpersInternals.browser_base64UrlToBuffer(base64url))),
34
54
  ]);
35
55
  }
56
+ static base64ToBufferSync(rawBase64) {
57
+ try {
58
+ const base64 = z.base64().check(z.trim(), z.minLength(1)).parse(rawBase64);
59
+ return BufferHelpersInternals.browser_base64ToBuffer(base64);
60
+ }
61
+ catch {
62
+ const base64url = z.base64url().check(z.trim(), z.minLength(1)).parse(rawBase64);
63
+ return BufferHelpersInternals.browser_base64UrlToBuffer(base64url);
64
+ }
65
+ }
36
66
  static bufferToBase64(buffer, urlSafe) {
37
67
  return BufferHelpersInternals.node_bufferToBase64(buffer, urlSafe).catch(() => BufferHelpersInternals.browser_bufferToBase64(buffer, urlSafe));
38
68
  }
69
+ static bufferToBase64Sync(buffer, urlSafe) {
70
+ return BufferHelpersInternals.browser_bufferToBase64(buffer, urlSafe);
71
+ }
39
72
  static v7OptionsBase = z.object({
40
73
  /**
41
74
  * RFC "timestamp" field
@@ -53,10 +86,9 @@ export class BufferHelpers {
53
86
  static generateUuid7(_options) {
54
87
  return Promise.all([
55
88
  //
56
- import('uuid'),
57
89
  this.v7OptionsBase.parseAsync(_options ?? {}),
58
90
  CryptoHelpers.secretBytes(16),
59
- ]).then(([{ v7: uuidv7 }, options, random]) => {
91
+ ]).then(([options, random]) => {
60
92
  const uuid = uuidv7({ msecs: options.msecs, random, seq: options.seq });
61
93
  const uuidHex = uuid.replaceAll('-', '');
62
94
  return this.hexToBuffer(uuidHex).then((blob) => Promise.all([this.bufferToBase64(blob, false), this.bufferToBase64(blob, true)]).then(([base64, base64url]) => ({
@@ -68,6 +100,22 @@ export class BufferHelpers {
68
100
  })));
69
101
  });
70
102
  }
103
+ static generateUuid7Sync(_options) {
104
+ const options = this.v7OptionsBase.parse(_options ?? {});
105
+ const random = CryptoHelpers.secretBytesSync(16);
106
+ const uuid = uuidv7({ msecs: options.msecs, random, seq: options.seq });
107
+ const uuidHex = uuid.replaceAll('-', '');
108
+ const blob = this.hexToBufferSync(uuidHex);
109
+ const base64 = this.bufferToBase64Sync(blob, false);
110
+ const base64url = this.bufferToBase64Sync(blob, true);
111
+ return {
112
+ utf8: uuid,
113
+ hex: uuidHex,
114
+ blob,
115
+ base64,
116
+ base64url,
117
+ };
118
+ }
71
119
  static generateUuid8(options) {
72
120
  return Promise.all([import('./uuid8.mjs'), CryptoHelpers.secretBytes(16)]).then(([{ v8: uuidv8 }, random]) => {
73
121
  const uuid = uuidv8({
@@ -85,18 +133,35 @@ export class BufferHelpers {
85
133
  })));
86
134
  });
87
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
+ }
88
155
  // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
89
156
  static uuidConvert(input) {
90
157
  if (input) {
91
158
  if (typeof input === 'string') {
92
- return import('zod/v4').then(({ z }) => Promise.any([
93
- //
94
- import('@chainfuse/types/zod').then(({ PrefixedUuidRaw }) => z
95
- .union([
159
+ return Promise.any([
160
+ z
161
+ .pipe(z.union([
96
162
  z.pipe(PrefixedUuidRaw, z.transform((prefixedUtf8) => prefixedUtf8.split('_')[1])),
97
- z.uuid().trim().nonempty().toLowerCase(),
98
- ])
99
- .transform((value) => value)
163
+ z.uuid().check(z.trim(), z.minLength(1), z.toLowerCase()),
164
+ ]), z.transform((value) => value))
100
165
  .parseAsync(input)
101
166
  .then((utf8) => {
102
167
  const hex = utf8.replaceAll('-', '');
@@ -107,13 +172,10 @@ export class BufferHelpers {
107
172
  base64,
108
173
  base64url,
109
174
  })));
110
- })),
175
+ }),
111
176
  z
112
- .string()
113
- .trim()
114
- .toLowerCase()
115
- .length(32)
116
- .refine((value) => import('validator/es/lib/isHexadecimal').then(({ default: isHexadecimal }) => isHexadecimal(value)).catch(() => import('validator').then(({ default: validator }) => validator.isHexadecimal(value))))
177
+ .hex()
178
+ .check(z.trim(), z.toLowerCase(), z.length(32))
117
179
  .parseAsync(input)
118
180
  .then((hex) => this.hexToBuffer(hex).then((blob) => Promise.all([this.bufferToBase64(blob, false), this.bufferToBase64(blob, true)]).then(([base64, base64url]) => ({
119
181
  utf8: `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`,
@@ -125,8 +187,7 @@ export class BufferHelpers {
125
187
  ]).catch(() => Promise.any([
126
188
  z
127
189
  .base64()
128
- .trim()
129
- .nonempty()
190
+ .check(z.trim(), z.minLength(1))
130
191
  .parseAsync(input)
131
192
  .then((base64) => this.base64ToBuffer(base64).then((blob) => Promise.all([this.bufferToHex(blob), this.bufferToBase64(blob, true)]).then(([hex, base64url]) => ({
132
193
  utf8: `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`,
@@ -137,8 +198,7 @@ export class BufferHelpers {
137
198
  })))),
138
199
  z
139
200
  .base64url()
140
- .trim()
141
- .nonempty()
201
+ .check(z.trim(), z.minLength(1))
142
202
  .parseAsync(input)
143
203
  .then((base64url) => this.base64ToBuffer(base64url).then((blob) => Promise.all([this.bufferToHex(blob), this.bufferToBase64(blob, false)]).then(([hex, base64]) => ({
144
204
  utf8: `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`,
@@ -147,7 +207,7 @@ export class BufferHelpers {
147
207
  base64,
148
208
  base64url,
149
209
  })))),
150
- ])));
210
+ ]));
151
211
  }
152
212
  else {
153
213
  return Promise.all([this.bufferToHex(input), this.bufferToBase64(input, false), this.bufferToBase64(input, true)]).then(([hex, base64, base64url]) => ({
@@ -170,14 +230,105 @@ export class BufferHelpers {
170
230
  }))();
171
231
  }
172
232
  // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
233
+ static uuidConvertSync(input) {
234
+ if (input) {
235
+ if (typeof input === 'string') {
236
+ try {
237
+ const utf8 = z
238
+ .pipe(z.union([
239
+ z.pipe(PrefixedUuidRaw, z.transform((prefixedUtf8) => prefixedUtf8.split('_')[1])),
240
+ z.uuid().check(z.trim(), z.minLength(1), z.toLowerCase()),
241
+ ]), z.transform((value) => value))
242
+ .parse(input);
243
+ const hex = utf8.replaceAll('-', '');
244
+ const blob = this.hexToBufferSync(hex);
245
+ const base64 = this.bufferToBase64Sync(blob, false);
246
+ const base64url = this.bufferToBase64Sync(blob, true);
247
+ return {
248
+ utf8,
249
+ hex,
250
+ blob,
251
+ base64,
252
+ base64url,
253
+ };
254
+ }
255
+ catch {
256
+ try {
257
+ const hex = z.hex().check(z.trim(), z.toLowerCase(), z.length(32)).parse(input);
258
+ const blob = this.hexToBufferSync(hex);
259
+ const base64 = this.bufferToBase64Sync(blob, false);
260
+ const base64url = this.bufferToBase64Sync(blob, true);
261
+ return {
262
+ utf8: `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`,
263
+ hex,
264
+ blob,
265
+ base64,
266
+ base64url,
267
+ };
268
+ }
269
+ catch {
270
+ try {
271
+ const base64 = z.base64().check(z.trim(), z.minLength(1)).parse(input);
272
+ const blob = this.base64ToBufferSync(base64);
273
+ const hex = this.bufferToHexSync(blob);
274
+ const base64url = this.bufferToBase64Sync(blob, true);
275
+ return {
276
+ utf8: `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`,
277
+ hex,
278
+ blob,
279
+ base64,
280
+ base64url,
281
+ };
282
+ }
283
+ catch {
284
+ const base64url = z.base64url().check(z.trim(), z.minLength(1)).parse(input);
285
+ const blob = this.base64ToBufferSync(base64url);
286
+ const hex = this.bufferToHexSync(blob);
287
+ const base64 = this.bufferToBase64Sync(blob, false);
288
+ return {
289
+ utf8: `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`,
290
+ hex,
291
+ blob,
292
+ base64,
293
+ base64url,
294
+ };
295
+ }
296
+ }
297
+ }
298
+ }
299
+ else {
300
+ const hex = this.bufferToHexSync(input);
301
+ const base64 = this.bufferToBase64Sync(input, false);
302
+ const base64url = this.bufferToBase64Sync(input, true);
303
+ return {
304
+ utf8: `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`,
305
+ hex,
306
+ // @ts-expect-error `ArrayBufferLike` is actually accepted and fine
307
+ blob: new Uint8Array(input).buffer,
308
+ base64,
309
+ base64url,
310
+ };
311
+ }
312
+ }
313
+ return {
314
+ utf8: undefined,
315
+ hex: undefined,
316
+ blob: undefined,
317
+ base64: undefined,
318
+ base64url: undefined,
319
+ };
320
+ }
321
+ // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
173
322
  static uuidExtractor(input) {
174
323
  return this.uuidConvert(
175
324
  // @ts-expect-error it's the same type
176
- input).then(async ({ utf8, hex: _hex }) => {
177
- const { success: hexSuccess, data: hex } = z.hex().check(z.length(32)).safeParse(_hex);
325
+ input).then(async ({ utf8, hex: _hex }) => z
326
+ .hex()
327
+ .check(z.length(32))
328
+ .safeParseAsync(_hex)
329
+ .then(async ({ success: hexSuccess, data: hex }) => {
178
330
  if (hexSuccess) {
179
- const { success: utf8v7Success } = z.uuid({ version: 'v7' }).safeParse(utf8);
180
- const { success: utf8v8Success } = z.uuid({ version: 'v8' }).safeParse(utf8);
331
+ const [{ success: utf8v7Success }, { success: utf8v8Success }] = await Promise.all([z.uuid({ version: 'v7' }).safeParseAsync(utf8), z.uuid({ version: 'v8' }).safeParseAsync(utf8)]);
181
332
  if (utf8v7Success || utf8v8Success) {
182
333
  if (utf8v8Success) {
183
334
  const suffix_hex = hex.substring(13, 16);
@@ -208,6 +359,46 @@ export class BufferHelpers {
208
359
  else {
209
360
  throw new Error('Invalid UUID provided');
210
361
  }
211
- });
362
+ }));
363
+ }
364
+ // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
365
+ static uuidExtractorSync(input) {
366
+ const { utf8, hex: _hex } = this.uuidConvertSync(
367
+ // @ts-expect-error it's the same type
368
+ input);
369
+ const { success: hexSuccess, data: hex } = z.hex().check(z.length(32)).safeParse(_hex);
370
+ if (hexSuccess) {
371
+ const { success: utf8v7Success } = z.uuid({ version: 'v7' }).safeParse(utf8);
372
+ const { success: utf8v8Success } = z.uuid({ version: 'v8' }).safeParse(utf8);
373
+ if (utf8v7Success || utf8v8Success) {
374
+ if (utf8v8Success) {
375
+ const suffix_hex = hex.substring(13, 16);
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
+ }
395
+ }
396
+ else {
397
+ throw new Error('Unsupported UUID version provided');
398
+ }
399
+ }
400
+ else {
401
+ throw new Error('Invalid UUID provided');
402
+ }
212
403
  }
213
404
  }
package/dist/crypto.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  export declare class CryptoHelpers {
2
2
  static secretBytes(byteSize: number): Promise<Uint8Array<ArrayBufferLike>>;
3
+ static secretBytesSync(byteSize: number): Uint8Array<ArrayBufferLike>;
3
4
  static base16secret(secretLength: number): Promise<string>;
4
5
  static base62secret(secretLength: number): Promise<string>;
5
6
  static getHash(algorithm: 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512', input: string | ArrayBufferLike): Promise<string>;
package/dist/crypto.mjs CHANGED
@@ -4,6 +4,9 @@ export class CryptoHelpers {
4
4
  static secretBytes(byteSize) {
5
5
  return CryptoHelpersInternals.node_secretBytes(byteSize).catch(() => CryptoHelpersInternals.browser_secretBytes(byteSize));
6
6
  }
7
+ static secretBytesSync(byteSize) {
8
+ return CryptoHelpersInternals.browser_secretBytes(byteSize);
9
+ }
7
10
  static base16secret(secretLength) {
8
11
  return this.secretBytes(Math.ceil(secretLength / 2))
9
12
  .then((bytes) => BufferHelpers.bufferToHex(bytes.buffer))
package/dist/db.d.mts CHANGED
@@ -34,8 +34,8 @@ export declare class SQLCache<C extends CacheStorageLike> extends DrizzleCache {
34
34
  cacheTTL: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
35
35
  cachePurge: z.ZodMiniDefault<z.ZodMiniUnion<readonly [z.ZodMiniBoolean<boolean>, z.ZodMiniDate<Date>]>>;
36
36
  strategy: z.ZodMiniDefault<z.ZodMiniEnum<{
37
- all: "all";
38
37
  explicit: "explicit";
38
+ all: "all";
39
39
  }>>;
40
40
  }, z.core.$strip>;
41
41
  /**
@@ -56,7 +56,7 @@ export declare class SQLCache<C extends CacheStorageLike> extends DrizzleCache {
56
56
  * - `all`: All queries are cached globally.
57
57
  * @default 'explicit'
58
58
  */
59
- strategy(): "all" | "explicit";
59
+ strategy(): "explicit" | "all";
60
60
  /**
61
61
  * Generates a cache key as a `Request` object based on the provided tag or key.
62
62
  *
@@ -1,6 +1,6 @@
1
1
  import type { ExecutionContext } from '@cloudflare/workers-types/experimental';
2
2
  import { CDN, type RESTOptions } from '@discordjs/rest';
3
- import type { z } from 'zod/v3';
3
+ import * as z from 'zod/mini';
4
4
  export declare class DiscordHelpers {
5
5
  /**
6
6
  * Discord Epoch, the first second of 2015 or 1420070400000
@@ -17,23 +17,14 @@ export declare class DiscordHelpers {
17
17
  * @link https://discord.com/developers/docs/reference#snowflakes-snowflake-id-format-structure-left-to-right
18
18
  */
19
19
  static discordSnowflakeToDate(snowflakeRaw?: bigint | string): Date;
20
- static disordRestLogging(): Promise<z.ZodDefault<z.ZodObject<{
21
- level: z.ZodDefault<z.ZodNumber>;
22
- error: z.ZodDefault<z.ZodNumber>;
23
- color: z.ZodDefault<z.ZodBoolean>;
24
- custom: z.ZodOptional<z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnion<[z.ZodVoid, z.ZodPromise<z.ZodVoid>]>>>;
25
- }, "strip", z.ZodTypeAny, {
26
- error: number;
27
- level: number;
28
- color: boolean;
29
- custom?: ((...args: unknown[]) => void | Promise<void>) | undefined;
30
- }, {
31
- custom?: ((...args: unknown[]) => void | Promise<void>) | undefined;
32
- error?: number | undefined;
33
- level?: number | undefined;
34
- color?: boolean | undefined;
35
- }>>>;
36
- static discordRest(apiKey: string, logging: z.input<Awaited<ReturnType<typeof DiscordHelpers.disordRestLogging>>>, cacheTtl?: number, forceCache?: boolean, executionContext?: ExecutionContext, restOptions?: Partial<Omit<RESTOptions, 'agent' | 'authPrefix' | 'makeRequest'>>): Promise<import("@discordjs/rest").REST>;
20
+ static customLogging: z.ZodMiniFunction<z.ZodMiniTuple<readonly [z.ZodMiniAny], z.ZodMiniAny>, z.ZodMiniUnion<readonly [z.ZodMiniPromise<z.ZodMiniVoid>, z.ZodMiniVoid]>>;
21
+ static disordRestLogging: z.ZodMiniDefault<z.ZodMiniObject<{
22
+ level: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
23
+ error: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
24
+ color: z.ZodMiniDefault<z.ZodMiniBoolean<boolean>>;
25
+ custom: z.ZodMiniOptional<z.ZodMiniPipe<z.ZodMiniFunction<z.ZodMiniTuple<readonly [z.ZodMiniAny], z.ZodMiniAny>, z.ZodMiniUnion<readonly [z.ZodMiniPromise<z.ZodMiniVoid>, z.ZodMiniVoid]>>, z.ZodMiniTransform<(args_0: any, ...args: any[]) => void | Promise<void>, z.core.$InferOuterFunctionType<z.ZodMiniTuple<readonly [z.ZodMiniAny], z.ZodMiniAny>, z.ZodMiniUnion<readonly [z.ZodMiniPromise<z.ZodMiniVoid>, z.ZodMiniVoid]>>>>>;
26
+ }, z.core.$strip>>;
27
+ static discordRest(apiKey: string, _logging: z.input<typeof this.disordRestLogging>, cacheTtl?: number, forceCache?: boolean, executionContext?: ExecutionContext, restOptions?: Partial<Omit<RESTOptions, 'agent' | 'authPrefix' | 'makeRequest'>>): Promise<import("@discordjs/rest").REST>;
37
28
  static userIcon(userId: bigint | string, userIconHash?: Parameters<CDN['avatar']>[1] | null, guildId?: bigint | string, memberIconHash?: Parameters<CDN['avatar']>[1] | null, options?: Parameters<CDN['avatar']>[2]): string;
38
29
  static guildIcon(guildId: bigint | string, iconHash: Parameters<CDN['icon']>[1], options?: Parameters<CDN['icon']>[2]): string;
39
30
  }
package/dist/discord.mjs CHANGED
@@ -1,4 +1,7 @@
1
1
  import { CDN } from '@discordjs/rest';
2
+ import * as z from 'zod/mini';
3
+ import { CryptoHelpers } from './crypto.mjs';
4
+ import { Methods, NetHelpers } from './net.mjs';
2
5
  export class DiscordHelpers {
3
6
  /**
4
7
  * Discord Epoch, the first second of 2015 or 1420070400000
@@ -28,31 +31,28 @@ export class DiscordHelpers {
28
31
  const snowflake = BigInt(snowflakeRaw);
29
32
  return new Date(Number((snowflake >> BigInt(22)) + this.discordEpoch));
30
33
  }
31
- static disordRestLogging() {
32
- return import('zod/v3').then(({ z: z3 }) => z3
33
- .object({
34
- level: z3.coerce.number().int().min(0).max(4).default(0),
35
- error: z3.coerce.number().int().min(0).max(4).default(1),
36
- color: z3.boolean().default(true),
37
- custom: z3
38
- .function()
39
- .args()
40
- .returns(z3.union([z3.void(), z3.promise(z3.void())]))
41
- .optional(),
42
- })
43
- .default({}));
44
- }
45
- static discordRest(apiKey, logging, cacheTtl = 24 * 60 * 60, forceCache = false, executionContext, restOptions) {
34
+ static customLogging = z.function({
35
+ input: z.tuple([z.any()], z.any()),
36
+ output: z.union([z.promise(z.void()), z.void()]),
37
+ });
38
+ static disordRestLogging = z._default(z.object({
39
+ level: z._default(z.int().check(z.minimum(0), z.maximum(3)), 0),
40
+ error: z._default(z.int().check(z.minimum(0), z.maximum(3)), 1),
41
+ color: z._default(z.boolean(), true),
42
+ custom: z.optional(z.pipe(this.customLogging,
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ z.transform((fn) => fn))),
45
+ }), {
46
+ level: 0,
47
+ error: 1,
48
+ color: true,
49
+ });
50
+ static discordRest(apiKey, _logging, cacheTtl = 24 * 60 * 60, forceCache = false, executionContext, restOptions) {
46
51
  return Promise.all([import('@discordjs/rest'), import('./crypto.mjs').then(({ CryptoHelpers }) => CryptoHelpers.base62secret(8))]).then(([{ REST }, potentialId]) => new REST({
47
52
  ...restOptions,
48
53
  agent: null,
49
54
  authPrefix: 'Bot',
50
- makeRequest: (url, rawInit) => Promise.all([
51
- //
52
- DiscordHelpers.disordRestLogging().then((parser) => parser.parseAsync(logging)),
53
- import('./net.mjs'),
54
- import('./crypto.mjs'),
55
- ]).then(async ([logging, { NetHelpers, Methods }, { CryptoHelpers }]) => {
55
+ makeRequest: (url, rawInit) => DiscordHelpers.disordRestLogging.parseAsync(_logging).then(async (logging) => {
56
56
  // Extra safety to make sure the string really is a URL
57
57
  const info = new URL(url);
58
58
  // CF's implementation of `RequestInit` is functionally the same as w3c `RequestInit` but TS doesn't know that
@@ -65,15 +65,27 @@ export class DiscordHelpers {
65
65
  error: logging.error >= 2 ? logging.error - 1 : logging.error,
66
66
  ...('color' in logging && { color: logging.color }),
67
67
  ...((logging.level > 0 || logging.error > 0) && {
68
- custom: async (...args) => {
68
+ custom: this.customLogging.implementAsync(async (args_0, ...args_x) => {
69
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
70
+ const args = [args_0, ...args_x];
69
71
  const [, id, , url] = args;
70
72
  const customUrl = new URL(url);
71
73
  if ('custom' in logging && logging.custom) {
74
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
75
+ const [argsFirst, ...argsRest] = args.slice(0, -1);
72
76
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
73
- return logging.custom(...args);
77
+ return logging.custom(argsFirst, ...argsRest);
74
78
  }
75
79
  else {
76
- await Promise.all([import('strip-ansi'), import('chalk').then(({ Chalk }) => new Chalk({ level: 2 })), import("./index.mjs")]).then(([{ default: stripAnsi }, chalk, { Helpers }]) => {
80
+ await Promise.all([
81
+ // Try the new native one
82
+ import('node:util')
83
+ .then(({ stripVTControlCharacters }) => stripVTControlCharacters)
84
+ // For web or unavailable node in general
85
+ .catch(() => import('strip-ansi').then(({ default: stripAnsi }) => stripAnsi)),
86
+ import('chalk').then(({ Chalk }) => new Chalk({ level: 2 })),
87
+ import("./index.mjs"),
88
+ ]).then(([ansiStripper, chalk, { Helpers }]) => {
77
89
  if (logging.level > 0) {
78
90
  console.info('Discord Rest',
79
91
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
@@ -83,7 +95,7 @@ export class DiscordHelpers {
83
95
  .map((value) => (value instanceof Date && !isNaN(value.getTime()) ? value.toISOString() : value))
84
96
  // Wrap id in brackets
85
97
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
86
- .map((value) => (value === id ? chalk.rgb(...Helpers.uniqueIdColor(stripAnsi(id)))(`[${stripAnsi(id)}]`) : value))
98
+ .map((value) => (value === id ? chalk.rgb(...Helpers.uniqueIdColor(ansiStripper(id)))(`[${ansiStripper(id)}]`) : value))
87
99
  // Strip out redundant parts of url
88
100
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
89
101
  .map((value) => (value === url ? `${customUrl.pathname}${customUrl.search}${customUrl.hash}` : value)));
@@ -97,14 +109,14 @@ export class DiscordHelpers {
97
109
  .map((value) => (value instanceof Date && !isNaN(value.getTime()) ? value.toISOString() : value))
98
110
  // Wrap id in brackets
99
111
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
100
- .map((value) => (value === id ? chalk.rgb(...Helpers.uniqueIdColor(stripAnsi(id)))(`[${stripAnsi(id)}]`) : value))
112
+ .map((value) => (value === id ? chalk.rgb(...Helpers.uniqueIdColor(ansiStripper(id)))(`[${ansiStripper(id)}]`) : value))
101
113
  // Strip out redundant parts of url
102
114
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
103
115
  .map((value) => (value === url ? `${customUrl.pathname}${customUrl.search}${customUrl.hash}` : value)));
104
116
  }
105
117
  });
106
118
  }
107
- },
119
+ }),
108
120
  }),
109
121
  },
110
122
  };
@@ -132,8 +144,10 @@ export class DiscordHelpers {
132
144
  });
133
145
  }
134
146
  if ('custom' in logging && logging.custom) {
147
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
148
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
135
149
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
136
- await logging.custom(...loggingItems);
150
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
137
151
  }
138
152
  else {
139
153
  console.info(
@@ -170,8 +184,10 @@ export class DiscordHelpers {
170
184
  });
171
185
  }
172
186
  if ('custom' in logging && logging.custom) {
187
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
188
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
173
189
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
174
- await logging.custom(...loggingItems);
190
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
175
191
  }
176
192
  else {
177
193
  console.info(
@@ -208,8 +224,10 @@ export class DiscordHelpers {
208
224
  });
209
225
  }
210
226
  if ('custom' in logging && logging.custom) {
227
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
228
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
211
229
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
212
- await logging.custom(...loggingItems);
230
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
213
231
  }
214
232
  else {
215
233
  console.info(
@@ -236,8 +254,10 @@ export class DiscordHelpers {
236
254
  });
237
255
  }
238
256
  if ('custom' in logging && logging.custom) {
257
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
258
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
239
259
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
240
- await logging.custom(...loggingItems);
260
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
241
261
  }
242
262
  else {
243
263
  console.info(
@@ -268,8 +288,10 @@ export class DiscordHelpers {
268
288
  });
269
289
  }
270
290
  if ('custom' in logging && logging.custom) {
291
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
292
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
271
293
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
272
- await logging.custom(...loggingItems);
294
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
273
295
  }
274
296
  else {
275
297
  console.info(
@@ -296,8 +318,10 @@ export class DiscordHelpers {
296
318
  });
297
319
  }
298
320
  if ('custom' in logging && logging.custom) {
321
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
322
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
299
323
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
300
- await logging.custom(...loggingItems);
324
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
301
325
  }
302
326
  else {
303
327
  console.info(
@@ -330,8 +354,10 @@ export class DiscordHelpers {
330
354
  });
331
355
  }
332
356
  if ('custom' in logging && logging.custom) {
357
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
358
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
333
359
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
334
- await logging.custom(...loggingItems);
360
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
335
361
  }
336
362
  else {
337
363
  console.info(
@@ -358,8 +384,10 @@ export class DiscordHelpers {
358
384
  });
359
385
  }
360
386
  if ('custom' in logging && logging.custom) {
387
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
388
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
361
389
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
362
- await logging.custom(...loggingItems);
390
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
363
391
  }
364
392
  else {
365
393
  console.info(
@@ -390,8 +418,10 @@ export class DiscordHelpers {
390
418
  });
391
419
  }
392
420
  if ('custom' in logging && logging.custom) {
421
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
422
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
393
423
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
394
- await logging.custom(...loggingItems);
424
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
395
425
  }
396
426
  else {
397
427
  console.info(
@@ -418,8 +448,10 @@ export class DiscordHelpers {
418
448
  });
419
449
  }
420
450
  if ('custom' in logging && logging.custom) {
451
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
452
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
421
453
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
422
- await logging.custom(...loggingItems);
454
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
423
455
  }
424
456
  else {
425
457
  console.info(
@@ -453,8 +485,10 @@ export class DiscordHelpers {
453
485
  });
454
486
  }
455
487
  if ('custom' in logging && logging.custom) {
488
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
489
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
456
490
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
457
- await logging.custom(...loggingItems);
491
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
458
492
  }
459
493
  else {
460
494
  console.info(
@@ -482,8 +516,10 @@ export class DiscordHelpers {
482
516
  });
483
517
  }
484
518
  if ('custom' in logging && logging.custom) {
519
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
520
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
485
521
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
486
- await logging.custom(...loggingItems);
522
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
487
523
  }
488
524
  else {
489
525
  console.info(
@@ -512,8 +548,10 @@ export class DiscordHelpers {
512
548
  });
513
549
  }
514
550
  if ('custom' in logging && logging.custom) {
551
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
552
+ const [loggingItemsFirst, ...loggingItemsRest] = loggingItems;
515
553
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
516
- await logging.custom(...loggingItems);
554
+ await logging.custom(loggingItemsFirst, ...loggingItemsRest);
517
555
  }
518
556
  else {
519
557
  console.info(
package/dist/net.d.mts CHANGED
@@ -67,9 +67,9 @@ export declare class NetHelpers {
67
67
  * @link https://blog.cloudflare.com/introducing-polish-automatic-image-optimizati/
68
68
  */
69
69
  polish: z.ZodMiniOptional<z.ZodMiniEnum<{
70
- off: "off";
71
70
  lossy: "lossy";
72
71
  lossless: "lossless";
72
+ off: "off";
73
73
  }>>;
74
74
  /**
75
75
  * Whether ScrapeShield should be enabled for this request, if otherwise configured for this zone.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chainfuse/helpers",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "",
5
5
  "author": "ChainFuse",
6
6
  "homepage": "https://github.com/ChainFuse/packages/tree/main/packages/helpers#readme",
@@ -80,18 +80,18 @@
80
80
  },
81
81
  "prettier": "@demosjarco/prettier-config",
82
82
  "dependencies": {
83
- "@chainfuse/types": "^3.0.0",
83
+ "@chainfuse/types": "^3.0.5",
84
84
  "@discordjs/rest": "^2.6.0",
85
85
  "chalk": "^5.6.2",
86
86
  "cloudflare": "^5.0.0",
87
87
  "drizzle-orm": "^0.44.5",
88
88
  "strip-ansi": "^7.1.2",
89
89
  "uuid": "^13.0.0",
90
- "zod": "^4.1.5"
90
+ "zod": "^4.1.8"
91
91
  },
92
92
  "devDependencies": {
93
- "@cloudflare/workers-types": "^4.20250909.0",
93
+ "@cloudflare/workers-types": "^4.20250910.0",
94
94
  "@types/node": "^22.18.1"
95
95
  },
96
- "gitHead": "a53477407bf7365156b75df30b94c9ad5d58bb53"
96
+ "gitHead": "c20b4ff8bb19d397282f183966fb7e45a6d9942d"
97
97
  }