@arcjet/stable-hash 1.0.0-beta.9 → 1.1.0-rc

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
@@ -21,10 +21,25 @@
21
21
  - [npm package (`@arcjet/stable-hash`)](https://www.npmjs.com/package/@arcjet/stable-hash)
22
22
  - [GitHub source code (`stable-hash/` in `arcjet/arcjet-js`)](https://github.com/arcjet/arcjet-js/tree/main/stable-hash)
23
23
 
24
- ## Installation
24
+ ## What is this?
25
25
 
26
- ```shell
27
- npm install -S @arcjet/stable-hash
26
+ This is an internal utility to help us create stable hashes.
27
+ It’s super minimal and matches similar internal code in other languages.
28
+ This exists to make sure things work the same across languages.
29
+
30
+ ## When should I use this?
31
+
32
+ This is an internal Arcjet package not designed for public use.
33
+ See our [_Get started_ guide][arcjet-get-started] for how to use Arcjet in your
34
+ application.
35
+
36
+ ## Install
37
+
38
+ This package is ESM only.
39
+ Install with npm in Node.js:
40
+
41
+ ```sh
42
+ npm install @arcjet/stable-hash
28
43
  ```
29
44
 
30
45
  ## Example
@@ -32,18 +47,28 @@ npm install -S @arcjet/stable-hash
32
47
  ```ts
33
48
  import * as hasher from "@arcjet/stable-hash";
34
49
 
35
- const id = hasher.hash(
50
+ const id = await hasher.hash(
36
51
  hasher.string("type", "EMAIL"),
37
52
  hasher.uint32("version", 0),
38
53
  hasher.string("mode", "LIVE"),
39
54
  hasher.stringSliceOrdered("allow", []),
40
55
  hasher.stringSliceOrdered("deny", []),
41
56
  );
57
+
58
+ console.log(id);
59
+ // => 49573b7df8d854c2cd5d8a755a4c03aff4014493a41b963490861a279ad675b2
42
60
  ```
43
61
 
44
62
  ## License
45
63
 
46
- Licensed under the [Apache License, Version 2.0][apache-license].
64
+ [Apache License, Version 2.0][apache-license] © [Arcjet Labs, Inc.][arcjet]
65
+
66
+ Derivative work based on [`feross/buffer`][github-buffer] licensed under
67
+ [MIT][github-buffer-license] © Feross Aboukhadijeh and contributors.
68
+ Our work picks its internal hex encoding logic adjusted for our use.
47
69
 
48
- [arcjet]: https://arcjet.com
49
70
  [apache-license]: http://www.apache.org/licenses/LICENSE-2.0
71
+ [arcjet]: https://arcjet.com
72
+ [arcjet-get-started]: https://docs.arcjet.com/get-started
73
+ [github-buffer-license]: https://github.com/feross/buffer/blob/5857e295f4d37e3ad02c3abcbf7e8e5ef51f3be6/LICENSE
74
+ [github-buffer]: https://github.com/feross/buffer/tree/5857e295f4d37e3ad02c3abcbf7e8e5ef51f3be6
package/edge-light.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export * from "./hasher.js";
2
- export declare const hash: (...hashers: import("./hasher.js").FieldHasher[]) => Promise<string>;
2
+ export declare const hash: (...hashers: ReadonlyArray<import("./hasher.js").FieldHasher>) => Promise<string>;
package/edge-light.js CHANGED
@@ -1,6 +1,10 @@
1
1
  import { makeHasher } from './hasher.js';
2
2
  export { bool, string, stringSliceOrdered, uint32 } from './hasher.js';
3
3
 
4
+ // @ts-ignore: this value exists in Edge Light, as it implements the DOM type for it.
5
+ // See <https://vercel.com/docs/functions/runtimes/edge#crypto-apis>.
6
+ // This can be verified by adding `/// <reference lib="dom" />` above.
7
+ // But we don’t want to load the entire DOM types or edge-light-specific types.
4
8
  const hash = makeHasher(crypto.subtle);
5
9
 
6
10
  export { hash, makeHasher };
package/hasher.d.ts CHANGED
@@ -1,13 +1,75 @@
1
+ /**
2
+ * Writer.
3
+ */
1
4
  export interface StringWriter {
5
+ /**
6
+ * Write data.
7
+ *
8
+ * @param data
9
+ * Value.
10
+ */
2
11
  writeString(data: string): void;
3
12
  }
4
13
  interface SubtleCryptoLike {
5
- digest(algorithm: AlgorithmIdentifier, data: BufferSource): Promise<ArrayBuffer>;
14
+ digest(algorithm: {
15
+ name: string;
16
+ } | string, data: ArrayBufferView<ArrayBufferLike> | ArrayBufferLike): Promise<ArrayBuffer>;
6
17
  }
18
+ /**
19
+ * Hash a field.
20
+ */
7
21
  export type FieldHasher = (data: StringWriter) => void;
22
+ /**
23
+ * Create a hasher for a boolean.
24
+ *
25
+ * @param key
26
+ * Key.
27
+ * @param value
28
+ * Value.
29
+ * @returns
30
+ * Hasher.
31
+ */
8
32
  export declare function bool(key: string, value: boolean): FieldHasher;
33
+ /**
34
+ * Create a hasher for an unsigned 32-bit integer.
35
+ *
36
+ * @param key
37
+ * Key.
38
+ * @param value
39
+ * Value.
40
+ * @returns
41
+ * Hasher.
42
+ */
9
43
  export declare function uint32(key: string, value: number): FieldHasher;
44
+ /**
45
+ * Create a hasher for a string.
46
+ *
47
+ * @param key
48
+ * Key.
49
+ * @param value
50
+ * Value.
51
+ * @returns
52
+ * Hasher.
53
+ */
10
54
  export declare function string(key: string, value: string): FieldHasher;
11
- export declare function stringSliceOrdered(key: string, values: string[]): FieldHasher;
12
- export declare function makeHasher(subtle: SubtleCryptoLike): (...hashers: FieldHasher[]) => Promise<string>;
55
+ /**
56
+ * Create a hasher for an array of strings.
57
+ *
58
+ * @param key
59
+ * Key.
60
+ * @param values
61
+ * Values.
62
+ * @returns
63
+ * Hasher.
64
+ */
65
+ export declare function stringSliceOrdered(key: string, values: ReadonlyArray<string>): FieldHasher;
66
+ /**
67
+ * Create a hasher.
68
+ *
69
+ * @param subtle
70
+ * Subtle crypto.
71
+ * @returns
72
+ * Hasher.
73
+ */
74
+ export declare function makeHasher(subtle: SubtleCryptoLike): (...hashers: ReadonlyArray<FieldHasher>) => Promise<string>;
13
75
  export {};
package/hasher.js CHANGED
@@ -20,6 +20,16 @@ class Sha256 {
20
20
  const maxUint32 = 4294967295;
21
21
  const fieldSeparator = ":";
22
22
  const itemSeparator = ",";
23
+ /**
24
+ * Create a hasher for a boolean.
25
+ *
26
+ * @param key
27
+ * Key.
28
+ * @param value
29
+ * Value.
30
+ * @returns
31
+ * Hasher.
32
+ */
23
33
  function bool(key, value) {
24
34
  return (data) => {
25
35
  data.writeString(key);
@@ -32,6 +42,16 @@ function bool(key, value) {
32
42
  }
33
43
  };
34
44
  }
45
+ /**
46
+ * Create a hasher for an unsigned 32-bit integer.
47
+ *
48
+ * @param key
49
+ * Key.
50
+ * @param value
51
+ * Value.
52
+ * @returns
53
+ * Hasher.
54
+ */
35
55
  function uint32(key, value) {
36
56
  return (data) => {
37
57
  data.writeString(key);
@@ -44,6 +64,16 @@ function uint32(key, value) {
44
64
  }
45
65
  };
46
66
  }
67
+ /**
68
+ * Create a hasher for a string.
69
+ *
70
+ * @param key
71
+ * Key.
72
+ * @param value
73
+ * Value.
74
+ * @returns
75
+ * Hasher.
76
+ */
47
77
  function string(key, value) {
48
78
  return (data) => {
49
79
  data.writeString(key);
@@ -53,6 +83,16 @@ function string(key, value) {
53
83
  data.writeString(`"`);
54
84
  };
55
85
  }
86
+ /**
87
+ * Create a hasher for an array of strings.
88
+ *
89
+ * @param key
90
+ * Key.
91
+ * @param values
92
+ * Values.
93
+ * @returns
94
+ * Hasher.
95
+ */
56
96
  function stringSliceOrdered(key, values) {
57
97
  return (data) => {
58
98
  data.writeString(key);
@@ -67,7 +107,23 @@ function stringSliceOrdered(key, values) {
67
107
  data.writeString("]");
68
108
  };
69
109
  }
110
+ /**
111
+ * Create a hasher.
112
+ *
113
+ * @param subtle
114
+ * Subtle crypto.
115
+ * @returns
116
+ * Hasher.
117
+ */
70
118
  function makeHasher(subtle) {
119
+ /**
120
+ * Hash fields.
121
+ *
122
+ * @param hashers
123
+ * Hashers.
124
+ * @returns
125
+ * Promise to a hash.
126
+ */
71
127
  return async function hash(...hashers) {
72
128
  const h = new Sha256(subtle);
73
129
  for (const hasher of hashers) {
package/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export * from "./hasher.js";
2
- export declare const hash: (...hashers: import("./hasher.js").FieldHasher[]) => Promise<string>;
2
+ export declare const hash: (...hashers: ReadonlyArray<import("./hasher.js").FieldHasher>) => Promise<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcjet/stable-hash",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.1.0-rc",
4
4
  "description": "Arcjet stable hashing utility",
5
5
  "keywords": [
6
6
  "arcjet",
@@ -25,13 +25,14 @@
25
25
  "url": "https://arcjet.com"
26
26
  },
27
27
  "engines": {
28
- "node": ">=18"
28
+ "node": ">=20"
29
29
  },
30
30
  "type": "module",
31
31
  "main": "./index.js",
32
32
  "types": "./index.d.ts",
33
33
  "exports": {
34
34
  "edge-light": "./edge-light.js",
35
+ "workerd": "./workerd.js",
35
36
  "default": "./index.js"
36
37
  },
37
38
  "files": [
@@ -40,25 +41,25 @@
40
41
  "hasher.d.ts",
41
42
  "hasher.js",
42
43
  "index.d.ts",
43
- "index.js"
44
+ "index.js",
45
+ "workerd.d.ts",
46
+ "workerd.js"
44
47
  ],
45
48
  "scripts": {
46
49
  "build": "rollup --config rollup.config.js",
47
50
  "lint": "eslint .",
48
- "prepublishOnly": "npm run build",
49
- "test-api": "node --test",
50
- "test-coverage": "node --experimental-test-coverage --test",
51
+ "test-api": "node --test -- test/*.test.js",
52
+ "test-coverage": "node --experimental-test-coverage --test -- test/*.test.js",
51
53
  "test": "npm run build && npm run lint && npm run test-coverage"
52
54
  },
53
55
  "dependencies": {},
54
56
  "devDependencies": {
55
- "@arcjet/eslint-config": "1.0.0-beta.9",
56
- "@arcjet/rollup-config": "1.0.0-beta.9",
57
- "@arcjet/tsconfig": "1.0.0-beta.9",
58
- "@rollup/wasm-node": "4.44.2",
59
- "@types/node": "18.18.0",
60
- "eslint": "9.30.1",
61
- "typescript": "5.8.3"
57
+ "@arcjet/eslint-config": "1.1.0-rc",
58
+ "@arcjet/rollup-config": "1.1.0-rc",
59
+ "@rollup/wasm-node": "4.57.0",
60
+ "@types/node": "25.0.10",
61
+ "eslint": "9.39.2",
62
+ "typescript": "5.9.3"
62
63
  },
63
64
  "publishConfig": {
64
65
  "access": "public",
package/workerd.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./hasher.js";
2
+ export declare const hash: (...hashers: ReadonlyArray<import("./hasher.js").FieldHasher>) => Promise<string>;
package/workerd.js ADDED
@@ -0,0 +1,10 @@
1
+ import { makeHasher } from './hasher.js';
2
+ export { bool, string, stringSliceOrdered, uint32 } from './hasher.js';
3
+
4
+ // @ts-ignore: this value exists in Workerd, as it implements the DOM type for it.
5
+ // See <https://developers.cloudflare.com/workers/runtime-apis/web-crypto/>.
6
+ // This can be verified by adding `/// <reference lib="dom" />` above.
7
+ // But we don’t want to load the entire DOM types or workerd-specific types.
8
+ const hash = makeHasher(crypto.subtle);
9
+
10
+ export { hash, makeHasher };