@interop/did-method-webvh 3.2.0 → 3.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/witness.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { concatBuffers } from './utils/buffer.js';
2
2
  import { canonicalizeStrict } from './utils/canonicalize.js';
3
3
  import { createHash } from './utils/crypto.js';
4
- import { multibaseDecode } from './utils/multiformats.js';
4
+ import { isEd25519Multikey, multibaseDecode } from './utils/multiformats.js';
5
5
  import { fetchWitnessProofs, parseDidKeyDid, parseDidKeyVerificationMethod, resolveVM } from './utils.js';
6
6
  function createWitnessProofSigner(signer) {
7
7
  return async (document, proofTemplate) => {
@@ -44,19 +44,21 @@ export async function createWitnessProof(signer, versionId, verificationMethod,
44
44
  };
45
45
  // Strip undefined fields to keep the proof JSON-compatible.
46
46
  const sanitizedProof = JSON.parse(JSON.stringify(mergedProof));
47
- if (!sanitizedProof.verificationMethod) {
47
+ const verificationMethodValue = mergedProof.verificationMethod;
48
+ if (!verificationMethodValue) {
48
49
  throw new Error('Witness proof is missing verificationMethod');
49
50
  }
50
- if (!sanitizedProof.proofValue) {
51
+ const proofValue = mergedProof.proofValue;
52
+ if (!proofValue) {
51
53
  throw new Error('Witness proof is missing proofValue');
52
54
  }
53
55
  return {
54
56
  id: sanitizedProof.id,
55
57
  type: sanitizedProof.type ?? proofTemplate.type,
56
58
  cryptosuite: sanitizedProof.cryptosuite ?? proofTemplate.cryptosuite,
57
- verificationMethod: sanitizedProof.verificationMethod,
59
+ verificationMethod: verificationMethodValue,
58
60
  created: sanitizedProof.created ?? proofTemplate.created,
59
- proofValue: sanitizedProof.proofValue,
61
+ proofValue,
60
62
  proofPurpose: sanitizedProof.proofPurpose ?? proofTemplate.proofPurpose,
61
63
  };
62
64
  }
@@ -130,6 +132,11 @@ export function validateWitnessParameter(witness) {
130
132
  throw new Error('Witness DIDs must be did:key format');
131
133
  }
132
134
  })();
135
+ // did:webvh v1.0 requires witness keys to be Ed25519 multikeys.
136
+ const keyBytes = multibaseDecode(parsedDid.keyMultibase).bytes;
137
+ if (!isEd25519Multikey(keyBytes)) {
138
+ throw new Error(`Witness DID key type must be Ed25519 (multicodec 0xed01): ${w.id}`);
139
+ }
133
140
  if (ids.has(parsedDid.did)) {
134
141
  throw new Error(`Duplicate witness id: ${w.id}`);
135
142
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@interop/did-method-webvh",
3
3
  "type": "module",
4
- "version": "3.2.0",
4
+ "version": "3.3.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -29,7 +29,6 @@
29
29
  "test:bail": "rm -rf ./test/logs && NODE_ENV=test vitest --bail=1",
30
30
  "test:coverage": "rm -rf ./test/logs && NODE_ENV=test vitest run --coverage",
31
31
  "test:log": "mkdir -p ./test/logs && rm -rf ./test/logs/* && LOG_RESOLVES=true NODE_ENV=test vitest run > ./test/logs/test-run.txt 2>&1",
32
- "cli": "tsx src/cli.ts",
33
32
  "build": "npm run build:clean && tsc",
34
33
  "build:clean": "rm -rf dist",
35
34
  "check": "tsc --noEmit --project tsconfig.dev.json",
@@ -38,6 +37,7 @@
38
37
  },
39
38
  "devDependencies": {
40
39
  "@biomejs/biome": "^2.3.6",
40
+ "@stablelib/ed25519": "^2.1.0",
41
41
  "@types/node": "^22.10.0",
42
42
  "@vitest/coverage-v8": "^4.1.8",
43
43
  "tsx": "^4.19.0",
@@ -46,12 +46,8 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "@noble/hashes": "^2.2.0",
49
- "@stablelib/ed25519": "^2.1.0",
50
49
  "json-canonicalize": "^2.0.0"
51
50
  },
52
- "bin": {
53
- "didwebvh": "./dist/cli.js"
54
- },
55
51
  "publishConfig": {
56
52
  "access": "public",
57
53
  "provenance": true
package/dist/cli.d.ts DELETED
@@ -1,21 +0,0 @@
1
- #!/usr/bin/env node
2
- import type { DIDLog } from './interfaces.js';
3
- export declare function handleCreate(args: string[]): Promise<{
4
- did: string;
5
- doc: import("./interfaces.js").DIDDoc;
6
- meta: import("./interfaces.js").DIDResolutionMeta;
7
- log: DIDLog;
8
- }>;
9
- export declare function handleResolve(args: string[]): Promise<{
10
- did: string;
11
- doc: any;
12
- meta: import("./interfaces.js").DIDResolutionMeta;
13
- }>;
14
- export declare function handleUpdate(args: string[]): Promise<import("./interfaces.js").UpdateDIDResult>;
15
- export declare function handleDeactivate(args: string[]): Promise<{
16
- did: string;
17
- doc: any;
18
- meta: import("./interfaces.js").DIDResolutionMeta;
19
- log: DIDLog;
20
- }>;
21
- export declare function main(): Promise<void>;
package/dist/cli.js DELETED
@@ -1,533 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'node:fs';
3
- import { dirname } from 'node:path';
4
- import { pathToFileURL } from 'node:url';
5
- import { parseEnv } from 'node:util';
6
- import { sign as ed25519Sign, verify as ed25519Verify, generateKeyPair } from '@stablelib/ed25519';
7
- import { createDID, deactivateDID, resolveDIDFromLog, updateDID } from './method.js';
8
- import { bufferToString, concatBuffers, createBuffer } from './utils/buffer.js';
9
- import { canonicalizeStrict } from './utils/canonicalize.js';
10
- import { createHash } from './utils/crypto.js';
11
- import { MultibaseEncoding, multibaseDecode, multibaseEncode } from './utils/multiformats.js';
12
- import { fetchLogFromIdentifier, parseDidKeyDid, readLogFromDisk, writeLogToDisk, writeVerificationMethodToEnv, } from './utils.js';
13
- import { signWitnessProofEntries } from './witness.js';
14
- const usage = `
15
- Usage: npm run cli -- [command] [options]
16
-
17
- Commands:
18
- create Create a new DID
19
- resolve Resolve a DID
20
- update Update an existing DID
21
- deactivate Deactivate an existing DID
22
- generate-witness-proof Generate witness proofs for a DID version
23
- generate-vm Generate a new verification method keypair
24
-
25
- Options:
26
- --address [address] Address for the DID (host, host:port, http://localhost, https://url, or did:webvh form) (required for create)
27
- --domain [domain] DEPRECATED: Use --address instead. Domain for the DID (backwards compatibility).
28
- --log [file] Path to the DID log file (required for resolve, update, deactivate)
29
- --output [file] Path to save the updated DID log (optional for create, update, deactivate)
30
- --portable Make the DID portable (optional for create)
31
- --witness [witness] Add a witness (can be used multiple times)
32
- --witness-threshold [n] Set witness threshold (optional, defaults to number of witnesses)
33
- --watcher [url] Add a watcher URL (can be used multiple times)
34
- --service [service] Add a service (format: type,endpoint) (can be used multiple times)
35
- --add-vm [type] Add a verification method (type can be authentication, assertionMethod, keyAgreement, capabilityInvocation, capabilityDelegation)
36
- --also-known-as [alias] Add an alsoKnownAs alias (can be used multiple times)
37
- --next-key-hash [hash] Add a nextKeyHash (can be used multiple times)
38
- --witness-file [file] Path to witness proofs file (optional for resolve)
39
-
40
- # Options for generate-witness-proof:
41
- --version-id [id] The version ID to generate proofs for (required, can be used multiple times)
42
- --witness-did [did] Witness DID (did:key) (can be used multiple times)
43
- --witness-secret [secret] Witness secret key multibase (matches witness-did order)
44
-
45
- Examples:
46
- npm run cli -- create --address example.com --portable --witness did:key:z6Mk... --witness did:key:z6Mk...
47
- npm run cli -- create --address https://example.com --portable
48
- npm run cli -- create --address "example.com:3000" --portable
49
- npm run cli -- create --address "did:webvh:example.com:3000" --portable
50
- npm run cli -- create --domain example.com --portable # DEPRECATED: use --address
51
- npm run cli -- resolve --did did:webvh:123456:example.com
52
- npm run cli -- resolve --log ./did.jsonl --witness-file ./did-witness.json
53
- npm run cli -- update --log ./did.jsonl --output ./updated-did.jsonl --add-vm keyAgreement --service LinkedDomains,https://example.com
54
- npm run cli -- deactivate --log ./did.jsonl --output ./deactivated-did.jsonl
55
- npm run cli -- generate-witness-proof --version-id 1-abc123 --witness-did did:key:z6Mk... --witness-secret z1A... --output did-witness.json
56
- npm run cli -- generate-witness-proof --version-id 1-abc123 --version-id 2-def456 --witness-did did:key:z6Mk... --witness-secret z1A... --output did-witness.json
57
- npm run cli -- generate-vm
58
- `;
59
- // Add this function at the top with the other constants
60
- function showHelp() {
61
- console.log(usage);
62
- }
63
- async function generateVerificationMethod(purpose = 'authentication') {
64
- const keyPair = generateKeyPair();
65
- const publicKeyBytes = new Uint8Array([0xed, 0x01, ...keyPair.publicKey]);
66
- const secretKeyBytes = new Uint8Array([0x80, 0x26, ...keyPair.secretKey]);
67
- return {
68
- type: 'Multikey',
69
- publicKeyMultibase: multibaseEncode(publicKeyBytes, MultibaseEncoding.BASE58_BTC),
70
- secretKeyMultibase: multibaseEncode(secretKeyBytes, MultibaseEncoding.BASE58_BTC),
71
- purpose,
72
- };
73
- }
74
- class CustomCryptoImplementation {
75
- verificationMethod;
76
- constructor(verificationMethod) {
77
- this.verificationMethod = verificationMethod;
78
- }
79
- getVerificationMethodId() {
80
- if (!this.verificationMethod) {
81
- throw new Error('Verification method not set');
82
- }
83
- return `did:key:${this.verificationMethod.publicKeyMultibase}#${this.verificationMethod.publicKeyMultibase}`;
84
- }
85
- async sign(input) {
86
- if (!this.verificationMethod) {
87
- throw new Error('Verification method not set');
88
- }
89
- if (!this.verificationMethod.secretKeyMultibase) {
90
- throw new Error('Secret key not set on verification method');
91
- }
92
- const { document, proof } = input;
93
- const dataHash = await createHash(canonicalizeStrict(document));
94
- const proofHash = await createHash(canonicalizeStrict(proof));
95
- const message = concatBuffers(proofHash, dataHash);
96
- const secretKey = multibaseDecode(this.verificationMethod.secretKeyMultibase).bytes.slice(2);
97
- const signature = ed25519Sign(secretKey, message);
98
- return {
99
- proofValue: multibaseEncode(signature, MultibaseEncoding.BASE58_BTC),
100
- };
101
- }
102
- async verify(signature, message, publicKey) {
103
- return ed25519Verify(publicKey, message, signature);
104
- }
105
- }
106
- function createCustomCrypto(verificationMethod) {
107
- return new CustomCryptoImplementation(verificationMethod);
108
- }
109
- export async function handleCreate(args) {
110
- const options = parseOptions(args);
111
- // Support both --address (new) and --domain (deprecated) options
112
- const addressInput = (options.address || options.domain);
113
- // Extract optional explicit paths (colon-delimited) from CLI args
114
- // If provided, these override any paths parsed from address input
115
- const explicitPaths = options.paths;
116
- const output = options.output;
117
- const portable = options.portable !== undefined;
118
- const nextKeyHashes = options['next-key-hash'];
119
- const witnesses = options.witness;
120
- const watchers = options.watcher;
121
- const witnessThreshold = options['witness-threshold']
122
- ? parseInt(options['witness-threshold'], 10)
123
- : (witnesses?.length ?? 0);
124
- if (!addressInput) {
125
- console.error('Address is required for create command (use --address or deprecated --domain)');
126
- process.exit(1);
127
- }
128
- try {
129
- const authKey = await generateVerificationMethod();
130
- if (!authKey.publicKeyMultibase) {
131
- throw new Error('Generated verification method is missing publicKeyMultibase');
132
- }
133
- const crypto = createCustomCrypto(authKey);
134
- // Strip secret key from verification method for DID document (security)
135
- const publicAuthKey = {
136
- id: authKey.id,
137
- type: authKey.type,
138
- controller: authKey.controller,
139
- publicKeyMultibase: authKey.publicKeyMultibase,
140
- purpose: authKey.purpose,
141
- };
142
- // Use new address parameter for strict parsing and encoding
143
- const { did, doc, meta, log } = await createDID({
144
- address: addressInput,
145
- paths: explicitPaths,
146
- signer: crypto,
147
- verifier: crypto,
148
- updateKeys: [authKey.publicKeyMultibase],
149
- verificationMethods: [publicAuthKey],
150
- portable,
151
- witness: witnesses?.length
152
- ? {
153
- witnesses: witnesses.map((witness) => ({ id: witness })),
154
- threshold: witnessThreshold,
155
- }
156
- : undefined,
157
- watchers: watchers ?? undefined,
158
- nextKeyHashes,
159
- });
160
- console.log('Created DID:', did);
161
- if (output) {
162
- // Ensure output directory exists
163
- const outputDir = dirname(output);
164
- if (!fs.existsSync(outputDir)) {
165
- fs.mkdirSync(outputDir, { recursive: true });
166
- }
167
- // Write log to file
168
- await writeLogToDisk(output, log);
169
- console.log(`DID log written to ${output}`);
170
- // Save verification method to env
171
- await writeVerificationMethodToEnv({
172
- ...authKey,
173
- controller: did,
174
- id: `${did}#${authKey.publicKeyMultibase?.slice(-8)}`,
175
- });
176
- console.log(`DID verification method saved to env`);
177
- }
178
- else {
179
- // If no output specified, print to console
180
- console.log('DID Document:', JSON.stringify(doc, null, 2));
181
- console.log('DID Log:', JSON.stringify(log, null, 2));
182
- }
183
- return { did, doc, meta, log };
184
- }
185
- catch (error) {
186
- console.error('Error creating DID:', error);
187
- process.exit(1);
188
- }
189
- }
190
- export async function handleResolve(args) {
191
- const options = parseOptions(args);
192
- const didIdentifier = options.did;
193
- const logFile = options.log;
194
- const witnessFile = options['witness-file'];
195
- if (!didIdentifier && !logFile) {
196
- console.error('Either --did or --log is required for resolve command');
197
- process.exit(1);
198
- }
199
- try {
200
- let log;
201
- if (logFile) {
202
- log = await readLogFromDisk(logFile);
203
- }
204
- else {
205
- log = await fetchLogFromIdentifier(didIdentifier);
206
- }
207
- const resolutionOptions = {};
208
- if (witnessFile) {
209
- const witnessProofs = JSON.parse(fs.readFileSync(witnessFile, 'utf8'));
210
- resolutionOptions.witnessProofs = witnessProofs;
211
- }
212
- const crypto = createCustomCrypto();
213
- resolutionOptions.verifier = crypto;
214
- console.time('Resolution time');
215
- const { did, doc, meta } = await resolveDIDFromLog(log, resolutionOptions);
216
- console.timeEnd('Resolution time');
217
- console.log('Resolved DID:', did);
218
- console.log('DID Document:', JSON.stringify(doc, null, 2));
219
- console.log('Metadata:', JSON.stringify(meta, null, 2));
220
- return { did, doc, meta };
221
- }
222
- catch (error) {
223
- console.error('Error resolving DID:', error);
224
- process.exit(1);
225
- }
226
- }
227
- export async function handleUpdate(args) {
228
- const options = parseOptions(args);
229
- const logFile = options.log;
230
- const output = options.output;
231
- const witnesses = options.witness;
232
- const witnessThreshold = options['witness-threshold']
233
- ? parseInt(options['witness-threshold'], 10)
234
- : undefined;
235
- const services = options.service ? parseServices(options.service) : undefined;
236
- const addVm = options['add-vm'];
237
- const alsoKnownAs = options['also-known-as'];
238
- const updateKey = options['update-key'];
239
- const watchers = options.watcher;
240
- if (!logFile) {
241
- console.error('Log file is required for update command');
242
- process.exit(1);
243
- }
244
- try {
245
- const log = await readLogFromDisk(logFile);
246
- const { did, meta } = await resolveDIDFromLog(log, { verifier: createCustomCrypto() });
247
- // console.log('\nCurrent DID:', did);
248
- // console.log('Current meta:', meta);
249
- // Get the verification method from environment
250
- const envVMs = JSON.parse(bufferToString(createBuffer(process.env.DID_VERIFICATION_METHODS || 'W10=', 'base64')));
251
- let vm = envVMs.find((vm) => vm.controller === did);
252
- if (!vm) {
253
- // Try to find VM by matching public key with current update keys
254
- vm = envVMs.find((vm) => meta.updateKeys.includes(vm.publicKeyMultibase));
255
- }
256
- if (!vm && envVMs.length > 0) {
257
- // Fall back to first available VM with warning
258
- console.warn('Warning: No matching verification method found for DID or update keys. Using first available VM.');
259
- vm = envVMs[0];
260
- }
261
- // console.log('\nFound VM:', vm);
262
- if (!vm) {
263
- throw new Error('No verification method found in environment');
264
- }
265
- if (!vm.publicKeyMultibase) {
266
- throw new Error('Verification method missing publicKeyMultibase');
267
- }
268
- // Create verification methods array
269
- const verificationMethods = [];
270
- // If we're adding VMs, create a VM for each type
271
- if (addVm && addVm.length > 0) {
272
- const vmId = `${did}#${vm.publicKeyMultibase?.slice(-8)}`;
273
- // Add a verification method for each type
274
- for (const vmType of addVm) {
275
- const newVM = {
276
- id: vmId,
277
- type: 'Multikey',
278
- controller: did,
279
- publicKeyMultibase: vm.publicKeyMultibase,
280
- purpose: vmType,
281
- };
282
- verificationMethods.push(newVM);
283
- }
284
- }
285
- else {
286
- // For non-VM updates (services, alsoKnownAs), still need a VM with purpose
287
- verificationMethods.push({
288
- id: `${did}#${vm.publicKeyMultibase?.slice(-8)}`,
289
- type: 'Multikey',
290
- controller: did,
291
- publicKeyMultibase: vm.publicKeyMultibase,
292
- purpose: 'assertionMethod',
293
- });
294
- }
295
- const crypto = createCustomCrypto(vm);
296
- const result = await updateDID({
297
- log,
298
- signer: crypto,
299
- verifier: crypto,
300
- updateKeys: [vm.publicKeyMultibase],
301
- verificationMethods,
302
- witness: witnesses?.length
303
- ? {
304
- witnesses: witnesses.map((witness) => ({ id: witness })),
305
- threshold: witnessThreshold ?? witnesses.length,
306
- }
307
- : undefined,
308
- watchers: watchers ?? undefined,
309
- services,
310
- alsoKnownAs,
311
- });
312
- if (output) {
313
- await writeLogToDisk(output, result.log);
314
- console.log(`Updated DID log written to ${output}`);
315
- }
316
- return result;
317
- }
318
- catch (error) {
319
- console.error('Error updating DID:', error);
320
- process.exit(1);
321
- }
322
- }
323
- export async function handleDeactivate(args) {
324
- const options = parseOptions(args);
325
- const logFile = options.log;
326
- const output = options.output;
327
- if (!logFile) {
328
- console.error('Log file is required for deactivate command');
329
- process.exit(1);
330
- }
331
- try {
332
- // Read the current log to get the latest state
333
- const log = await readLogFromDisk(logFile);
334
- const { did, meta } = await resolveDIDFromLog(log, { verifier: createCustomCrypto() });
335
- // Get the verification method from environment
336
- const envContent = fs.readFileSync('.env', 'utf8');
337
- const vmMatch = envContent.match(/DID_VERIFICATION_METHODS=(.+)/);
338
- if (!vmMatch) {
339
- throw new Error('No verification method found in .env file');
340
- }
341
- // Parse the VM from env
342
- const vms = JSON.parse(bufferToString(createBuffer(vmMatch[1], 'base64')));
343
- if (!vms || vms.length === 0) {
344
- throw new Error('No verification method found in environment');
345
- }
346
- // Find VM that matches the current update key
347
- let vm = vms.find((v) => v.publicKeyMultibase === meta.updateKeys[0]);
348
- if (!vm) {
349
- // If no matching VM found, use the first one and warn
350
- console.warn('Warning: No matching verification method found for current update key. Using first available VM.');
351
- vm = vms[0];
352
- }
353
- // Don't modify the publicKeyMultibase - it should match the secretKeyMultibase
354
- const crypto = createCustomCrypto(vm);
355
- const result = await deactivateDID({
356
- log,
357
- signer: crypto,
358
- verifier: crypto,
359
- });
360
- if (output) {
361
- await writeLogToDisk(output, result.log);
362
- console.log(`Deactivated DID log written to ${output}`);
363
- }
364
- return result;
365
- }
366
- catch (error) {
367
- console.error('Error deactivating DID:', error);
368
- process.exit(1);
369
- }
370
- }
371
- async function handleGenerateWitnessProof(args) {
372
- const options = parseOptions(args);
373
- const rawVersionIds = options['version-id'];
374
- const versionIds = Array.isArray(rawVersionIds) ? rawVersionIds : rawVersionIds ? [rawVersionIds] : [];
375
- const witnessDids = options['witness-did'];
376
- const witnessSecrets = options['witness-secret'];
377
- const output = options.output;
378
- if (versionIds.length === 0) {
379
- console.error('At least one --version-id is required');
380
- process.exit(1);
381
- }
382
- if (!output) {
383
- console.error('Output file is required');
384
- process.exit(1);
385
- }
386
- if (!witnessDids || !witnessSecrets || witnessDids.length !== witnessSecrets.length) {
387
- console.error('Must provide matching number of witness DIDs and secrets');
388
- process.exit(1);
389
- }
390
- const witnessSignersByDid = {};
391
- const witnesses = [];
392
- for (let i = 0; i < witnessDids.length; i++) {
393
- const did = witnessDids[i];
394
- const secret = witnessSecrets[i];
395
- const { did: normalizedDid, keyMultibase: publicKeyMultibase } = parseDidKeyDid(did);
396
- const vm = {
397
- type: 'Multikey',
398
- publicKeyMultibase,
399
- secretKeyMultibase: secret,
400
- purpose: 'authentication',
401
- };
402
- witnessSignersByDid[normalizedDid] = createCustomCrypto(vm);
403
- witnesses.push({ id: normalizedDid });
404
- }
405
- const witnessEntries = await signWitnessProofEntries(versionIds, witnesses, witnessSignersByDid);
406
- const witnessFileContent = witnessEntries.map((entry) => ({
407
- versionId: entry.versionId,
408
- proof: entry.proof,
409
- }));
410
- fs.writeFileSync(output, JSON.stringify(witnessFileContent, null, 2));
411
- console.log(`Witness proof file generated at ${output}`);
412
- }
413
- function parseOptions(args) {
414
- const options = {};
415
- for (let i = 0; i < args.length; i++) {
416
- if (args[i].startsWith('--')) {
417
- const key = args[i].slice(2);
418
- if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
419
- if (key === 'witness' ||
420
- key === 'service' ||
421
- key === 'also-known-as' ||
422
- key === 'next-key-hash' ||
423
- key === 'watcher' ||
424
- key === 'witness-did' ||
425
- key === 'witness-secret' ||
426
- key === 'version-id') {
427
- options[key] = options[key] || [];
428
- options[key].push(args[++i]);
429
- }
430
- else if (key === 'add-vm') {
431
- options[key] = options[key] || [];
432
- const value = args[++i];
433
- if (isValidVerificationMethodType(value)) {
434
- options[key].push(value);
435
- }
436
- else {
437
- console.error(`Invalid verification method type: ${value}`);
438
- process.exit(1);
439
- }
440
- }
441
- else {
442
- options[key] = args[++i];
443
- }
444
- }
445
- else {
446
- options[key] = '';
447
- }
448
- }
449
- }
450
- return options;
451
- }
452
- // Add this function to validate VerificationMethodType
453
- function isValidVerificationMethodType(type) {
454
- return ['authentication', 'assertionMethod', 'keyAgreement', 'capabilityInvocation', 'capabilityDelegation'].includes(type);
455
- }
456
- function parseServices(services) {
457
- return services.map((service) => {
458
- const [type, serviceEndpoint] = service.split(',');
459
- return { type, serviceEndpoint };
460
- });
461
- }
462
- // Load .env from the working directory, matching Bun's behavior:
463
- // values already present in process.env take precedence over .env values.
464
- function loadEnvFile() {
465
- try {
466
- const parsed = parseEnv(fs.readFileSync('.env', 'utf8'));
467
- for (const [key, value] of Object.entries(parsed)) {
468
- if (!(key in process.env)) {
469
- process.env[key] = value;
470
- }
471
- }
472
- }
473
- catch {
474
- // No .env file is fine
475
- }
476
- }
477
- // Update the main function to be exported
478
- export async function main() {
479
- loadEnvFile();
480
- const [command, ...args] = process.argv.slice(2);
481
- // console.log('Command:', command);
482
- // console.log('Args:', args);
483
- try {
484
- switch (command) {
485
- case 'create':
486
- console.log('Handling create command...');
487
- await handleCreate(args);
488
- break;
489
- case 'resolve':
490
- await handleResolve(args);
491
- break;
492
- case 'update':
493
- await handleUpdate(args);
494
- break;
495
- case 'deactivate':
496
- await handleDeactivate(args);
497
- break;
498
- case 'generate-witness-proof':
499
- await handleGenerateWitnessProof(args);
500
- break;
501
- case 'generate-vm': {
502
- const vm = await generateVerificationMethod('authentication');
503
- const publicKeyMultibase = vm.publicKeyMultibase;
504
- const did = `did:key:${publicKeyMultibase}`;
505
- console.log(JSON.stringify({
506
- did,
507
- publicKeyMultibase,
508
- secretKeyMultibase: vm.secretKeyMultibase,
509
- }, null, 2));
510
- break;
511
- }
512
- case 'help':
513
- showHelp();
514
- break;
515
- default:
516
- console.error('Unknown command:', command);
517
- showHelp();
518
- process.exit(1);
519
- }
520
- }
521
- catch (error) {
522
- console.error('Error:', error);
523
- process.exit(1);
524
- }
525
- }
526
- // Only run main if this file is being executed directly
527
- const isMain = process.argv[1] && import.meta.url === pathToFileURL(fs.realpathSync(process.argv[1])).href;
528
- if (isMain) {
529
- main().catch((error) => {
530
- console.error('Fatal error:', error);
531
- process.exit(1);
532
- });
533
- }