@chainfuse/helpers 0.4.1 → 0.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 CHANGED
@@ -1,4 +1,4 @@
1
- [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/ChainFuse/packages/badge)](https://securityscorecards.dev/viewer/?uri=github.com/ChainFuse/packages)[![Socket Badge](https://socket.dev/api/badge/npm/package/@chainfuse/helpers)](https://socket.dev/npm/package/@chainFuse/helpers)
1
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/ChainFuse/packages/badge)](https://securityscorecards.dev/viewer/?uri=github.com/ChainFuse/packages)[![Socket Badge](https://socket.dev/api/badge/npm/package/@chainfuse/helpers)](https://socket.dev/npm/package/@chainfuse/helpers)
2
2
 
3
3
  ![NPM Downloads](https://img.shields.io/npm/dw/@chainfuse/helpers)![npm bundle size](https://img.shields.io/bundlephobia/min/@chainfuse/helpers)![NPM Unpacked Size](https://img.shields.io/npm/unpacked-size/@chainfuse/helpers)
4
4
 
package/dist/crypto.d.mts CHANGED
@@ -1,13 +1,7 @@
1
1
  export declare class CryptoHelpers {
2
- static secretBytes(byteSize: number): Promise<Uint8Array<ArrayBuffer> | Uint8Array<ArrayBuffer | SharedArrayBuffer>>;
3
- /**
4
- * @yields secret length = (`byteSize` * Math.log2(16)) / 8
5
- */
6
- static base16secret(byteSize: number): Promise<string>;
7
- /**
8
- * @yields secret length = (`byteSize` * Math.log2(62)) / 8
9
- */
10
- static base62secret(byteSize: number): Promise<string>;
2
+ static secretBytes(byteSize: number): Promise<Uint8Array<ArrayBuffer | SharedArrayBuffer> | Uint8Array<ArrayBuffer>>;
3
+ static base16secret(secretLength: number): Promise<string>;
4
+ static base62secret(secretLength: number): Promise<string>;
11
5
  static getHash(algorithm: 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512', input: string | ArrayBufferLike): Promise<string>;
12
6
  /**
13
7
  * @returns Fully formatted (double quote encapsulated) `ETag` header value
package/dist/crypto.mjs CHANGED
@@ -12,20 +12,14 @@ export class CryptoHelpers {
12
12
  return randomBytes;
13
13
  });
14
14
  }
15
- /**
16
- * @yields secret length = (`byteSize` * Math.log2(16)) / 8
17
- */
18
- static base16secret(byteSize) {
19
- return this.secretBytes(byteSize).then((bytes) => BufferHelpers.bufferToHex(bytes.buffer));
15
+ static base16secret(secretLength) {
16
+ return this.secretBytes(secretLength / 2).then((bytes) => BufferHelpers.bufferToHex(bytes.buffer));
20
17
  }
21
- /**
22
- * @yields secret length = (`byteSize` * Math.log2(62)) / 8
23
- */
24
- static base62secret(byteSize) {
18
+ static base62secret(secretLength) {
25
19
  const LOWER_CHAR_SET = 'abcdefghijklmnopqrstuvwxyz';
26
20
  const NUMBER_CHAR_SET = '0123456789';
27
21
  const CHAR_SET = `${NUMBER_CHAR_SET}${LOWER_CHAR_SET}${LOWER_CHAR_SET.toUpperCase()}`;
28
- return this.secretBytes(byteSize).then((randomBytes) => {
22
+ return this.secretBytes(secretLength).then((randomBytes) => {
29
23
  /**
30
24
  * @link https://jsbm.dev/x1F2ITy7RU8T2
31
25
  */
package/dist/dns.d.mts ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Supported parameters for Cloudflare's 1.1.1.1 DNS over HTTPS API
3
+ */
4
+ export interface DohBodyRequest {
5
+ /** Query name (required) */
6
+ name: string;
7
+ /** Query type - either a numeric value or text. Default is 'A' */
8
+ type?: string | number;
9
+ /**
10
+ * DO bit - whether the client wants DNSSEC data.
11
+ * Either empty or one of `0`, `false`, `1`, or `true`. Default is `false`
12
+ */
13
+ do?: string | number | boolean;
14
+ /**
15
+ * CD bit - disable validation.
16
+ * Either empty or one of `0`, `false`, `1`, or `true`. Default is `false`
17
+ */
18
+ cd?: string | number | boolean;
19
+ }
20
+ /**
21
+ * A record structure with name, type, TTL, and data.
22
+ */
23
+ interface Record {
24
+ /** The record owner */
25
+ name: string;
26
+ /** The type of DNS record. Defined here: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4 */
27
+ type: number;
28
+ /** The number of seconds the answer can be stored in cache before it is considered stale */
29
+ TTL: number;
30
+ /** The value of the DNS record for the given name and type. The data will be in text for standardized record types and in hex for unknown types */
31
+ data: string;
32
+ }
33
+ /**
34
+ * A successful DNS response from Cloudflare's 1.1.1.1 DNS over HTTPS API
35
+ */
36
+ export interface DohSuccessfulResponse {
37
+ /** The Response Code of the DNS Query. Defined here: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 */
38
+ Status: number;
39
+ /** True if the truncated bit was set. This happens when the DNS answer is larger than a single UDP or TCP packet */
40
+ TC: boolean;
41
+ /** True if the Recursive Desired bit was set. This is always set to true for Cloudflare DNS over HTTPS */
42
+ RD: boolean;
43
+ /** True if the Recursion Available bit was set. This is always set to true for Cloudflare DNS over HTTPS */
44
+ RA: boolean;
45
+ /** True if every record in the answer was verified with DNSSEC */
46
+ AD: boolean;
47
+ /** True if the client asked to disable DNSSEC validation. In this case, Cloudflare will still fetch the DNSSEC-related records, but it will not attempt to validate the records */
48
+ CD: boolean;
49
+ /** The record name requested */
50
+ Question: Record[];
51
+ /** The answer record */
52
+ Answer?: Record[];
53
+ /** The authority record */
54
+ Authority: Record[];
55
+ /** The additional record */
56
+ Additional: Record[];
57
+ /** List of EDE messages. Refer to Extended DNS error codes for more information */
58
+ Comment?: string[];
59
+ }
60
+ /**
61
+ * An error response from Cloudflare's 1.1.1.1 DNS over HTTPS API
62
+ */
63
+ export interface DohErrorResponse {
64
+ /** An explanation of the error that occurred */
65
+ error: string;
66
+ }
67
+ export declare class DnsHelpers {
68
+ private nameserver_url;
69
+ constructor(nameserver_url: string | URL);
70
+ query(qName: string, qType?: string | number, qDo?: string | number | boolean, qCd?: string | number | boolean, timeout?: number): Promise<DohSuccessfulResponse | DohErrorResponse>;
71
+ private makeGetQuery;
72
+ private sendDohMsg;
73
+ }
74
+ export {};
package/dist/dns.mjs ADDED
@@ -0,0 +1,46 @@
1
+ export class DnsHelpers {
2
+ nameserver_url;
3
+ constructor(nameserver_url) {
4
+ this.nameserver_url = new URL(nameserver_url);
5
+ }
6
+ query(qName, qType = 'A', qDo = false, qCd = false, timeout = 10 * 1000) {
7
+ return new Promise((resolve, reject) => {
8
+ this.sendDohMsg(timeout, this.makeGetQuery(this.nameserver_url, qName, qType, qDo, qCd))
9
+ .then((response) => {
10
+ if (response.ok) {
11
+ response.json().then(resolve).catch(reject);
12
+ }
13
+ else {
14
+ // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
15
+ reject(response.status);
16
+ }
17
+ })
18
+ .catch(reject);
19
+ });
20
+ }
21
+ makeGetQuery(url, qName, qType = 'A', qDo = false, qCd = false) {
22
+ url.searchParams.set('name', qName);
23
+ url.searchParams.set('type', qType.toString());
24
+ url.searchParams.set('do', qDo.toString());
25
+ url.searchParams.set('cd', qCd.toString());
26
+ return url;
27
+ }
28
+ async sendDohMsg(timeout = 10 * 1000, url = this.nameserver_url) {
29
+ const controller = new AbortController();
30
+ const timer = setTimeout(() => controller.abort(), timeout);
31
+ const response = await fetch(url, {
32
+ method: 'GET',
33
+ headers: {
34
+ Accept: 'application/dns-json',
35
+ },
36
+ signal: controller.signal,
37
+ });
38
+ clearTimeout(timer);
39
+ if (response.ok || response.status === 304) {
40
+ return response;
41
+ }
42
+ else {
43
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
44
+ }
45
+ }
46
+ }
package/dist/index.d.mts CHANGED
@@ -1,8 +1,17 @@
1
+ import type { Chalk } from 'chalk';
1
2
  export * from './buffers.mjs';
2
3
  export * from './crypto.mjs';
3
4
  export * from './discord.mjs';
5
+ export * from './dns.mjs';
4
6
  export * from './net.mjs';
5
7
  export declare class Helpers {
8
+ /**
9
+ * Generates a unique RGB color based unique to the provided string ID. The RGB values are clamped to a range that ensures the resulting color is legible
10
+ *
11
+ * @param id - The input string used to generate the unique color.
12
+ * @returns A tuple containing the RGB values [r, g, b].
13
+ */
14
+ static uniqueIdColor(id: string): Parameters<InstanceType<typeof Chalk>['rgb']>;
6
15
  static precisionFloat(input: string): number;
7
16
  /**
8
17
  * A wrapper around `Promise.allSettled()` that filters and returns only the fulfilled results. This method behaves like `Promise.allSettled()` where one promise failing doesn't stop others.
@@ -12,4 +21,5 @@ export declare class Helpers {
12
21
  * @returns A promise that resolves to an array of fulfilled values from the input promises.
13
22
  */
14
23
  static getFulfilledResults<T extends unknown>(promises: PromiseLike<T>[]): Promise<Awaited<T>[]>;
24
+ static areArraysEqual<T>(array1: T[], array2: T[]): boolean;
15
25
  }
package/dist/index.mjs CHANGED
@@ -1,8 +1,34 @@
1
1
  export * from './buffers.mjs';
2
2
  export * from './crypto.mjs';
3
3
  export * from './discord.mjs';
4
+ export * from './dns.mjs';
4
5
  export * from './net.mjs';
5
6
  export class Helpers {
7
+ /**
8
+ * Generates a unique RGB color based unique to the provided string ID. The RGB values are clamped to a range that ensures the resulting color is legible
9
+ *
10
+ * @param id - The input string used to generate the unique color.
11
+ * @returns A tuple containing the RGB values [r, g, b].
12
+ */
13
+ static uniqueIdColor(id) {
14
+ // Hash the string to a numeric value
15
+ let hash = 0;
16
+ for (let i = 0; i < id.length; i++) {
17
+ const char = id.charCodeAt(i);
18
+ hash = (hash << 5) - hash + char;
19
+ hash |= 0; // Convert to 32-bit integer
20
+ }
21
+ // Convert the hash to RGB components
22
+ let r = (hash & 0xff0000) >> 16; // Extract red
23
+ let g = (hash & 0x00ff00) >> 8; // Extract green
24
+ let b = hash & 0x0000ff; // Extract blue
25
+ // Clamp RGB values to a more legible range (e.g., 64-200)
26
+ const clamp = (value) => Math.max(100, Math.min(222, value));
27
+ r = clamp(r);
28
+ g = clamp(g);
29
+ b = clamp(b);
30
+ return [r, g, b];
31
+ }
6
32
  static precisionFloat(input) {
7
33
  if (!input.includes('.')) {
8
34
  // No decimal point means it's an integer, just return as a float
@@ -29,4 +55,22 @@ export class Helpers {
29
55
  static getFulfilledResults(promises) {
30
56
  return Promise.allSettled(promises).then((results) => results.filter((result) => result.status === 'fulfilled').map((result) => result.value));
31
57
  }
58
+ static areArraysEqual(array1, array2) {
59
+ // Quick length check for early exit
60
+ if (array1.length !== array2.length) {
61
+ return false;
62
+ }
63
+ // Use Set for efficient comparison if arrays are of primitive types
64
+ const set1 = new Set(array1);
65
+ const set2 = new Set(array2);
66
+ if (set1.size !== set2.size) {
67
+ return false;
68
+ }
69
+ for (const item of set1) {
70
+ if (!set2.has(item)) {
71
+ return false;
72
+ }
73
+ }
74
+ return true;
75
+ }
32
76
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chainfuse/helpers",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "",
5
5
  "author": "ChainFuse",
6
6
  "homepage": "https://github.com/ChainFuse/packages/tree/main/packages/helpers#readme",
@@ -30,8 +30,7 @@
30
30
  "build": "tsc",
31
31
  "build:clean": "npm run build -- --build --clean && npm run build",
32
32
  "pretest": "tsc --project tsconfig.tests.json",
33
- "test": "node --enable-source-maps --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout",
34
- "test:local": "npm run test"
33
+ "test": "node --enable-source-maps --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout"
35
34
  },
36
35
  "type": "module",
37
36
  "bugs": {
@@ -49,14 +48,14 @@
49
48
  },
50
49
  "prettier": "@demosjarco/prettier-config",
51
50
  "dependencies": {
52
- "@discordjs/rest": "^2.4.0",
53
- "chalk": "^5.3.0",
51
+ "@discordjs/rest": "^2.4.2",
52
+ "chalk": "^5.4.1",
54
53
  "cloudflare": "^3.5.0",
55
- "uuid": "^11.0.3"
54
+ "uuid": "^11.0.4"
56
55
  },
57
56
  "devDependencies": {
58
- "@chainfuse/types": "^1.3.0",
59
- "@types/node": "^22.10.0"
57
+ "@chainfuse/types": "^1.4.1",
58
+ "@types/node": "^22.10.5"
60
59
  },
61
- "gitHead": "ea93b05607f7e9687526434591370bfad1ad8605"
60
+ "gitHead": "75406cd04aedccc51d9972a79dfbbd5ce7fe6945"
62
61
  }