@moltdm/client 1.3.2 → 1.4.1

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/index.mjs CHANGED
@@ -1,27 +1,147 @@
1
1
  // src/index.ts
2
2
  import * as ed from "@noble/ed25519";
3
3
  import { x25519 } from "@noble/curves/ed25519";
4
- import * as fs from "fs";
5
- import * as path from "path";
6
- import * as os from "os";
7
- import { createHmac } from "crypto";
4
+ var MemoryStorage = class {
5
+ data = /* @__PURE__ */ new Map();
6
+ async get(key) {
7
+ return this.data.get(key) ?? null;
8
+ }
9
+ async set(key, value) {
10
+ this.data.set(key, value);
11
+ }
12
+ async delete(key) {
13
+ this.data.delete(key);
14
+ }
15
+ };
16
+ var BrowserStorage = class {
17
+ prefix;
18
+ constructor(prefix = "moltdm") {
19
+ this.prefix = prefix;
20
+ }
21
+ async get(key) {
22
+ if (typeof localStorage === "undefined") return null;
23
+ return localStorage.getItem(`${this.prefix}:${key}`);
24
+ }
25
+ async set(key, value) {
26
+ if (typeof localStorage === "undefined") return;
27
+ localStorage.setItem(`${this.prefix}:${key}`, value);
28
+ }
29
+ async delete(key) {
30
+ if (typeof localStorage === "undefined") return;
31
+ localStorage.removeItem(`${this.prefix}:${key}`);
32
+ }
33
+ };
34
+ var FileStorage = class {
35
+ basePath;
36
+ _fs = null;
37
+ _path = null;
38
+ _initialized = false;
39
+ constructor(basePath) {
40
+ this.basePath = basePath || ".moltdm";
41
+ }
42
+ async ensureModules() {
43
+ if (this._initialized) return;
44
+ if (typeof window !== "undefined") {
45
+ console.warn("FileStorage is not supported in browser. Use BrowserStorage instead.");
46
+ return;
47
+ }
48
+ try {
49
+ const fs = await import(
50
+ /* webpackIgnore: true */
51
+ "fs"
52
+ );
53
+ const path = await import(
54
+ /* webpackIgnore: true */
55
+ "path"
56
+ );
57
+ const os = await import(
58
+ /* webpackIgnore: true */
59
+ "os"
60
+ );
61
+ this._fs = fs;
62
+ this._path = path;
63
+ if (this.basePath === ".moltdm") {
64
+ const envPath = process.env.OPENCLAW_STATE_DIR;
65
+ this.basePath = envPath ? path.join(envPath, ".moltdm") : path.join(os.homedir(), ".moltdm");
66
+ }
67
+ if (!fs.existsSync(this.basePath)) {
68
+ fs.mkdirSync(this.basePath, { recursive: true });
69
+ }
70
+ this._initialized = true;
71
+ } catch (e) {
72
+ console.error("Failed to load Node.js modules for FileStorage:", e);
73
+ }
74
+ }
75
+ async get(key) {
76
+ await this.ensureModules();
77
+ if (!this._fs) return null;
78
+ const filePath = this._path.join(this.basePath, `${key}.json`);
79
+ if (!this._fs.existsSync(filePath)) return null;
80
+ return this._fs.readFileSync(filePath, "utf-8");
81
+ }
82
+ async set(key, value) {
83
+ await this.ensureModules();
84
+ if (!this._fs) return;
85
+ const filePath = this._path.join(this.basePath, `${key}.json`);
86
+ this._fs.writeFileSync(filePath, value);
87
+ }
88
+ async delete(key) {
89
+ await this.ensureModules();
90
+ if (!this._fs) return;
91
+ const filePath = this._path.join(this.basePath, `${key}.json`);
92
+ if (this._fs.existsSync(filePath)) {
93
+ this._fs.unlinkSync(filePath);
94
+ }
95
+ }
96
+ };
8
97
  function toBase64(bytes) {
9
- return Buffer.from(bytes).toString("base64");
98
+ if (typeof Buffer !== "undefined") {
99
+ return Buffer.from(bytes).toString("base64");
100
+ }
101
+ let binary = "";
102
+ for (let i = 0; i < bytes.length; i++) {
103
+ binary += String.fromCharCode(bytes[i]);
104
+ }
105
+ return btoa(binary);
10
106
  }
11
107
  function fromBase64(str) {
12
- return new Uint8Array(Buffer.from(str, "base64"));
108
+ if (typeof Buffer !== "undefined") {
109
+ return new Uint8Array(Buffer.from(str, "base64"));
110
+ }
111
+ const binary = atob(str);
112
+ const bytes = new Uint8Array(binary.length);
113
+ for (let i = 0; i < binary.length; i++) {
114
+ bytes[i] = binary.charCodeAt(i);
115
+ }
116
+ return bytes;
117
+ }
118
+ async function hmacSha256(key, data) {
119
+ const keyBuffer = new Uint8Array(key).buffer;
120
+ const dataBuffer = new Uint8Array(data).buffer;
121
+ const cryptoKey = await crypto.subtle.importKey(
122
+ "raw",
123
+ keyBuffer,
124
+ { name: "HMAC", hash: "SHA-256" },
125
+ false,
126
+ ["sign"]
127
+ );
128
+ const signature = await crypto.subtle.sign("HMAC", cryptoKey, dataBuffer);
129
+ return new Uint8Array(signature);
13
130
  }
14
131
  var MoltDMClient = class {
15
- storagePath;
132
+ storage;
16
133
  relayUrl;
17
134
  identity = null;
18
- // Our sender keys (for messages we send)
19
135
  senderKeys = /* @__PURE__ */ new Map();
20
- // Received sender keys (for messages from others) - keyed by `${convId}:${fromId}`
21
136
  receivedSenderKeys = /* @__PURE__ */ new Map();
22
137
  constructor(options = {}) {
23
- const defaultStoragePath = process.env.OPENCLAW_STATE_DIR ? path.join(process.env.OPENCLAW_STATE_DIR, ".moltdm") : path.join(os.homedir(), ".moltdm");
24
- this.storagePath = options.storagePath || defaultStoragePath;
138
+ if (options.storage) {
139
+ this.storage = options.storage;
140
+ } else if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
141
+ this.storage = new BrowserStorage();
142
+ } else {
143
+ this.storage = new FileStorage(options.storagePath);
144
+ }
25
145
  this.relayUrl = options.relayUrl || "https://relay.moltdm.com";
26
146
  if (options.identity) {
27
147
  this.identity = options.identity;
@@ -50,22 +170,30 @@ var MoltDMClient = class {
50
170
  // ============================================
51
171
  async initialize() {
52
172
  if (this.identity) {
173
+ this.validateIdentity(this.identity);
53
174
  await this.loadSenderKeys();
54
175
  return;
55
176
  }
56
- if (!fs.existsSync(this.storagePath)) {
57
- fs.mkdirSync(this.storagePath, { recursive: true });
58
- }
59
- const identityPath = path.join(this.storagePath, "identity.json");
60
- if (fs.existsSync(identityPath)) {
61
- const data = fs.readFileSync(identityPath, "utf-8");
62
- this.identity = JSON.parse(data);
177
+ const identityJson = await this.storage.get("identity");
178
+ if (identityJson) {
179
+ this.identity = JSON.parse(identityJson);
180
+ this.validateIdentity(this.identity);
63
181
  } else {
64
182
  await this.createIdentity();
65
- fs.writeFileSync(identityPath, JSON.stringify(this.identity, null, 2));
183
+ await this.storage.set("identity", JSON.stringify(this.identity));
66
184
  }
67
185
  await this.loadSenderKeys();
68
186
  }
187
+ validateIdentity(identity) {
188
+ if (!identity.signedPreKey?.privateKey) {
189
+ throw new Error(
190
+ "Identity is missing signedPreKey.privateKey. This moltbot was created with an older client version. Please delete your stored identity and re-register, or update your identity file to include the signedPreKey private key."
191
+ );
192
+ }
193
+ if (!identity.moltbotId || !identity.publicKey || !identity.privateKey) {
194
+ throw new Error("Identity is missing required fields (moltbotId, publicKey, or privateKey)");
195
+ }
196
+ }
69
197
  async createIdentity() {
70
198
  const privateKeyBytes = ed.utils.randomPrivateKey();
71
199
  const publicKeyBytes = await ed.getPublicKeyAsync(privateKeyBytes);
@@ -114,10 +242,9 @@ var MoltDMClient = class {
114
242
  };
115
243
  }
116
244
  async loadSenderKeys() {
117
- const keysPath = path.join(this.storagePath, "sender_keys.json");
118
- if (fs.existsSync(keysPath)) {
119
- const data = fs.readFileSync(keysPath, "utf-8");
120
- const keys = JSON.parse(data);
245
+ const keysJson = await this.storage.get("sender_keys");
246
+ if (keysJson) {
247
+ const keys = JSON.parse(keysJson);
121
248
  for (const [convId, keyData] of Object.entries(keys)) {
122
249
  const k = keyData;
123
250
  const chainKey = fromBase64(k.chainKey || k.key || "");
@@ -129,10 +256,9 @@ var MoltDMClient = class {
129
256
  });
130
257
  }
131
258
  }
132
- const receivedPath = path.join(this.storagePath, "received_sender_keys.json");
133
- if (fs.existsSync(receivedPath)) {
134
- const data = fs.readFileSync(receivedPath, "utf-8");
135
- const keys = JSON.parse(data);
259
+ const receivedJson = await this.storage.get("received_sender_keys");
260
+ if (receivedJson) {
261
+ const keys = JSON.parse(receivedJson);
136
262
  for (const [key, keyData] of Object.entries(keys)) {
137
263
  const k = keyData;
138
264
  this.receivedSenderKeys.set(key, {
@@ -144,7 +270,6 @@ var MoltDMClient = class {
144
270
  }
145
271
  }
146
272
  async saveSenderKeys() {
147
- const keysPath = path.join(this.storagePath, "sender_keys.json");
148
273
  const obj = {};
149
274
  for (const [convId, keyData] of this.senderKeys) {
150
275
  obj[convId] = {
@@ -154,8 +279,7 @@ var MoltDMClient = class {
154
279
  messageIndex: keyData.messageIndex
155
280
  };
156
281
  }
157
- fs.writeFileSync(keysPath, JSON.stringify(obj, null, 2));
158
- const receivedPath = path.join(this.storagePath, "received_sender_keys.json");
282
+ await this.storage.set("sender_keys", JSON.stringify(obj));
159
283
  const receivedObj = {};
160
284
  for (const [key, keyData] of this.receivedSenderKeys) {
161
285
  receivedObj[key] = {
@@ -164,7 +288,7 @@ var MoltDMClient = class {
164
288
  messageIndex: keyData.messageIndex
165
289
  };
166
290
  }
167
- fs.writeFileSync(receivedPath, JSON.stringify(receivedObj, null, 2));
291
+ await this.storage.set("received_sender_keys", JSON.stringify(receivedObj));
168
292
  }
169
293
  // ============================================
170
294
  // Sender Keys Protocol (Signal-style)
@@ -173,37 +297,25 @@ var MoltDMClient = class {
173
297
  * Derive message key from chain key using HMAC
174
298
  * message_key = HMAC-SHA256(chain_key, 0x01)
175
299
  */
176
- deriveMessageKey(chainKey) {
177
- const keyBuffer = Buffer.from(chainKey);
178
- const hmac = createHmac("sha256", keyBuffer);
179
- hmac.update(Buffer.from([1]));
180
- const digest = hmac.digest();
181
- const result = new Uint8Array(32);
182
- result.set(new Uint8Array(digest));
183
- return result;
300
+ async deriveMessageKey(chainKey) {
301
+ return hmacSha256(chainKey, new Uint8Array([1]));
184
302
  }
185
303
  /**
186
304
  * Ratchet chain key forward
187
305
  * new_chain_key = HMAC-SHA256(chain_key, 0x02)
188
306
  */
189
- ratchetChainKey(chainKey) {
190
- const keyBuffer = Buffer.from(chainKey);
191
- const hmac = createHmac("sha256", keyBuffer);
192
- hmac.update(Buffer.from([2]));
193
- const digest = hmac.digest();
194
- const result = new Uint8Array(32);
195
- result.set(new Uint8Array(digest));
196
- return result;
307
+ async ratchetChainKey(chainKey) {
308
+ return hmacSha256(chainKey, new Uint8Array([2]));
197
309
  }
198
310
  /**
199
311
  * Ratchet a chain key forward N steps (for catching up on missed messages)
200
312
  */
201
- ratchetChainKeyN(chainKey, steps) {
313
+ async ratchetChainKeyN(chainKey, steps) {
202
314
  const messageKeys = [];
203
315
  let current = chainKey;
204
316
  for (let i = 0; i < steps; i++) {
205
- messageKeys.push(this.deriveMessageKey(current));
206
- current = this.ratchetChainKey(current);
317
+ messageKeys.push(await this.deriveMessageKey(current));
318
+ current = await this.ratchetChainKey(current);
207
319
  }
208
320
  return { chainKey: current, messageKeys };
209
321
  }
@@ -297,27 +409,24 @@ var MoltDMClient = class {
297
409
  async send(conversationId, content, options) {
298
410
  this.ensureInitialized();
299
411
  let senderKeyState = this.senderKeys.get(conversationId);
300
- const isNewKey = !senderKeyState;
301
412
  if (!senderKeyState) {
302
413
  const initialKey = crypto.getRandomValues(new Uint8Array(32));
303
414
  senderKeyState = {
304
415
  chainKey: initialKey,
305
416
  initialChainKey: new Uint8Array(initialKey),
306
- // Copy for distribution
307
417
  version: 1,
308
418
  messageIndex: 0
309
419
  };
310
420
  this.senderKeys.set(conversationId, senderKeyState);
311
421
  }
312
- const messageKey = this.deriveMessageKey(senderKeyState.chainKey);
422
+ const messageKey = await this.deriveMessageKey(senderKeyState.chainKey);
313
423
  const currentIndex = senderKeyState.messageIndex;
314
- senderKeyState.chainKey = this.ratchetChainKey(senderKeyState.chainKey);
424
+ senderKeyState.chainKey = await this.ratchetChainKey(senderKeyState.chainKey);
315
425
  senderKeyState.messageIndex++;
316
426
  const ciphertext = await this.encrypt(content, messageKey);
317
427
  const encryptedSenderKeys = await this.encryptChainKeyForRecipients(
318
428
  conversationId,
319
429
  senderKeyState.initialChainKey
320
- // Send the original, unratcheted key
321
430
  );
322
431
  const response = await this.fetch(`/api/conversations/${conversationId}/messages`, {
323
432
  method: "POST",
@@ -369,26 +478,23 @@ var MoltDMClient = class {
369
478
  sharedSecretCopy.set(new Uint8Array(sharedSecret));
370
479
  const chainKeyCopy = new Uint8Array(32);
371
480
  chainKeyCopy.set(new Uint8Array(chainKey));
372
- const keyMaterial = await crypto.subtle.importKey(
373
- "raw",
374
- sharedSecretCopy.buffer,
375
- { name: "HKDF" },
376
- false,
377
- ["deriveKey"]
378
- );
481
+ const keyMaterial = await crypto.subtle.importKey("raw", sharedSecretCopy.buffer, { name: "HKDF" }, false, [
482
+ "deriveKey"
483
+ ]);
379
484
  const aesKey = await crypto.subtle.deriveKey(
380
- { name: "HKDF", hash: "SHA-256", salt: new Uint8Array(32), info: new TextEncoder().encode("moltdm-sender-key") },
485
+ {
486
+ name: "HKDF",
487
+ hash: "SHA-256",
488
+ salt: new Uint8Array(32),
489
+ info: new TextEncoder().encode("moltdm-sender-key")
490
+ },
381
491
  keyMaterial,
382
492
  { name: "AES-GCM", length: 256 },
383
493
  false,
384
494
  ["encrypt"]
385
495
  );
386
496
  const iv = crypto.getRandomValues(new Uint8Array(12));
387
- const encrypted = await crypto.subtle.encrypt(
388
- { name: "AES-GCM", iv },
389
- aesKey,
390
- chainKeyCopy.buffer
391
- );
497
+ const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, aesKey, chainKeyCopy.buffer);
392
498
  const combined = new Uint8Array(32 + 12 + encrypted.byteLength);
393
499
  combined.set(ephemeralPublic);
394
500
  combined.set(iv, 32);
@@ -408,7 +514,19 @@ var MoltDMClient = class {
408
514
  */
409
515
  async decryptChainKey(encryptedBlob) {
410
516
  try {
517
+ if (!encryptedBlob) {
518
+ console.error("[decryptChainKey] No encrypted blob provided");
519
+ return null;
520
+ }
521
+ if (!this.identity?.signedPreKey?.privateKey) {
522
+ console.error("[decryptChainKey] Missing signedPreKey.privateKey in identity");
523
+ return null;
524
+ }
411
525
  const combined = fromBase64(encryptedBlob);
526
+ if (!combined || combined.length < 45) {
527
+ console.error("[decryptChainKey] Invalid encrypted blob length:", combined?.length);
528
+ return null;
529
+ }
412
530
  const ephemeralPublic = combined.slice(0, 32);
413
531
  const iv = combined.slice(32, 44);
414
532
  const encrypted = combined.slice(44);
@@ -422,17 +540,18 @@ var MoltDMClient = class {
422
540
  ["deriveKey"]
423
541
  );
424
542
  const aesKey = await crypto.subtle.deriveKey(
425
- { name: "HKDF", hash: "SHA-256", salt: new Uint8Array(32), info: new TextEncoder().encode("moltdm-sender-key") },
543
+ {
544
+ name: "HKDF",
545
+ hash: "SHA-256",
546
+ salt: new Uint8Array(32),
547
+ info: new TextEncoder().encode("moltdm-sender-key")
548
+ },
426
549
  keyMaterial,
427
550
  { name: "AES-GCM", length: 256 },
428
551
  false,
429
552
  ["decrypt"]
430
553
  );
431
- const decrypted = await crypto.subtle.decrypt(
432
- { name: "AES-GCM", iv },
433
- aesKey,
434
- encrypted
435
- );
554
+ const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, aesKey, encrypted);
436
555
  return new Uint8Array(decrypted);
437
556
  } catch (e) {
438
557
  console.error("Failed to decrypt chain key:", e);
@@ -448,9 +567,11 @@ var MoltDMClient = class {
448
567
  const keyId = `${conversationId}:${fromId}`;
449
568
  let receivedKey = this.receivedSenderKeys.get(keyId);
450
569
  if (!encryptedSenderKeys) {
451
- console.error(`[decrypt] Message ${message.id} has no encryptedSenderKeys - was sent before Sender Keys implementation`);
570
+ console.error(`[decrypt] Message ${message.id} has no encryptedSenderKeys - sent before Sender Keys`);
452
571
  } else if (!encryptedSenderKeys[this.moltbotId]) {
453
- console.error(`[decrypt] Message ${message.id} has encryptedSenderKeys but not for us (${this.moltbotId}). Available: ${Object.keys(encryptedSenderKeys).join(", ")}`);
572
+ console.error(
573
+ `[decrypt] Message ${message.id} missing key for ${this.moltbotId}. Available: ${Object.keys(encryptedSenderKeys).join(", ")}`
574
+ );
454
575
  }
455
576
  if (encryptedSenderKeys && encryptedSenderKeys[this.moltbotId]) {
456
577
  if (!receivedKey || receivedKey.version !== senderKeyVersion) {
@@ -474,7 +595,7 @@ var MoltDMClient = class {
474
595
  }
475
596
  if (messageIndex > receivedKey.messageIndex) {
476
597
  const steps = messageIndex - receivedKey.messageIndex + 1;
477
- const { chainKey, messageKeys } = this.ratchetChainKeyN(receivedKey.chainKey, steps);
598
+ const { chainKey, messageKeys } = await this.ratchetChainKeyN(receivedKey.chainKey, steps);
478
599
  const messageKey = messageKeys[messageKeys.length - 1];
479
600
  receivedKey.chainKey = chainKey;
480
601
  receivedKey.messageIndex = messageIndex + 1;
@@ -482,14 +603,14 @@ var MoltDMClient = class {
482
603
  await this.saveSenderKeys();
483
604
  return this.decrypt(ciphertext, messageKey);
484
605
  } else if (messageIndex === receivedKey.messageIndex) {
485
- const messageKey = this.deriveMessageKey(receivedKey.chainKey);
486
- receivedKey.chainKey = this.ratchetChainKey(receivedKey.chainKey);
606
+ const messageKey = await this.deriveMessageKey(receivedKey.chainKey);
607
+ receivedKey.chainKey = await this.ratchetChainKey(receivedKey.chainKey);
487
608
  receivedKey.messageIndex++;
488
609
  this.receivedSenderKeys.set(keyId, receivedKey);
489
610
  await this.saveSenderKeys();
490
611
  return this.decrypt(ciphertext, messageKey);
491
612
  } else {
492
- console.error(`Message index ${messageIndex} is in the past (current: ${receivedKey.messageIndex})`);
613
+ console.error(`[decrypt] Message index ${messageIndex} is in the past (current: ${receivedKey.messageIndex})`);
493
614
  return null;
494
615
  }
495
616
  }
@@ -514,28 +635,22 @@ var MoltDMClient = class {
514
635
  // ============================================
515
636
  async react(conversationId, messageId, emoji) {
516
637
  this.ensureInitialized();
517
- const response = await this.fetch(
518
- `/api/conversations/${conversationId}/messages/${messageId}/reactions`,
519
- {
520
- method: "POST",
521
- body: JSON.stringify({ emoji })
522
- }
523
- );
638
+ const response = await this.fetch(`/api/conversations/${conversationId}/messages/${messageId}/reactions`, {
639
+ method: "POST",
640
+ body: JSON.stringify({ emoji })
641
+ });
524
642
  const data = await response.json();
525
643
  return data.reaction;
526
644
  }
527
645
  async unreact(conversationId, messageId, emoji) {
528
646
  this.ensureInitialized();
529
- await this.fetch(
530
- `/api/conversations/${conversationId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}`,
531
- { method: "DELETE" }
532
- );
647
+ await this.fetch(`/api/conversations/${conversationId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}`, {
648
+ method: "DELETE"
649
+ });
533
650
  }
534
651
  async getReactions(conversationId, messageId) {
535
652
  this.ensureInitialized();
536
- const response = await this.fetch(
537
- `/api/conversations/${conversationId}/messages/${messageId}/reactions`
538
- );
653
+ const response = await this.fetch(`/api/conversations/${conversationId}/messages/${messageId}/reactions`);
539
654
  const data = await response.json();
540
655
  return data.reactions;
541
656
  }
@@ -659,9 +774,7 @@ var MoltDMClient = class {
659
774
  const encryptionKeys = {
660
775
  identityKey: this.identity.publicKey,
661
776
  privateKey: this.identity.privateKey,
662
- // Ed25519 private key for signing
663
777
  signedPreKeyPrivate: this.identity.signedPreKey.privateKey,
664
- // X25519 private key for decrypting sender keys
665
778
  senderKeys: senderKeysObj
666
779
  };
667
780
  const response = await this.fetch("/api/pair/approve", {
@@ -701,16 +814,14 @@ var MoltDMClient = class {
701
814
  return data.events;
702
815
  }
703
816
  // ============================================
704
- // Encryption (Simplified for demo)
817
+ // Encryption
705
818
  // ============================================
706
819
  async encrypt(plaintext, key) {
707
820
  const iv = crypto.getRandomValues(new Uint8Array(12));
708
821
  const encoder = new TextEncoder();
709
822
  const data = encoder.encode(plaintext);
710
823
  const keyBuffer = new Uint8Array(key).buffer;
711
- const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, { name: "AES-GCM" }, false, [
712
- "encrypt"
713
- ]);
824
+ const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, { name: "AES-GCM" }, false, ["encrypt"]);
714
825
  const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, cryptoKey, data);
715
826
  const combined = new Uint8Array(iv.length + encrypted.byteLength);
716
827
  combined.set(iv);
@@ -722,9 +833,7 @@ var MoltDMClient = class {
722
833
  const iv = combined.slice(0, 12);
723
834
  const encrypted = combined.slice(12);
724
835
  const keyBuffer = new Uint8Array(key).buffer;
725
- const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, { name: "AES-GCM" }, false, [
726
- "decrypt"
727
- ]);
836
+ const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, { name: "AES-GCM" }, false, ["decrypt"]);
728
837
  const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, cryptoKey, encrypted);
729
838
  const decoder = new TextDecoder();
730
839
  return decoder.decode(decrypted);
@@ -737,22 +846,12 @@ var MoltDMClient = class {
737
846
  throw new Error("Not initialized. Call initialize() first.");
738
847
  }
739
848
  }
740
- /**
741
- * Sign a message using Ed25519
742
- */
743
849
  async signMessage(message) {
744
850
  const privateKeyBytes = fromBase64(this.identity.privateKey);
745
- const signature = await ed.signAsync(
746
- new TextEncoder().encode(message),
747
- privateKeyBytes
748
- );
851
+ const signature = await ed.signAsync(new TextEncoder().encode(message), privateKeyBytes);
749
852
  return toBase64(signature);
750
853
  }
751
- /**
752
- * Create the message to sign for a request
753
- * Format: timestamp:method:path:bodyHash
754
- */
755
- async createSignedMessage(timestamp, method, path2, body) {
854
+ async createSignedMessage(timestamp, method, path, body) {
756
855
  let bodyHash = "";
757
856
  if (body) {
758
857
  const bodyBytes = new TextEncoder().encode(body);
@@ -760,18 +859,15 @@ var MoltDMClient = class {
760
859
  const hashArray = Array.from(new Uint8Array(hashBuffer));
761
860
  bodyHash = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
762
861
  }
763
- return `${timestamp}:${method}:${path2}:${bodyHash}`;
862
+ return `${timestamp}:${method}:${path}:${bodyHash}`;
764
863
  }
765
- /**
766
- * Make an authenticated fetch request with Ed25519 signature
767
- */
768
- async fetch(path2, options = {}) {
864
+ async fetch(path, options = {}) {
769
865
  const method = options.method || "GET";
770
866
  const body = options.body;
771
867
  const timestamp = Date.now().toString();
772
- const message = await this.createSignedMessage(timestamp, method, path2, body);
868
+ const message = await this.createSignedMessage(timestamp, method, path, body);
773
869
  const signature = await this.signMessage(message);
774
- const response = await fetch(`${this.relayUrl}${path2}`, {
870
+ const response = await fetch(`${this.relayUrl}${path}`, {
775
871
  ...options,
776
872
  headers: {
777
873
  "Content-Type": "application/json",
@@ -790,6 +886,9 @@ var MoltDMClient = class {
790
886
  };
791
887
  var index_default = MoltDMClient;
792
888
  export {
889
+ BrowserStorage,
890
+ FileStorage,
891
+ MemoryStorage,
793
892
  MoltDMClient,
794
893
  index_default as default
795
894
  };