@charter-agreement-protocol/signer 0.2.1 → 0.3.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/dist/signer.js CHANGED
@@ -1,180 +1,289 @@
1
1
  // CAP never authorizes.
2
- //
3
- // The holder-side companion signer for the Charter Agreement Protocol,
4
- // ported from the Elixir reference (charter_agreement_signer). The caller
5
- // owns key custody through a handle object with two callbacks:
6
- //
7
- // keyIdentity(handle) -> { kid, publicKey } // ONE atomic snapshot
8
- // sign(message, handle) -> signature bytes // the holder's job
9
- //
10
- // Framing, the producer claims gate, the honest-signer refusal guards
11
- // (R1–R3), and assembly are ALL the verifier package's producer surface —
12
- // exactly one implementation, exactly the reference signer's delegation.
13
- // This package adds the custody half: the atomic key snapshot, the sign
14
- // callback, the wrong-key guard against the snapshot's public key, and the
15
- // post-sign verification of the assembled artifact. It never verifies
16
- // third-party artifacts, never transports, never persists, and never sees
17
- // a private key.
18
- import { acceptanceSigningInput, algorithmRegistry, assembleCompact, descriptorSigningInput, receiptSigningInput, terminationSigningInput, verifyAcceptance, verifyChain, verifyDescriptor, verifyReceipt, verifySignature, verifyTermination, } from "@charter-agreement-protocol/verifier";
19
- function registryRow(algorithm) {
20
- return algorithmRegistry().find((row) => row.name === algorithm) ?? null;
2
+ // The holder supplies one key snapshot and signs the verifier's prepared
3
+ // message. The verifier owns framing, claims, context, limits, profile,
4
+ // key matching, assembly, and completion. This package keeps custody and
5
+ // the wrong-key guard.
6
+ import { DEFAULT_LIMITS, algorithmRegistry, MAXIMUM_LIMITS, defaultEmissionName, decodeCharterRevision, emissions, finishSigning, prepareSigning, verifySignature, } from "@charter-agreement-protocol/verifier";
7
+ const COPY_LIMIT = Symbol("copy limit");
8
+ // Read one child at a time without recursion or array constructor hooks.
9
+ // Only ancestors are retained, so repeated objects get separate copies.
10
+ function copyClaims(value) {
11
+ const limits = MAXIMUM_LIMITS;
12
+ const ancestors = new WeakSet();
13
+ const frames = [];
14
+ let bytes = 0;
15
+ const addBytes = (size) => {
16
+ bytes += size;
17
+ if (bytes > limits.max_bytes)
18
+ throw COPY_LIMIT;
19
+ };
20
+ const stringBytes = (text) => {
21
+ if (Buffer.byteLength(text) > limits.max_string_bytes)
22
+ throw COPY_LIMIT;
23
+ return Buffer.byteLength(JSON.stringify(text));
24
+ };
25
+ const copy = (item, depth) => {
26
+ if (item === null || typeof item === "boolean") {
27
+ addBytes(item === null || item === true ? 4 : 5);
28
+ return item;
29
+ }
30
+ if (typeof item === "string") {
31
+ addBytes(stringBytes(item));
32
+ return item;
33
+ }
34
+ if (typeof item === "number" && Number.isFinite(item)) {
35
+ addBytes(JSON.stringify(item).length);
36
+ return item;
37
+ }
38
+ if (typeof item !== "object" || ancestors.has(item))
39
+ throw new TypeError("invalid_type");
40
+ if (depth + 1 > limits.max_depth)
41
+ throw COPY_LIMIT;
42
+ const array = Array.isArray(item);
43
+ let keys = null;
44
+ if (!array) {
45
+ const prototype = Object.getPrototypeOf(item);
46
+ if ((prototype !== Object.prototype && prototype !== null) || Object.getOwnPropertySymbols(item).length > 0) {
47
+ throw new TypeError("invalid_type");
48
+ }
49
+ keys = Object.keys(item);
50
+ }
51
+ const size = array ? item.length : keys.length;
52
+ if (!Number.isSafeInteger(size) || size < 0 || array && size > 2 ** 32 - 1)
53
+ throw new TypeError("invalid_type");
54
+ if (size > (array ? limits.max_array_items : limits.max_object_members)) {
55
+ throw COPY_LIMIT;
56
+ }
57
+ addBytes(2 + Math.max(0, size - 1));
58
+ const target = array ? [] : Object.create(null);
59
+ ancestors.add(item);
60
+ frames.push({ source: item, target, keys, size, index: 0, depth: depth + 1 });
61
+ return target;
62
+ };
63
+ const result = copy(value, 0);
64
+ while (frames.length > 0) {
65
+ const frame = frames[frames.length - 1];
66
+ if (frame.index === frame.size) {
67
+ ancestors.delete(frame.source);
68
+ frames.pop();
69
+ continue;
70
+ }
71
+ const index = frame.index++;
72
+ const key = frame.keys ? frame.keys[index] : String(index);
73
+ if (frame.keys)
74
+ addBytes(stringBytes(key) + 1);
75
+ const child = frame.source[key];
76
+ const copied = copy(child, frame.depth);
77
+ if (Array.isArray(frame.target))
78
+ frame.target.push(copied);
79
+ else
80
+ frame.target[key] = copied;
81
+ }
82
+ return result;
83
+ }
84
+ function copyChainView(chain) {
85
+ const names = ["revisions", "acceptances", "descriptors", "terminations"];
86
+ const lists = Object.fromEntries(names.map((name) => [name, (value) => copyTextList(value, MAXIMUM_LIMITS.max_artifact_set_items + 1)]));
87
+ return optionMembers(chain, names, lists);
21
88
  }
22
89
  async function resolveKeyIdentity(handle) {
23
- if (handle === null || typeof handle !== "object" || !("keyIdentity" in handle)) {
24
- return { error: "invalid_handle" };
25
- }
26
90
  try {
91
+ if (handle === null || typeof handle !== "object")
92
+ return { error: "invalid_key_handle" };
27
93
  const snapshot = await handle.keyIdentity(handle);
28
- if (snapshot &&
29
- typeof snapshot.kid === "string" &&
30
- snapshot.kid.length > 0 &&
31
- typeof snapshot.publicKey === "string" &&
32
- Buffer.from(snapshot.publicKey, "base64url").length > 0) {
33
- return snapshot;
94
+ if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot))
95
+ return { error: "invalid_key_handle" };
96
+ const { kid, publicKey } = snapshot;
97
+ if (typeof kid !== "string" || kid.length === 0 || typeof publicKey !== "string") {
98
+ return { error: "invalid_key_handle" };
34
99
  }
35
- return { error: "invalid_handle" };
100
+ return { kid, publicKey };
36
101
  }
37
102
  catch (_fault) {
38
- return { error: "invalid_handle" };
103
+ return { error: "invalid_key_handle" };
104
+ }
105
+ }
106
+ const OPTION_KEYS = new Set(["algorithm", "limits", "profile"]);
107
+ const byteArrayTag = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Array.prototype), Symbol.toStringTag).get;
108
+ // Read the defined shape once, including inherited and nonenumerable members.
109
+ // Invalid member values stay opaque for the verifier to check synchronously.
110
+ function optionMembers(value, names, nested = {}) {
111
+ if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Number)
112
+ return value;
113
+ const source = value;
114
+ const result = Object.create(null);
115
+ const unknown = Object.keys(source).find((name) => !names.includes(name));
116
+ if (unknown !== undefined)
117
+ result[unknown] = null;
118
+ for (const name of names) {
119
+ const member = source[name];
120
+ if (member !== undefined || name in source)
121
+ result[name] = nested[name] ? nested[name](member) : member;
122
+ }
123
+ return result;
124
+ }
125
+ function optionAlgorithms(value) {
126
+ if (!Array.isArray(value))
127
+ return value;
128
+ const length = value.length;
129
+ if (!Number.isSafeInteger(length) || length < 0)
130
+ throw new TypeError("invalid_type");
131
+ // A unique registry subset cannot be longer than the registry. Retain an
132
+ // invalid length for the verifier without reading an unbounded caller list.
133
+ if (length > MAXIMUM_LIMITS.max_artifact_set_items)
134
+ return Array(MAXIMUM_LIMITS.max_artifact_set_items + 1);
135
+ if (length > algorithmRegistry().length)
136
+ return value;
137
+ const result = [];
138
+ for (let i = 0; i < length; i += 1)
139
+ result.push(value[i]);
140
+ return result;
141
+ }
142
+ function copyTextList(value, maximum = 2 ** 32 - 1) {
143
+ if (!Array.isArray(value))
144
+ return value;
145
+ const length = value.length;
146
+ // A plain array cannot represent a length above 2^32 - 1.
147
+ if (!Number.isSafeInteger(length) || length < 0 || length > 2 ** 32 - 1)
148
+ throw new TypeError("invalid_type");
149
+ const result = [];
150
+ for (let i = 0; i < Math.min(length, maximum); i += 1)
151
+ result.push(value[i]);
152
+ return result;
153
+ }
154
+ function checkOptions(settings) {
155
+ // Empty text always gives invalid_syntax after successful option checks.
156
+ // Every earlier code comes from the verifier, including copy failures.
157
+ const checked = decodeCharterRevision("", settings);
158
+ return !checked.ok && checked.code !== "invalid_syntax" ? { error: "invalid_input", code: checked.code } : null;
159
+ }
160
+ function signingOptions(opts, descriptor) {
161
+ try {
162
+ if (opts === null || typeof opts !== "object" || Array.isArray(opts) || opts instanceof Number) {
163
+ return { error: "invalid_input", code: "invalid_type" };
164
+ }
165
+ if (!Reflect.ownKeys(opts).every((key) => typeof key === "string" &&
166
+ (OPTION_KEYS.has(key) || descriptor && key === "predecessor"))) {
167
+ return { error: "invalid_input", code: "invalid_type" };
168
+ }
169
+ const supplied = opts;
170
+ const settings = {
171
+ limits: optionMembers(supplied.limits, Object.keys(DEFAULT_LIMITS)),
172
+ };
173
+ const limitsError = checkOptions(settings);
174
+ if (limitsError)
175
+ return limitsError;
176
+ settings.profile = optionMembers(supplied.profile, ["algorithms", "revisions"], {
177
+ algorithms: optionAlgorithms,
178
+ revisions: (range) => optionMembers(range, ["min", "max"]),
179
+ });
180
+ const profileError = checkOptions(settings);
181
+ if (profileError)
182
+ return profileError;
183
+ const algorithm = supplied.algorithm ?? defaultEmissionName();
184
+ if (typeof algorithm !== "string" || !Object.hasOwn(emissions(), algorithm)) {
185
+ return { error: "invalid_input", code: "algorithm_unsupported" };
186
+ }
187
+ if (!descriptor)
188
+ return { ...settings, algorithm };
189
+ const previous = supplied.predecessor;
190
+ const predecessor = optionMembers(previous, ["digest", "descriptor_digest", "lineage"], {
191
+ lineage: (value) => copyTextList(value),
192
+ });
193
+ return { ...settings, algorithm, predecessor: predecessor };
194
+ }
195
+ catch (fault) {
196
+ return { error: "invalid_input", code: fault === COPY_LIMIT ? "limit_exceeded" : "invalid_type" };
39
197
  }
40
198
  }
41
- // The shared custody tail (the reference signer's): identity snapshot ->
42
- // producer (framing, claims schema, R1-R3 refusals - one implementation,
43
- // in the verifier package) -> sign via the handle -> wrong-key guard.
44
- // A refusal or producer rejection never touches the key.
45
- async function signProduced(keyHandle, produce, opts) {
199
+ function prepareError(code) {
200
+ switch (code) {
201
+ case "signing_refused":
202
+ case "signing_key_mismatch":
203
+ return { error: "refused", code };
204
+ case "signing_key_invalid":
205
+ return { error: "invalid_key_handle" };
206
+ case "algorithm_unsupported_on_substrate":
207
+ return { error: "algorithm_unsupported_on_substrate" };
208
+ default:
209
+ return { error: "invalid_input", code };
210
+ }
211
+ }
212
+ async function signPrepared(kind, claims, keyHandle, context, opts) {
213
+ const options = signingOptions(opts, kind === "descriptor");
214
+ if ("error" in options)
215
+ return options;
216
+ let retained;
217
+ try {
218
+ retained = kind === "descriptor" ? options.predecessor ?? null :
219
+ typeof context === "string" ? context : copyChainView(context);
220
+ }
221
+ catch (fault) {
222
+ return { error: "invalid_input", code: fault === COPY_LIMIT ? "limit_exceeded" : "invalid_type" };
223
+ }
224
+ try {
225
+ // Caller limits belong to preparation. The entry guard only stops values
226
+ // beyond every JSON limit the verifier can accept.
227
+ claims = copyClaims(claims);
228
+ }
229
+ catch (fault) {
230
+ return { error: "invalid_input", code: fault === COPY_LIMIT ? "signing_input_invalid" : "invalid_type" };
231
+ }
46
232
  const snapshot = await resolveKeyIdentity(keyHandle);
47
233
  if ("error" in snapshot)
48
234
  return snapshot;
49
- const produced = produce(snapshot.kid, opts?.algorithm);
50
- if (!produced.ok) {
51
- // signing_refused is the honest-signer refusal; every other producer
52
- // code stays caller input.
53
- return produced.code === "signing_refused"
54
- ? { error: "refused", code: produced.code }
55
- : { error: "invalid_input", code: produced.code };
56
- }
57
- // The holder signs the exact message; a fault or a wrong-length result is
58
- // a signing failure, never a silent pass.
235
+ const prepared = prepareSigning(kind, snapshot.kid, claims, snapshot.publicKey, retained, {
236
+ algorithm: options.algorithm,
237
+ limits: options.limits,
238
+ profile: options.profile,
239
+ });
240
+ if (!prepared.ok)
241
+ return prepareError(prepared.code);
242
+ const input = prepared.plan.input;
59
243
  let signature;
60
244
  try {
61
- signature = await keyHandle.sign(produced.input.message, keyHandle);
245
+ signature = await keyHandle.sign(Buffer.from(input.message), keyHandle);
62
246
  }
63
247
  catch (_fault) {
64
248
  return { error: "signing_failed" };
65
249
  }
66
- if (!(signature instanceof Uint8Array) || signature.length === 0) {
250
+ if (!ArrayBuffer.isView(signature) || byteArrayTag.call(signature) !== "Uint8Array") {
67
251
  return { error: "signing_failed" };
68
252
  }
69
- const row = registryRow(produced.input.alg);
70
- if (!row || signature.length !== row.signatureBytes) {
253
+ let checkedSignature;
254
+ try {
255
+ checkedSignature = Buffer.from(signature);
256
+ }
257
+ catch (_signature) {
71
258
  return { error: "signing_failed" };
72
259
  }
73
- // The wrong-key guard: the signature MUST verify against the snapshot's
74
- // public key under the minted algorithm.
75
- if (!verifySignature(produced.input.message, Buffer.from(signature), snapshot.publicKey, produced.input.alg)) {
260
+ // The verifier's signature guard owns signature length checks.
261
+ if (!verifySignature(prepared.plan.input.message, checkedSignature, snapshot.publicKey, input.alg, {
262
+ limits: options.limits,
263
+ profile: options.profile,
264
+ })) {
76
265
  return { error: "signing_failed" };
77
266
  }
78
- return { input: produced.input, signature: Buffer.from(signature) };
79
- }
80
- // Assembly goes through the verifier's assembleCompact: registry-row
81
- // length, framing re-decode, size gate - never a local string join.
82
- function compactOrInvalid(signed) {
83
- const assembled = assembleCompact(signed.input, signed.signature);
84
- if (!assembled.ok)
85
- return { error: "invalid_input", code: assembled.code };
86
- return { compact: assembled.compact };
87
- }
88
- // The view's chain is THIS package's public contract (the producer surface
89
- // validates its depth); the shallow shape is policed here so the closed
90
- // error vocabulary holds regardless of which verifier revision resolves.
91
- // A verifier crash past this gate stays loud - never a misleading error.
92
- function chainViewOrInvalid(chain) {
93
- if (!chain || typeof chain !== "object" || Array.isArray(chain)) {
94
- return { error: "invalid_input", code: "signing_input_invalid" };
95
- }
96
- return chain;
97
- }
98
- // A missing view object is caller input like a missing chain: the closed
99
- // error, never a dereference throw.
100
- function viewChainOrInvalid(view) {
101
- if (!view || typeof view !== "object")
102
- return { error: "invalid_input", code: "signing_input_invalid" };
103
- return chainViewOrInvalid(view.chain);
267
+ const finished = finishSigning(prepared.plan, checkedSignature);
268
+ // No real-crypto path reaches this mapping after preparation and the
269
+ // custody guard succeed; keep it for a verifier completion error.
270
+ if (!finished.ok)
271
+ return { error: "verification_failed" };
272
+ return { compact: finished.compact };
104
273
  }
105
- // ---------------------------------------------------------------------------
106
- // Public signing surface
107
- // ---------------------------------------------------------------------------
108
274
  export async function signDescriptor(claims, keyHandle, opts = {}) {
109
- const signed = await signProduced(keyHandle, (kid, algorithm) => descriptorSigningInput(kid, claims, algorithm), opts);
110
- if ("error" in signed)
111
- return { ok: false, ...signed };
112
- const assembled = compactOrInvalid(signed);
113
- if ("error" in assembled)
114
- return { ok: false, ...assembled };
115
- const verified = verifyDescriptor(assembled.compact);
116
- if (!verified.ok)
117
- return { ok: false, error: "verification_failed" };
118
- return { ok: true, result: { descriptor: assembled.compact } };
275
+ const signed = await signPrepared("descriptor", claims, keyHandle, null, opts);
276
+ return "error" in signed ? { ok: false, ...signed } : { ok: true, result: { descriptor: signed.compact } };
119
277
  }
120
- export async function signReceipt(claims, keyHandle, chain, opts = {}) {
121
- // The issuing view is REQUIRED (the reference takes ChainFacts or a
122
- // CharterRevision, never none) and its discipline runs after the build,
123
- // before the key - the reference's context is a verified ChainFacts by
124
- // construction, so a TS view that fails the chain discipline is caller
125
- // input, never a burned key operation.
126
- const signed = await signProduced(keyHandle, (kid, algorithm) => {
127
- const built = receiptSigningInput(kid, claims, algorithm);
128
- if (!built.ok)
129
- return built;
130
- const resolved = chainViewOrInvalid(chain);
131
- if ("error" in resolved)
132
- return { ok: false, code: resolved.code };
133
- if (!verifyChain(resolved).ok)
134
- return { ok: false, code: "chain_invalid" };
135
- return built;
136
- }, opts);
137
- if ("error" in signed)
138
- return { ok: false, ...signed };
139
- const assembled = compactOrInvalid(signed);
140
- if ("error" in assembled)
141
- return { ok: false, ...assembled };
142
- const verified = verifyReceipt(assembled.compact, chain);
143
- if (!verified.ok)
144
- return { ok: false, error: "verification_failed" };
145
- return { ok: true, result: { receipt: assembled.compact } };
278
+ export async function signReceipt(claims, keyHandle, context, opts = {}) {
279
+ const signed = await signPrepared("receipt", claims, keyHandle, context, opts);
280
+ return "error" in signed ? { ok: false, ...signed } : { ok: true, result: { receipt: signed.compact } };
146
281
  }
147
- export async function signAcceptance(claims, keyHandle, view, opts = {}) {
148
- const viewChain = viewChainOrInvalid(view);
149
- const signed = await signProduced(keyHandle, (kid, algorithm) => {
150
- if ("error" in viewChain)
151
- return { ok: false, code: viewChain.code };
152
- return acceptanceSigningInput(kid, claims, viewChain, algorithm);
153
- }, opts);
154
- if ("error" in signed)
155
- return { ok: false, ...signed };
156
- const assembled = compactOrInvalid(signed);
157
- if ("error" in assembled)
158
- return { ok: false, ...assembled };
159
- const verified = verifyAcceptance(assembled.compact, view.revisionText, view.descriptorCompacts);
160
- if (!verified.ok)
161
- return { ok: false, error: "verification_failed" };
162
- return { ok: true, result: { acceptance: assembled.compact } };
282
+ export async function signAcceptance(claims, keyHandle, chain, opts = {}) {
283
+ const signed = await signPrepared("acceptance", claims, keyHandle, chain, opts);
284
+ return "error" in signed ? { ok: false, ...signed } : { ok: true, result: { acceptance: signed.compact } };
163
285
  }
164
- export async function signTermination(claims, keyHandle, view, opts = {}) {
165
- const viewChain = viewChainOrInvalid(view);
166
- const signed = await signProduced(keyHandle, (kid, algorithm) => {
167
- if ("error" in viewChain)
168
- return { ok: false, code: viewChain.code };
169
- return terminationSigningInput(kid, claims, viewChain, algorithm);
170
- }, opts);
171
- if ("error" in signed)
172
- return { ok: false, ...signed };
173
- const assembled = compactOrInvalid(signed);
174
- if ("error" in assembled)
175
- return { ok: false, ...assembled };
176
- const verified = verifyTermination(assembled.compact, view.revisionText, view.descriptorCompacts);
177
- if (!verified.ok)
178
- return { ok: false, error: "verification_failed" };
179
- return { ok: true, result: { termination: assembled.compact } };
286
+ export async function signTermination(claims, keyHandle, chain, opts = {}) {
287
+ const signed = await signPrepared("termination", claims, keyHandle, chain, opts);
288
+ return "error" in signed ? { ok: false, ...signed } : { ok: true, result: { termination: signed.compact } };
180
289
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@charter-agreement-protocol/signer",
3
- "version": "0.2.1",
4
- "description": "Holder-side companion signer for the Charter Agreement Protocol (CAP) in TypeScript - key custody only: an atomic key snapshot, the sign callback, the wrong-key guard, and post-sign verification, with framing, the claims gate, the R1-R3 honest-signer refusals, and assembly all delegated to the @charter-agreement-protocol/verifier producer surface. CAP verifies; it never authorizes; this signer signs, it never verifies third-party artifacts or takes custody.",
3
+ "version": "0.3.0",
4
+ "description": "Holder-side companion signer for the Charter Agreement Protocol (CAP) in TypeScript - key custody only: an atomic key snapshot, the sign callback, the wrong-key guard, and post-sign verification, with framing, claims, context, key matching, limits, profile, and completion delegated to the @charter-agreement-protocol/verifier pre-sign API. CAP verifies; it never authorizes; this signer signs, it never verifies third-party artifacts or takes custody.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -15,32 +15,37 @@
15
15
  },
16
16
  "files": [
17
17
  "CHANGELOG.md",
18
+ "CODE_OF_CONDUCT.md",
19
+ "CONTRIBUTING.md",
18
20
  "dist",
19
21
  "LICENSE",
20
22
  "NOTICE",
21
- "README.md"
23
+ "README.md",
24
+ "SECURITY.md"
22
25
  ],
23
26
  "engines": {
24
27
  "node": ">=24.8.0"
25
28
  },
26
29
  "scripts": {
27
- "build": "tsc -p tsconfig.build.json",
30
+ "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json",
28
31
  "typecheck": "tsc --noEmit",
29
- "test": "node --test --experimental-strip-types --no-warnings signer.test.ts",
32
+ "test": "node --test --experimental-strip-types --no-warnings signer.test.ts signer.browser.test.ts signer.cases.test.ts",
33
+ "test:cost": "node --test --experimental-strip-types --no-warnings signer.cost.test.ts",
34
+ "test:cases": "node --test --experimental-strip-types --no-warnings signer.cases.test.ts",
30
35
  "prepack": "npm run build",
31
36
  "typecheck:web": "tsc -p tsconfig.web.json",
32
37
  "build:site": "node web/build.mjs && esbuild web/main.ts --bundle --minify --format=iife --target=es2022 --outfile=site-dist/app.js --alias:node:crypto=./web/shim/node-crypto.ts --alias:node:fs=./web/shim/node-fs.ts --alias:node:path=./web/shim/node-path.ts --inject:./web/shim/buffer-global.ts"
33
38
  },
34
39
  "dependencies": {
35
- "@charter-agreement-protocol/verifier": "^0.5.0"
40
+ "@charter-agreement-protocol/verifier": "^0.7.0"
36
41
  },
37
42
  "devDependencies": {
38
43
  "@noble/ed25519": "^3.2.0",
39
44
  "@noble/hashes": "^2.4.0",
40
- "@types/node": "^26.5.1",
45
+ "@types/node": "^26.6.4",
41
46
  "buffer": "^6.0.3",
42
47
  "esbuild": "^0.28.2",
43
- "typescript": "~5.9.0"
48
+ "typescript": "^7.0.2"
44
49
  },
45
50
  "repository": {
46
51
  "type": "git",