@gnufoo/canaad 0.5.1 → 2.0.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,84 +1,116 @@
1
- # @gnufoo/canaad
1
+ # canaad-wasm
2
2
 
3
- AAD canonicalization in your browser or Worker. Same spec, same bytes.
3
+ [![npm](https://img.shields.io/npm/v/@gnufoo%2Fcanaad)](https://www.npmjs.com/package/@gnufoo/canaad)
4
4
 
5
- ```bash
6
- npm install @gnufoo/canaad
5
+ AAD canonicalization for the browser and Cloudflare Workers. Same spec, same bytes as canaad-core.
6
+
7
+ ## Initialize
8
+
9
+ WASM must be initialized once before any function calls.
10
+
11
+ Browser / Cloudflare Workers:
12
+
13
+ ```typescript
14
+ import init, { canonicalizeDefault } from '@gnufoo/canaad';
15
+
16
+ await init();
7
17
  ```
8
18
 
9
- ## canonicalize
19
+ Node.js:
10
20
 
11
21
  ```typescript
12
- import { canonicalize, canonicalizeString, validate, hash } from '@gnufoo/canaad';
22
+ import { readFileSync } from 'node:fs';
23
+ import { initSync, canonicalizeDefault } from '@gnufoo/canaad';
13
24
 
14
- const bytes = canonicalize('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
15
- const str = canonicalizeString('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
16
- const ok = validate(json);
17
- const sha = hash(json); // 32-byte SHA-256
25
+ initSync({ module: readFileSync(new URL('./canaad_wasm_bg.wasm', import.meta.url)) });
18
26
  ```
19
27
 
20
- ## build
28
+ ## Default profile
21
29
 
22
30
  ```typescript
23
- import { AadBuilder } from '@gnufoo/canaad';
31
+ const bytes = canonicalizeDefault('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
32
+ // → Uint8Array
24
33
 
25
- const aad = new AadBuilder()
26
- .tenant("org_abc")
27
- .resource("secrets/db")
28
- .purpose("encryption")
29
- .timestamp(1706400000)
30
- .extensionString("x_vault_cluster", "us-east-1")
31
- .extensionInt("x_app_priority", 5)
32
- .build(); // Uint8Array
34
+ const str = canonicalizeDefaultString('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
35
+ // → string
36
+
37
+ const ok = validateDefault('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
38
+ // → boolean
33
39
  ```
34
40
 
35
- Numbers only no BigInt. `build()` and `buildString()` validate all inputs:
41
+ ## Generic object layer
42
+
43
+ Canonicalize any valid JSON object — no required fields, no version check:
36
44
 
37
- - NaN, Infinity, negative, fractional → rejected
38
- - `-0.0` allowed (equals 0 in IEEE 754)
39
- - integers > 2^53-1 rejected (JS safe integer limit)
45
+ ```typescript
46
+ const bytes = canonicalizeObject('{"z":"last","a":"first"}');
47
+ //Uint8Array
40
48
 
41
- ## exports
49
+ const str = canonicalizeObjectString('{"z":"last","a":"first"}');
50
+ // → '{"a":"first","z":"last"}'
51
+
52
+ const ok = validateObject('{"anything":"goes"}');
53
+ // → true
54
+ ```
42
55
 
43
- This package follows the gnufoo tool package format with four entry points:
56
+ Use this layer to build custom profiles.
44
57
 
45
- | Import | What you get |
46
- |--------|-------------|
47
- | `@gnufoo/canaad` | Direct WASM functions (after init) |
48
- | `@gnufoo/canaad/init` | `initWasm()` + `isInitialized()` |
49
- | `@gnufoo/canaad/meta` | Zod schemas + metadata (no WASM, SSG-safe) |
50
- | `@gnufoo/canaad/tool` | `toolDefinition` with `execute()` |
58
+ ## Hash
51
59
 
52
- The `/meta` import is safe for static site generation — no WASM loaded.
60
+ SHA-256 of the canonical form (default profile):
53
61
 
54
- The `/tool` path validates inputs via Zod (`z.number().int().nonnegative()` for timestamps and extension integers). Direct WASM imports bypass Zod — the Rust layer validates as defense-in-depth.
62
+ ```typescript
63
+ const sha = hash('{"v":1,"tenant":"org_abc","resource":"secrets/db","purpose":"encryption"}');
64
+ // → Uint8Array (32 bytes)
65
+ ```
55
66
 
56
- ## cloudflare workers
67
+ ## Build
57
68
 
58
69
  ```typescript
59
- import wasmModule from '@gnufoo/canaad/canaad_wasm_bg.wasm';
60
- import { toolDefinition } from '@gnufoo/canaad/tool';
70
+ import { AadBuilder } from '@gnufoo/canaad';
61
71
 
62
- await toolDefinition.initWasm(wasmModule);
72
+ const aad = new AadBuilder()
73
+ .tenant("org_abc")
74
+ .resource("secrets/db")
75
+ .purpose("encryption")
76
+ .timestamp(1706400000)
77
+ .extensionString("x_vault_cluster", "us-east-1")
78
+ .extensionInt("x_app_priority", 5)
79
+ .build(); // → Uint8Array
63
80
 
64
- const result = await toolDefinition.execute({
65
- action: 'build',
66
- tenant: 'org_abc',
67
- resource: 'secrets/db',
68
- purpose: 'encryption',
69
- });
81
+ const str = new AadBuilder()
82
+ .tenant("org_abc")
83
+ .resource("secrets/db")
84
+ .purpose("encryption")
85
+ .buildString(); // → string
70
86
  ```
71
87
 
72
- ## browser (vite)
88
+ Numbers only — no BigInt. `build()` and `buildString()` reject NaN, Infinity, negative, fractional, and values above `Number.MAX_SAFE_INTEGER`.
73
89
 
74
- With `vite-plugin-wasm` and `vite-plugin-top-level-await`:
90
+ ## Constants
75
91
 
76
92
  ```typescript
77
- import { toolDefinition } from '@gnufoo/canaad/tool';
93
+ SPEC_VERSION() // 1 (current AAD spec version)
94
+ MAX_SAFE_INTEGER() // → 9007199254740991 (2^53 - 1, max allowed integer value)
95
+ MAX_SERIALIZED_BYTES() // → 16384 (16 KiB size limit)
96
+ ```
97
+
98
+ ## Errors
78
99
 
79
- await toolDefinition.initWasm();
100
+ Failed calls throw with a descriptive message:
101
+
102
+ ```typescript
103
+ try {
104
+ canonicalizeDefault('{"v":1}');
105
+ } catch (e) {
106
+ console.error(e.message); // "missing required field: tenant"
107
+ }
80
108
  ```
81
109
 
82
- ## license
110
+ ## Build from source
111
+
112
+ ```bash
113
+ wasm-pack build --target web --out-dir ../../pkg crates/canaad-wasm
114
+ ```
83
115
 
84
- MIT OR Apache-2.0
116
+ `--target web` exports an explicit `init()` you control — works with Cloudflare Workers and Vite.
package/canaad_wasm.d.ts CHANGED
@@ -2,83 +2,99 @@
2
2
  /* eslint-disable */
3
3
 
4
4
  /**
5
- * Fluent builder for AAD objects. Chain setters, call `build()` or `buildString()`.
5
+ * fluent builder for AAD objects. Chain setters, call `build()` or `buildString()`.
6
6
  */
7
7
  export class AadBuilder {
8
8
  free(): void;
9
9
  [Symbol.dispose](): void;
10
10
  /**
11
- * Builds AAD and returns canonical bytes.
11
+ * builds AAD and returns canonical bytes.
12
12
  */
13
13
  build(): Uint8Array;
14
14
  /**
15
- * Builds AAD and returns canonical UTF-8 string.
15
+ * builds AAD and returns canonical UTF-8 string.
16
16
  */
17
17
  buildString(): string;
18
18
  /**
19
- * Adds an integer extension. Validated at `build()`.
19
+ * adds an integer extension. Validated at `build()`.
20
20
  */
21
21
  extensionInt(key: string, value: number): AadBuilder;
22
22
  /**
23
- * Adds a string extension. Key format: `x_<app>_<field>`.
23
+ * adds a string extension. Key format: `x_<app>_<field>`.
24
24
  */
25
25
  extensionString(key: string, value: string): AadBuilder;
26
26
  /**
27
- * Creates a new AAD builder.
27
+ * creates an empty builder. Setters store raw values; validation runs on `build()`.
28
28
  */
29
29
  constructor();
30
30
  /**
31
- * Sets the purpose. 1+ bytes, no NUL.
31
+ * sets the purpose. 1+ bytes, no NUL.
32
32
  */
33
33
  purpose(value: string): AadBuilder;
34
34
  /**
35
- * Sets the resource. 1-1024 bytes, no NUL.
35
+ * sets the resource. 1-1024 bytes, no NUL.
36
36
  */
37
37
  resource(value: string): AadBuilder;
38
38
  /**
39
- * Sets the tenant. 1-256 bytes, no NUL.
39
+ * sets the tenant. 1-256 bytes, no NUL.
40
40
  */
41
41
  tenant(value: string): AadBuilder;
42
42
  /**
43
- * Sets the timestamp. Validated at `build()`.
43
+ * sets the timestamp. Validated at `build()`.
44
44
  */
45
45
  timestamp(ts: number): AadBuilder;
46
46
  }
47
47
 
48
48
  /**
49
- * Maximum safe integer (2^53 - 1).
49
+ * maximum safe integer (2^53 - 1).
50
50
  */
51
51
  export function MAX_SAFE_INTEGER(): number;
52
52
 
53
53
  /**
54
- * Maximum serialized AAD size in bytes (16 KiB).
54
+ * maximum serialized AAD size in bytes (16 KiB).
55
55
  */
56
56
  export function MAX_SERIALIZED_BYTES(): number;
57
57
 
58
58
  /**
59
- * Current AAD specification version (always 1).
59
+ * current AAD specification version (always 1).
60
60
  */
61
61
  export function SPEC_VERSION(): number;
62
62
 
63
63
  /**
64
- * Parses and canonicalizes a JSON string to bytes (RFC 8785).
64
+ * parses and canonicalizes a JSON string to bytes using the default AAD profile.
65
65
  */
66
- export function canonicalize(json: string): Uint8Array;
66
+ export function canonicalizeDefault(json: string): Uint8Array;
67
67
 
68
68
  /**
69
- * Parses and canonicalizes a JSON string to a UTF-8 string.
69
+ * parses and canonicalizes a JSON string to a UTF-8 string using the default AAD profile.
70
70
  */
71
- export function canonicalizeString(json: string): string;
71
+ export function canonicalizeDefaultString(json: string): string;
72
72
 
73
73
  /**
74
- * SHA-256 hash of the canonical JSON form.
74
+ * canonicalizes any valid JSON object to bytes (core rules only, no profile fields required).
75
+ */
76
+ export function canonicalizeObject(json: string): Uint8Array;
77
+
78
+ /**
79
+ * canonicalizes any valid JSON object to a UTF-8 string (core rules only, no profile fields required).
80
+ */
81
+ export function canonicalizeObjectString(json: string): string;
82
+
83
+ /**
84
+ * SHA-256 hash of the canonical JSON form (default AAD profile).
75
85
  */
76
86
  export function hash(json: string): Uint8Array;
77
87
 
78
88
  /**
79
- * Validates a JSON string against the AAD specification.
89
+ * validates a JSON string against the default AAD profile. Returns false on any error.
90
+ */
91
+ export function validateDefault(json: string): boolean;
92
+
93
+ /**
94
+ * validates a JSON string against core rules only (size, duplicate keys, object shape).
95
+ * Returns false on any error.
80
96
  */
81
- export function validate(json: string): boolean;
97
+ export function validateObject(json: string): boolean;
82
98
 
83
99
  export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
84
100
 
@@ -97,10 +113,13 @@ export interface InitOutput {
97
113
  readonly aadbuilder_resource: (a: number, b: number, c: number) => number;
98
114
  readonly aadbuilder_tenant: (a: number, b: number, c: number) => number;
99
115
  readonly aadbuilder_timestamp: (a: number, b: number) => number;
100
- readonly canonicalize: (a: number, b: number) => [number, number, number, number];
101
- readonly canonicalizeString: (a: number, b: number) => [number, number, number, number];
116
+ readonly canonicalizeDefault: (a: number, b: number) => [number, number, number, number];
117
+ readonly canonicalizeDefaultString: (a: number, b: number) => [number, number, number, number];
118
+ readonly canonicalizeObject: (a: number, b: number) => [number, number, number, number];
119
+ readonly canonicalizeObjectString: (a: number, b: number) => [number, number, number, number];
102
120
  readonly hash: (a: number, b: number) => [number, number, number, number];
103
- readonly validate: (a: number, b: number) => number;
121
+ readonly validateDefault: (a: number, b: number) => number;
122
+ readonly validateObject: (a: number, b: number) => number;
104
123
  readonly __wbindgen_externrefs: WebAssembly.Table;
105
124
  readonly __externref_table_dealloc: (a: number) => void;
106
125
  readonly __wbindgen_free: (a: number, b: number, c: number) => void;
package/canaad_wasm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* @ts-self-types="./canaad_wasm.d.ts" */
2
2
 
3
3
  /**
4
- * Fluent builder for AAD objects. Chain setters, call `build()` or `buildString()`.
4
+ * fluent builder for AAD objects. Chain setters, call `build()` or `buildString()`.
5
5
  */
6
6
  export class AadBuilder {
7
7
  static __wrap(ptr) {
@@ -22,7 +22,7 @@ export class AadBuilder {
22
22
  wasm.__wbg_aadbuilder_free(ptr, 0);
23
23
  }
24
24
  /**
25
- * Builds AAD and returns canonical bytes.
25
+ * builds AAD and returns canonical bytes.
26
26
  * @returns {Uint8Array}
27
27
  */
28
28
  build() {
@@ -35,7 +35,7 @@ export class AadBuilder {
35
35
  return v1;
36
36
  }
37
37
  /**
38
- * Builds AAD and returns canonical UTF-8 string.
38
+ * builds AAD and returns canonical UTF-8 string.
39
39
  * @returns {string}
40
40
  */
41
41
  buildString() {
@@ -57,7 +57,7 @@ export class AadBuilder {
57
57
  }
58
58
  }
59
59
  /**
60
- * Adds an integer extension. Validated at `build()`.
60
+ * adds an integer extension. Validated at `build()`.
61
61
  * @param {string} key
62
62
  * @param {number} value
63
63
  * @returns {AadBuilder}
@@ -70,7 +70,7 @@ export class AadBuilder {
70
70
  return AadBuilder.__wrap(ret);
71
71
  }
72
72
  /**
73
- * Adds a string extension. Key format: `x_<app>_<field>`.
73
+ * adds a string extension. Key format: `x_<app>_<field>`.
74
74
  * @param {string} key
75
75
  * @param {string} value
76
76
  * @returns {AadBuilder}
@@ -85,7 +85,7 @@ export class AadBuilder {
85
85
  return AadBuilder.__wrap(ret);
86
86
  }
87
87
  /**
88
- * Creates a new AAD builder.
88
+ * creates an empty builder. Setters store raw values; validation runs on `build()`.
89
89
  */
90
90
  constructor() {
91
91
  const ret = wasm.aadbuilder_new();
@@ -94,7 +94,7 @@ export class AadBuilder {
94
94
  return this;
95
95
  }
96
96
  /**
97
- * Sets the purpose. 1+ bytes, no NUL.
97
+ * sets the purpose. 1+ bytes, no NUL.
98
98
  * @param {string} value
99
99
  * @returns {AadBuilder}
100
100
  */
@@ -106,7 +106,7 @@ export class AadBuilder {
106
106
  return AadBuilder.__wrap(ret);
107
107
  }
108
108
  /**
109
- * Sets the resource. 1-1024 bytes, no NUL.
109
+ * sets the resource. 1-1024 bytes, no NUL.
110
110
  * @param {string} value
111
111
  * @returns {AadBuilder}
112
112
  */
@@ -118,7 +118,7 @@ export class AadBuilder {
118
118
  return AadBuilder.__wrap(ret);
119
119
  }
120
120
  /**
121
- * Sets the tenant. 1-256 bytes, no NUL.
121
+ * sets the tenant. 1-256 bytes, no NUL.
122
122
  * @param {string} value
123
123
  * @returns {AadBuilder}
124
124
  */
@@ -130,7 +130,7 @@ export class AadBuilder {
130
130
  return AadBuilder.__wrap(ret);
131
131
  }
132
132
  /**
133
- * Sets the timestamp. Validated at `build()`.
133
+ * sets the timestamp. Validated at `build()`.
134
134
  * @param {number} ts
135
135
  * @returns {AadBuilder}
136
136
  */
@@ -143,7 +143,7 @@ export class AadBuilder {
143
143
  if (Symbol.dispose) AadBuilder.prototype[Symbol.dispose] = AadBuilder.prototype.free;
144
144
 
145
145
  /**
146
- * Maximum safe integer (2^53 - 1).
146
+ * maximum safe integer (2^53 - 1).
147
147
  * @returns {number}
148
148
  */
149
149
  export function MAX_SAFE_INTEGER() {
@@ -152,7 +152,7 @@ export function MAX_SAFE_INTEGER() {
152
152
  }
153
153
 
154
154
  /**
155
- * Maximum serialized AAD size in bytes (16 KiB).
155
+ * maximum serialized AAD size in bytes (16 KiB).
156
156
  * @returns {number}
157
157
  */
158
158
  export function MAX_SERIALIZED_BYTES() {
@@ -161,7 +161,7 @@ export function MAX_SERIALIZED_BYTES() {
161
161
  }
162
162
 
163
163
  /**
164
- * Current AAD specification version (always 1).
164
+ * current AAD specification version (always 1).
165
165
  * @returns {number}
166
166
  */
167
167
  export function SPEC_VERSION() {
@@ -170,14 +170,14 @@ export function SPEC_VERSION() {
170
170
  }
171
171
 
172
172
  /**
173
- * Parses and canonicalizes a JSON string to bytes (RFC 8785).
173
+ * parses and canonicalizes a JSON string to bytes using the default AAD profile.
174
174
  * @param {string} json
175
175
  * @returns {Uint8Array}
176
176
  */
177
- export function canonicalize(json) {
177
+ export function canonicalizeDefault(json) {
178
178
  const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
179
179
  const len0 = WASM_VECTOR_LEN;
180
- const ret = wasm.canonicalize(ptr0, len0);
180
+ const ret = wasm.canonicalizeDefault(ptr0, len0);
181
181
  if (ret[3]) {
182
182
  throw takeFromExternrefTable0(ret[2]);
183
183
  }
@@ -187,17 +187,17 @@ export function canonicalize(json) {
187
187
  }
188
188
 
189
189
  /**
190
- * Parses and canonicalizes a JSON string to a UTF-8 string.
190
+ * parses and canonicalizes a JSON string to a UTF-8 string using the default AAD profile.
191
191
  * @param {string} json
192
192
  * @returns {string}
193
193
  */
194
- export function canonicalizeString(json) {
194
+ export function canonicalizeDefaultString(json) {
195
195
  let deferred3_0;
196
196
  let deferred3_1;
197
197
  try {
198
198
  const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
199
199
  const len0 = WASM_VECTOR_LEN;
200
- const ret = wasm.canonicalizeString(ptr0, len0);
200
+ const ret = wasm.canonicalizeDefaultString(ptr0, len0);
201
201
  var ptr2 = ret[0];
202
202
  var len2 = ret[1];
203
203
  if (ret[3]) {
@@ -213,7 +213,50 @@ export function canonicalizeString(json) {
213
213
  }
214
214
 
215
215
  /**
216
- * SHA-256 hash of the canonical JSON form.
216
+ * canonicalizes any valid JSON object to bytes (core rules only, no profile fields required).
217
+ * @param {string} json
218
+ * @returns {Uint8Array}
219
+ */
220
+ export function canonicalizeObject(json) {
221
+ const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
222
+ const len0 = WASM_VECTOR_LEN;
223
+ const ret = wasm.canonicalizeObject(ptr0, len0);
224
+ if (ret[3]) {
225
+ throw takeFromExternrefTable0(ret[2]);
226
+ }
227
+ var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
228
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
229
+ return v2;
230
+ }
231
+
232
+ /**
233
+ * canonicalizes any valid JSON object to a UTF-8 string (core rules only, no profile fields required).
234
+ * @param {string} json
235
+ * @returns {string}
236
+ */
237
+ export function canonicalizeObjectString(json) {
238
+ let deferred3_0;
239
+ let deferred3_1;
240
+ try {
241
+ const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
242
+ const len0 = WASM_VECTOR_LEN;
243
+ const ret = wasm.canonicalizeObjectString(ptr0, len0);
244
+ var ptr2 = ret[0];
245
+ var len2 = ret[1];
246
+ if (ret[3]) {
247
+ ptr2 = 0; len2 = 0;
248
+ throw takeFromExternrefTable0(ret[2]);
249
+ }
250
+ deferred3_0 = ptr2;
251
+ deferred3_1 = len2;
252
+ return getStringFromWasm0(ptr2, len2);
253
+ } finally {
254
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
255
+ }
256
+ }
257
+
258
+ /**
259
+ * SHA-256 hash of the canonical JSON form (default AAD profile).
217
260
  * @param {string} json
218
261
  * @returns {Uint8Array}
219
262
  */
@@ -230,14 +273,27 @@ export function hash(json) {
230
273
  }
231
274
 
232
275
  /**
233
- * Validates a JSON string against the AAD specification.
276
+ * validates a JSON string against the default AAD profile. Returns false on any error.
277
+ * @param {string} json
278
+ * @returns {boolean}
279
+ */
280
+ export function validateDefault(json) {
281
+ const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
282
+ const len0 = WASM_VECTOR_LEN;
283
+ const ret = wasm.validateDefault(ptr0, len0);
284
+ return ret !== 0;
285
+ }
286
+
287
+ /**
288
+ * validates a JSON string against core rules only (size, duplicate keys, object shape).
289
+ * Returns false on any error.
234
290
  * @param {string} json
235
291
  * @returns {boolean}
236
292
  */
237
- export function validate(json) {
293
+ export function validateObject(json) {
238
294
  const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
239
295
  const len0 = WASM_VECTOR_LEN;
240
- const ret = wasm.validate(ptr0, len0);
296
+ const ret = wasm.validateObject(ptr0, len0);
241
297
  return ret !== 0;
242
298
  }
243
299
 
Binary file
@@ -14,10 +14,13 @@ export const aadbuilder_purpose: (a: number, b: number, c: number) => number;
14
14
  export const aadbuilder_resource: (a: number, b: number, c: number) => number;
15
15
  export const aadbuilder_tenant: (a: number, b: number, c: number) => number;
16
16
  export const aadbuilder_timestamp: (a: number, b: number) => number;
17
- export const canonicalize: (a: number, b: number) => [number, number, number, number];
18
- export const canonicalizeString: (a: number, b: number) => [number, number, number, number];
17
+ export const canonicalizeDefault: (a: number, b: number) => [number, number, number, number];
18
+ export const canonicalizeDefaultString: (a: number, b: number) => [number, number, number, number];
19
+ export const canonicalizeObject: (a: number, b: number) => [number, number, number, number];
20
+ export const canonicalizeObjectString: (a: number, b: number) => [number, number, number, number];
19
21
  export const hash: (a: number, b: number) => [number, number, number, number];
20
- export const validate: (a: number, b: number) => number;
22
+ export const validateDefault: (a: number, b: number) => number;
23
+ export const validateObject: (a: number, b: number) => number;
21
24
  export const __wbindgen_externrefs: WebAssembly.Table;
22
25
  export const __externref_table_dealloc: (a: number) => void;
23
26
  export const __wbindgen_free: (a: number, b: number, c: number) => void;
package/package.json CHANGED
@@ -1,47 +1,33 @@
1
1
  {
2
2
  "name": "@gnufoo/canaad",
3
- "version": "0.5.1",
4
3
  "type": "module",
5
- "types": "canaad_wasm.d.ts",
6
- "exports": {
7
- ".": {
8
- "types": "./canaad_wasm.d.ts",
9
- "import": "./canaad_wasm.js"
10
- },
11
- "./meta": {
12
- "types": "./meta.d.ts",
13
- "import": "./meta.js"
14
- },
15
- "./tool": {
16
- "types": "./tool.d.ts",
17
- "import": "./tool.js"
18
- },
19
- "./init": {
20
- "types": "./init.d.ts",
21
- "import": "./init.js"
22
- }
23
- },
24
- "dependencies": {
25
- "zod": "^3.24.0"
4
+ "description": "WASM bindings for AAD canonicalization per RFC 8785",
5
+ "version": "2.0.0",
6
+ "license": "MIT OR Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/gnufood/canaad"
26
10
  },
27
11
  "files": [
28
- "*.js",
29
- "*.d.ts",
30
- "*.wasm"
12
+ "canaad_wasm.js",
13
+ "canaad_wasm.d.ts",
14
+ "canaad_wasm_bg.wasm",
15
+ "canaad_wasm_bg.wasm.d.ts"
31
16
  ],
17
+ "types": "canaad_wasm.d.ts",
32
18
  "sideEffects": false,
33
19
  "keywords": [
34
20
  "aead",
35
21
  "aad",
36
22
  "canonicalization",
37
23
  "jcs",
38
- "rfc8785",
39
- "wasm"
24
+ "rfc8785"
40
25
  ],
41
- "license": "MIT OR Apache-2.0",
42
- "description": "AAD canonicalization library (RFC 8785)",
43
- "repository": {
44
- "url": "https://gnu.foo/projects/canaad"
26
+ "exports": {
27
+ ".": {
28
+ "types": "./canaad_wasm.d.ts",
29
+ "import": "./canaad_wasm.js"
30
+ }
45
31
  },
46
32
  "homepage": "https://gnu.foo/projects/canaad",
47
33
  "bugs": {
package/canaad_wasm_bg.js DELETED
@@ -1,527 +0,0 @@
1
- /**
2
- * Builder for constructing AAD objects programmatically.
3
- *
4
- * Provides a fluent API for building AAD with method chaining.
5
- * All setter methods return a new builder to enable chaining.
6
- *
7
- * # Example (JavaScript)
8
- *
9
- * ```javascript
10
- * const builder = new AadBuilder()
11
- * .tenant("org_abc")
12
- * .resource("secrets/db")
13
- * .purpose("encryption")
14
- * .timestamp(1706400000)
15
- * .extensionString("x_vault_cluster", "us-east-1");
16
- *
17
- * const bytes = builder.build();
18
- * const canonical = builder.buildString();
19
- * ```
20
- */
21
- export class AadBuilder {
22
- static __wrap(ptr) {
23
- ptr = ptr >>> 0;
24
- const obj = Object.create(AadBuilder.prototype);
25
- obj.__wbg_ptr = ptr;
26
- AadBuilderFinalization.register(obj, obj.__wbg_ptr, obj);
27
- return obj;
28
- }
29
- __destroy_into_raw() {
30
- const ptr = this.__wbg_ptr;
31
- this.__wbg_ptr = 0;
32
- AadBuilderFinalization.unregister(this);
33
- return ptr;
34
- }
35
- free() {
36
- const ptr = this.__destroy_into_raw();
37
- wasm.__wbg_aadbuilder_free(ptr, 0);
38
- }
39
- /**
40
- * Builds the AAD and returns the canonical bytes.
41
- *
42
- * # Returns
43
- *
44
- * A `Uint8Array` containing the UTF-8 encoded canonical JSON.
45
- *
46
- * # Errors
47
- *
48
- * Throws a JavaScript error if:
49
- * - Required fields (tenant, resource, purpose) are missing
50
- * - Any field value is invalid
51
- * - Extension keys don't match the required pattern
52
- * - The serialized output exceeds 16 KiB
53
- * @returns {Uint8Array}
54
- */
55
- build() {
56
- const ret = wasm.aadbuilder_build(this.__wbg_ptr);
57
- if (ret[3]) {
58
- throw takeFromExternrefTable0(ret[2]);
59
- }
60
- var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
61
- wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
62
- return v1;
63
- }
64
- /**
65
- * Builds the AAD and returns the canonical string.
66
- *
67
- * # Returns
68
- *
69
- * The canonical (JCS) representation as a string.
70
- *
71
- * # Errors
72
- *
73
- * Throws a JavaScript error if:
74
- * - Required fields (tenant, resource, purpose) are missing
75
- * - Any field value is invalid
76
- * - Extension keys don't match the required pattern
77
- * - The serialized output exceeds 16 KiB
78
- * @returns {string}
79
- */
80
- buildString() {
81
- let deferred2_0;
82
- let deferred2_1;
83
- try {
84
- const ret = wasm.aadbuilder_buildString(this.__wbg_ptr);
85
- var ptr1 = ret[0];
86
- var len1 = ret[1];
87
- if (ret[3]) {
88
- ptr1 = 0; len1 = 0;
89
- throw takeFromExternrefTable0(ret[2]);
90
- }
91
- deferred2_0 = ptr1;
92
- deferred2_1 = len1;
93
- return getStringFromWasm0(ptr1, len1);
94
- } finally {
95
- wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
96
- }
97
- }
98
- /**
99
- * Adds an integer extension field.
100
- *
101
- * Extension keys must match pattern `x_<app>_<field>` where:
102
- * - `<app>` is one or more lowercase letters
103
- * - `<field>` is one or more lowercase letters or underscores
104
- *
105
- * # Arguments
106
- *
107
- * * `key` - Extension key (e.g., `x_app_priority`)
108
- * * `value` - Integer value (0 to 2^53-1)
109
- *
110
- * # Returns
111
- *
112
- * A new builder with the extension added.
113
- * @param {string} key
114
- * @param {number} value
115
- * @returns {AadBuilder}
116
- */
117
- extensionInt(key, value) {
118
- const ptr = this.__destroy_into_raw();
119
- const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
120
- const len0 = WASM_VECTOR_LEN;
121
- const ret = wasm.aadbuilder_extensionInt(ptr, ptr0, len0, value);
122
- return AadBuilder.__wrap(ret);
123
- }
124
- /**
125
- * Adds a string extension field.
126
- *
127
- * Extension keys must match pattern `x_<app>_<field>` where:
128
- * - `<app>` is one or more lowercase letters
129
- * - `<field>` is one or more lowercase letters or underscores
130
- *
131
- * # Arguments
132
- *
133
- * * `key` - Extension key (e.g., `x_vault_cluster`)
134
- * * `value` - String value (no NUL bytes)
135
- *
136
- * # Returns
137
- *
138
- * A new builder with the extension added.
139
- * @param {string} key
140
- * @param {string} value
141
- * @returns {AadBuilder}
142
- */
143
- extensionString(key, value) {
144
- const ptr = this.__destroy_into_raw();
145
- const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
146
- const len0 = WASM_VECTOR_LEN;
147
- const ptr1 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
148
- const len1 = WASM_VECTOR_LEN;
149
- const ret = wasm.aadbuilder_extensionString(ptr, ptr0, len0, ptr1, len1);
150
- return AadBuilder.__wrap(ret);
151
- }
152
- /**
153
- * Creates a new AAD builder.
154
- */
155
- constructor() {
156
- const ret = wasm.aadbuilder_new();
157
- this.__wbg_ptr = ret >>> 0;
158
- AadBuilderFinalization.register(this, this.__wbg_ptr, this);
159
- return this;
160
- }
161
- /**
162
- * Sets the purpose or usage context.
163
- *
164
- * # Arguments
165
- *
166
- * * `value` - Purpose description (1+ bytes, no NUL bytes)
167
- *
168
- * # Returns
169
- *
170
- * A new builder with the purpose set.
171
- * @param {string} value
172
- * @returns {AadBuilder}
173
- */
174
- purpose(value) {
175
- const ptr = this.__destroy_into_raw();
176
- const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
177
- const len0 = WASM_VECTOR_LEN;
178
- const ret = wasm.aadbuilder_purpose(ptr, ptr0, len0);
179
- return AadBuilder.__wrap(ret);
180
- }
181
- /**
182
- * Sets the resource path or identifier.
183
- *
184
- * # Arguments
185
- *
186
- * * `value` - Resource path (1-1024 bytes, no NUL bytes)
187
- *
188
- * # Returns
189
- *
190
- * A new builder with the resource set.
191
- * @param {string} value
192
- * @returns {AadBuilder}
193
- */
194
- resource(value) {
195
- const ptr = this.__destroy_into_raw();
196
- const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
197
- const len0 = WASM_VECTOR_LEN;
198
- const ret = wasm.aadbuilder_resource(ptr, ptr0, len0);
199
- return AadBuilder.__wrap(ret);
200
- }
201
- /**
202
- * Sets the tenant identifier.
203
- *
204
- * # Arguments
205
- *
206
- * * `value` - Tenant identifier (1-256 bytes, no NUL bytes)
207
- *
208
- * # Returns
209
- *
210
- * A new builder with the tenant set.
211
- * @param {string} value
212
- * @returns {AadBuilder}
213
- */
214
- tenant(value) {
215
- const ptr = this.__destroy_into_raw();
216
- const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
217
- const len0 = WASM_VECTOR_LEN;
218
- const ret = wasm.aadbuilder_tenant(ptr, ptr0, len0);
219
- return AadBuilder.__wrap(ret);
220
- }
221
- /**
222
- * Sets the timestamp.
223
- *
224
- * # Arguments
225
- *
226
- * * `ts` - Unix timestamp (0 to 2^53-1)
227
- *
228
- * # Returns
229
- *
230
- * A new builder with the timestamp set.
231
- * @param {number} ts
232
- * @returns {AadBuilder}
233
- */
234
- timestamp(ts) {
235
- const ptr = this.__destroy_into_raw();
236
- const ret = wasm.aadbuilder_timestamp(ptr, ts);
237
- return AadBuilder.__wrap(ret);
238
- }
239
- }
240
- if (Symbol.dispose) AadBuilder.prototype[Symbol.dispose] = AadBuilder.prototype.free;
241
-
242
- /**
243
- * Returns the maximum safe integer value (2^53 - 1).
244
- *
245
- * This is the maximum integer value that can be exactly represented in
246
- * JavaScript's Number type.
247
- * @returns {number}
248
- */
249
- export function MAX_SAFE_INTEGER() {
250
- const ret = wasm.MAX_SAFE_INTEGER();
251
- return ret;
252
- }
253
-
254
- /**
255
- * Returns the maximum serialized AAD size in bytes (16 KiB).
256
- * @returns {number}
257
- */
258
- export function MAX_SERIALIZED_BYTES() {
259
- const ret = wasm.MAX_SERIALIZED_BYTES();
260
- return ret >>> 0;
261
- }
262
-
263
- /**
264
- * Returns the current AAD specification version.
265
- *
266
- * Currently always returns 1.
267
- * @returns {number}
268
- */
269
- export function SPEC_VERSION() {
270
- const ret = wasm.SPEC_VERSION();
271
- return ret >>> 0;
272
- }
273
-
274
- /**
275
- * Parses and canonicalizes a JSON string to bytes.
276
- *
277
- * This function:
278
- * 1. Parses the JSON with duplicate key detection
279
- * 2. Validates all fields according to the AAD specification
280
- * 3. Returns the canonical (JCS) representation as bytes
281
- *
282
- * # Arguments
283
- *
284
- * * `json` - A JSON string containing an AAD object
285
- *
286
- * # Returns
287
- *
288
- * A `Uint8Array` containing the UTF-8 encoded canonical JSON.
289
- *
290
- * # Errors
291
- *
292
- * Throws a JavaScript error if:
293
- * - The JSON is invalid or contains duplicate keys
294
- * - Any field violates AAD constraints
295
- * - The serialized output exceeds 16 KiB
296
- * @param {string} json
297
- * @returns {Uint8Array}
298
- */
299
- export function canonicalize(json) {
300
- const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
301
- const len0 = WASM_VECTOR_LEN;
302
- const ret = wasm.canonicalize(ptr0, len0);
303
- if (ret[3]) {
304
- throw takeFromExternrefTable0(ret[2]);
305
- }
306
- var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
307
- wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
308
- return v2;
309
- }
310
-
311
- /**
312
- * Parses and canonicalizes a JSON string to a UTF-8 string.
313
- *
314
- * This is equivalent to `canonicalize` but returns a string instead of bytes.
315
- *
316
- * # Arguments
317
- *
318
- * * `json` - A JSON string containing an AAD object
319
- *
320
- * # Returns
321
- *
322
- * The canonical (JCS) representation as a string.
323
- *
324
- * # Errors
325
- *
326
- * Throws a JavaScript error if:
327
- * - The JSON is invalid or contains duplicate keys
328
- * - Any field violates AAD constraints
329
- * - The serialized output exceeds 16 KiB
330
- * @param {string} json
331
- * @returns {string}
332
- */
333
- export function canonicalizeString(json) {
334
- let deferred3_0;
335
- let deferred3_1;
336
- try {
337
- const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
338
- const len0 = WASM_VECTOR_LEN;
339
- const ret = wasm.canonicalizeString(ptr0, len0);
340
- var ptr2 = ret[0];
341
- var len2 = ret[1];
342
- if (ret[3]) {
343
- ptr2 = 0; len2 = 0;
344
- throw takeFromExternrefTable0(ret[2]);
345
- }
346
- deferred3_0 = ptr2;
347
- deferred3_1 = len2;
348
- return getStringFromWasm0(ptr2, len2);
349
- } finally {
350
- wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
351
- }
352
- }
353
-
354
- /**
355
- * Computes the SHA-256 hash of the canonical JSON form.
356
- *
357
- * This function:
358
- * 1. Parses and validates the JSON
359
- * 2. Canonicalizes according to RFC 8785
360
- * 3. Returns the SHA-256 hash of the canonical bytes
361
- *
362
- * # Arguments
363
- *
364
- * * `json` - A JSON string containing an AAD object
365
- *
366
- * # Returns
367
- *
368
- * A 32-byte `Uint8Array` containing the SHA-256 hash.
369
- *
370
- * # Errors
371
- *
372
- * Throws a JavaScript error if:
373
- * - The JSON is invalid or contains duplicate keys
374
- * - Any field violates AAD constraints
375
- * - The serialized output exceeds 16 KiB
376
- * @param {string} json
377
- * @returns {Uint8Array}
378
- */
379
- export function hash(json) {
380
- const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
381
- const len0 = WASM_VECTOR_LEN;
382
- const ret = wasm.hash(ptr0, len0);
383
- if (ret[3]) {
384
- throw takeFromExternrefTable0(ret[2]);
385
- }
386
- var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
387
- wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
388
- return v2;
389
- }
390
-
391
- /**
392
- * Validates a JSON string against the AAD specification.
393
- *
394
- * This function performs full validation without returning the context.
395
- * Use this for quick validation checks.
396
- *
397
- * # Arguments
398
- *
399
- * * `json` - A JSON string to validate
400
- *
401
- * # Returns
402
- *
403
- * `true` if the JSON is valid AAD, `false` otherwise.
404
- * @param {string} json
405
- * @returns {boolean}
406
- */
407
- export function validate(json) {
408
- const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
409
- const len0 = WASM_VECTOR_LEN;
410
- const ret = wasm.validate(ptr0, len0);
411
- return ret !== 0;
412
- }
413
- export function __wbg_Error_8c4e43fe74559d73(arg0, arg1) {
414
- const ret = Error(getStringFromWasm0(arg0, arg1));
415
- return ret;
416
- }
417
- export function __wbg___wbindgen_throw_be289d5034ed271b(arg0, arg1) {
418
- throw new Error(getStringFromWasm0(arg0, arg1));
419
- }
420
- export function __wbindgen_init_externref_table() {
421
- const table = wasm.__wbindgen_externrefs;
422
- const offset = table.grow(4);
423
- table.set(0, undefined);
424
- table.set(offset + 0, undefined);
425
- table.set(offset + 1, null);
426
- table.set(offset + 2, true);
427
- table.set(offset + 3, false);
428
- }
429
- const AadBuilderFinalization = (typeof FinalizationRegistry === 'undefined')
430
- ? { register: () => {}, unregister: () => {} }
431
- : new FinalizationRegistry(ptr => wasm.__wbg_aadbuilder_free(ptr >>> 0, 1));
432
-
433
- function getArrayU8FromWasm0(ptr, len) {
434
- ptr = ptr >>> 0;
435
- return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
436
- }
437
-
438
- function getStringFromWasm0(ptr, len) {
439
- ptr = ptr >>> 0;
440
- return decodeText(ptr, len);
441
- }
442
-
443
- let cachedUint8ArrayMemory0 = null;
444
- function getUint8ArrayMemory0() {
445
- if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
446
- cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
447
- }
448
- return cachedUint8ArrayMemory0;
449
- }
450
-
451
- function passStringToWasm0(arg, malloc, realloc) {
452
- if (realloc === undefined) {
453
- const buf = cachedTextEncoder.encode(arg);
454
- const ptr = malloc(buf.length, 1) >>> 0;
455
- getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
456
- WASM_VECTOR_LEN = buf.length;
457
- return ptr;
458
- }
459
-
460
- let len = arg.length;
461
- let ptr = malloc(len, 1) >>> 0;
462
-
463
- const mem = getUint8ArrayMemory0();
464
-
465
- let offset = 0;
466
-
467
- for (; offset < len; offset++) {
468
- const code = arg.charCodeAt(offset);
469
- if (code > 0x7F) break;
470
- mem[ptr + offset] = code;
471
- }
472
- if (offset !== len) {
473
- if (offset !== 0) {
474
- arg = arg.slice(offset);
475
- }
476
- ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
477
- const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
478
- const ret = cachedTextEncoder.encodeInto(arg, view);
479
-
480
- offset += ret.written;
481
- ptr = realloc(ptr, len, offset, 1) >>> 0;
482
- }
483
-
484
- WASM_VECTOR_LEN = offset;
485
- return ptr;
486
- }
487
-
488
- function takeFromExternrefTable0(idx) {
489
- const value = wasm.__wbindgen_externrefs.get(idx);
490
- wasm.__externref_table_dealloc(idx);
491
- return value;
492
- }
493
-
494
- let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
495
- cachedTextDecoder.decode();
496
- const MAX_SAFARI_DECODE_BYTES = 2146435072;
497
- let numBytesDecoded = 0;
498
- function decodeText(ptr, len) {
499
- numBytesDecoded += len;
500
- if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
501
- cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
502
- cachedTextDecoder.decode();
503
- numBytesDecoded = len;
504
- }
505
- return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
506
- }
507
-
508
- const cachedTextEncoder = new TextEncoder();
509
-
510
- if (!('encodeInto' in cachedTextEncoder)) {
511
- cachedTextEncoder.encodeInto = function (arg, view) {
512
- const buf = cachedTextEncoder.encode(arg);
513
- view.set(buf);
514
- return {
515
- read: arg.length,
516
- written: buf.length
517
- };
518
- };
519
- }
520
-
521
- let WASM_VECTOR_LEN = 0;
522
-
523
-
524
- let wasm;
525
- export function __wbg_set_wasm(val) {
526
- wasm = val;
527
- }
package/errors.d.ts DELETED
@@ -1,5 +0,0 @@
1
- /** Thrown when an operation is called before `initWasm()` completes. */
2
- export declare class WasmNotInitializedError extends Error {
3
- /** Discriminant for branded error handling — always `'WasmNotInitializedError'`. */
4
- readonly kind: 'WasmNotInitializedError';
5
- }
package/errors.js DELETED
@@ -1,10 +0,0 @@
1
- /** Thrown when an operation is called before `initWasm()` completes. */
2
- export class WasmNotInitializedError extends Error {
3
- /** Discriminant for branded error handling — always `'WasmNotInitializedError'`. */
4
- kind = 'WasmNotInitializedError';
5
-
6
- constructor() {
7
- super('WASM not initialized. Call initWasm() first.');
8
- this.name = 'WasmNotInitializedError';
9
- }
10
- }
package/init.d.ts DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * Initialize WASM. Call once before using any WASM functions.
3
- *
4
- * @param wasmModule - pass a precompiled WebAssembly.Module in Workers, omit in browser
5
- */
6
- export function initWasm(wasmModule?: WebAssembly.Module): Promise<void>;
7
-
8
- /**
9
- * True if WASM has been initialized via `initWasm()`.
10
- */
11
- export function isInitialized(): boolean;
package/init.js DELETED
@@ -1,27 +0,0 @@
1
- import init from './canaad_wasm.js';
2
-
3
- let initialized = false;
4
- let initPromise = null;
5
-
6
- /**
7
- * Initialize WASM. Call once before using any WASM functions.
8
- *
9
- * @param {WebAssembly.Module | undefined} wasmModule - pass a precompiled module in Workers, omit in browser
10
- */
11
- export async function initWasm(wasmModule) {
12
- if (initialized) return;
13
- if (initPromise) return initPromise;
14
-
15
- initPromise = init(wasmModule).then(() => {
16
- initialized = true;
17
- });
18
-
19
- return initPromise;
20
- }
21
-
22
- /**
23
- * True if WASM has been initialized via `initWasm()`.
24
- */
25
- export function isInitialized() {
26
- return initialized;
27
- }
package/meta.d.ts DELETED
@@ -1,27 +0,0 @@
1
- import { z } from 'zod';
2
-
3
- /** Validates and parses all AAD action inputs. */
4
- export declare const inputSchema: z.ZodType;
5
-
6
- /** Validates and parses all AAD action outputs. */
7
- export declare const outputSchema: z.ZodType;
8
-
9
- /** Discriminated union of all action input shapes. */
10
- export type CanaadInput = z.infer<typeof inputSchema>;
11
-
12
- /** Discriminated union of all action output shapes. */
13
- export type CanaadOutput = z.infer<typeof outputSchema>;
14
-
15
- /** Tool metadata: id, name, slug, description, category, execution type, positional args, schemas, and optional registry links. */
16
- export declare const meta: {
17
- id: string;
18
- name: string;
19
- slug: string;
20
- description: string;
21
- category: string;
22
- executionType: string;
23
- positionalArgs: { order: string[]; required: number };
24
- packages?: { npm?: string; crates?: string };
25
- inputSchema: typeof inputSchema;
26
- outputSchema: typeof outputSchema;
27
- };
package/meta.js DELETED
@@ -1,61 +0,0 @@
1
- import { z } from 'zod';
2
-
3
- // AAD spec: tenant field capped at 256 UTF-8 bytes.
4
- const TENANT_MAX_BYTES = 256;
5
- // AAD spec: resource field capped at 1024 UTF-8 bytes.
6
- const RESOURCE_MAX_BYTES = 1024;
7
- const encoder = new TextEncoder();
8
-
9
- const extensionSchema = z.object({
10
- key: z.string().regex(/^x_[a-z]+_[a-z_]+$/),
11
- value: z.union([z.string(), z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER)]),
12
- });
13
-
14
- export const inputSchema = z.discriminatedUnion('action', [
15
- z.object({
16
- action: z.literal('canonicalize'),
17
- input: z.string(),
18
- outputFormat: z.enum(['bytes', 'string']).default('string'),
19
- }),
20
- z.object({
21
- action: z.literal('validate'),
22
- input: z.string(),
23
- }),
24
- z.object({
25
- action: z.literal('hash'),
26
- input: z.string(),
27
- outputFormat: z.enum(['hex', 'base64']).default('hex'),
28
- }),
29
- z.object({
30
- action: z.literal('build'),
31
- tenant: z.string().min(1).refine(s => encoder.encode(s).length <= TENANT_MAX_BYTES, `tenant exceeds ${TENANT_MAX_BYTES} bytes`),
32
- resource: z.string().min(1).refine(s => encoder.encode(s).length <= RESOURCE_MAX_BYTES, `resource exceeds ${RESOURCE_MAX_BYTES} bytes`),
33
- purpose: z.string().min(1),
34
- timestamp: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional(),
35
- extensions: z.array(extensionSchema).optional(),
36
- outputFormat: z.enum(['bytes', 'string']).default('string'),
37
- }),
38
- ]);
39
-
40
- export const outputSchema = z.discriminatedUnion('action', [
41
- z.object({ action: z.literal('canonicalize'), output: z.union([z.string(), z.array(z.number())]), outputFormat: z.enum(['bytes', 'string']) }),
42
- z.object({ action: z.literal('validate'), valid: z.boolean() }),
43
- z.object({ action: z.literal('hash'), hash: z.string(), outputFormat: z.enum(['hex', 'base64']) }),
44
- z.object({ action: z.literal('build'), output: z.union([z.string(), z.array(z.number())]), outputFormat: z.enum(['bytes', 'string']) }),
45
- ]);
46
-
47
- export const meta = {
48
- id: 'canaad',
49
- name: 'canaad',
50
- slug: 'canaad',
51
- description: 'canonicalize JSON for AAD (Additional Authenticated Data) per RFC 8785',
52
- category: 'crypto',
53
- executionType: 'hybrid',
54
- positionalArgs: { order: ['action', 'input'], required: 1 },
55
- packages: {
56
- npm: '@gnufoo/canaad',
57
- crates: 'canaad-core',
58
- },
59
- inputSchema,
60
- outputSchema,
61
- };
package/tool.d.ts DELETED
@@ -1,14 +0,0 @@
1
- import type { meta, CanaadInput, CanaadOutput } from './meta.js';
2
- import type { initWasm, isInitialized } from './init.js';
3
-
4
- /**
5
- * Main tool export. Merges AAD metadata with WASM lifecycle methods and the action dispatcher.
6
- */
7
- export declare const toolDefinition: typeof meta & {
8
- initWasm: typeof initWasm;
9
- isInitialized: typeof isInitialized;
10
- /** Dispatches an AAD action to WASM. Requires prior `initWasm()` call. */
11
- execute(input: CanaadInput): Promise<CanaadOutput>;
12
- };
13
-
14
- export { WasmNotInitializedError } from './errors.js';
package/tool.js DELETED
@@ -1,50 +0,0 @@
1
- import { meta, inputSchema } from './meta.js';
2
- import { initWasm, isInitialized } from './init.js';
3
- import { canonicalize, canonicalizeString, hash, validate, AadBuilder } from './canaad_wasm.js';
4
- import { WasmNotInitializedError } from './errors.js';
5
- const bytesToHex = (bytes) => Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
6
- const bytesToBase64 = (bytes) => globalThis.btoa(String.fromCharCode(...bytes));
7
- /**
8
- * Main tool export. Merges AAD metadata with WASM lifecycle methods and the action dispatcher.
9
- */
10
- export const toolDefinition = {
11
- ...meta,
12
- initWasm,
13
- isInitialized,
14
-
15
- /**
16
- * Dispatches an AAD action to WASM. Requires prior `initWasm()` call.
17
- */
18
- async execute(rawInput) {
19
- if (!isInitialized()) {
20
- throw new WasmNotInitializedError();
21
- }
22
- const input = inputSchema.parse(rawInput);
23
- switch (input.action) {
24
- case 'canonicalize': {
25
- if (input.outputFormat === 'bytes') {
26
- return { action: 'canonicalize', output: Array.from(canonicalize(input.input)), outputFormat: 'bytes' };
27
- }
28
- return { action: 'canonicalize', output: canonicalizeString(input.input), outputFormat: 'string' };
29
- }
30
- case 'validate':
31
- return { action: 'validate', valid: validate(input.input) };
32
- case 'hash': {
33
- const h = hash(input.input);
34
- return { action: 'hash', hash: input.outputFormat === 'base64' ? bytesToBase64(h) : bytesToHex(h), outputFormat: input.outputFormat };
35
- }
36
- case 'build': {
37
- let b = new AadBuilder().tenant(input.tenant).resource(input.resource).purpose(input.purpose);
38
- if (input.timestamp !== undefined) b = b.timestamp(input.timestamp);
39
- for (const ext of input.extensions || []) {
40
- b = typeof ext.value === 'string' ? b.extensionString(ext.key, ext.value) : b.extensionInt(ext.key, ext.value);
41
- }
42
- if (input.outputFormat === 'bytes') {
43
- return { action: 'build', output: Array.from(b.build()), outputFormat: 'bytes' };
44
- }
45
- return { action: 'build', output: b.buildString(), outputFormat: 'string' };
46
- }
47
- }
48
- },
49
- };
50
- export { WasmNotInitializedError } from './errors.js';