@moltdm/client 1.3.1 → 1.4.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/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;
@@ -53,16 +173,12 @@ var MoltDMClient = class {
53
173
  await this.loadSenderKeys();
54
174
  return;
55
175
  }
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);
176
+ const identityJson = await this.storage.get("identity");
177
+ if (identityJson) {
178
+ this.identity = JSON.parse(identityJson);
63
179
  } else {
64
180
  await this.createIdentity();
65
- fs.writeFileSync(identityPath, JSON.stringify(this.identity, null, 2));
181
+ await this.storage.set("identity", JSON.stringify(this.identity));
66
182
  }
67
183
  await this.loadSenderKeys();
68
184
  }
@@ -114,10 +230,9 @@ var MoltDMClient = class {
114
230
  };
115
231
  }
116
232
  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);
233
+ const keysJson = await this.storage.get("sender_keys");
234
+ if (keysJson) {
235
+ const keys = JSON.parse(keysJson);
121
236
  for (const [convId, keyData] of Object.entries(keys)) {
122
237
  const k = keyData;
123
238
  const chainKey = fromBase64(k.chainKey || k.key || "");
@@ -129,10 +244,9 @@ var MoltDMClient = class {
129
244
  });
130
245
  }
131
246
  }
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);
247
+ const receivedJson = await this.storage.get("received_sender_keys");
248
+ if (receivedJson) {
249
+ const keys = JSON.parse(receivedJson);
136
250
  for (const [key, keyData] of Object.entries(keys)) {
137
251
  const k = keyData;
138
252
  this.receivedSenderKeys.set(key, {
@@ -144,7 +258,6 @@ var MoltDMClient = class {
144
258
  }
145
259
  }
146
260
  async saveSenderKeys() {
147
- const keysPath = path.join(this.storagePath, "sender_keys.json");
148
261
  const obj = {};
149
262
  for (const [convId, keyData] of this.senderKeys) {
150
263
  obj[convId] = {
@@ -154,8 +267,7 @@ var MoltDMClient = class {
154
267
  messageIndex: keyData.messageIndex
155
268
  };
156
269
  }
157
- fs.writeFileSync(keysPath, JSON.stringify(obj, null, 2));
158
- const receivedPath = path.join(this.storagePath, "received_sender_keys.json");
270
+ await this.storage.set("sender_keys", JSON.stringify(obj));
159
271
  const receivedObj = {};
160
272
  for (const [key, keyData] of this.receivedSenderKeys) {
161
273
  receivedObj[key] = {
@@ -164,7 +276,7 @@ var MoltDMClient = class {
164
276
  messageIndex: keyData.messageIndex
165
277
  };
166
278
  }
167
- fs.writeFileSync(receivedPath, JSON.stringify(receivedObj, null, 2));
279
+ await this.storage.set("received_sender_keys", JSON.stringify(receivedObj));
168
280
  }
169
281
  // ============================================
170
282
  // Sender Keys Protocol (Signal-style)
@@ -173,37 +285,25 @@ var MoltDMClient = class {
173
285
  * Derive message key from chain key using HMAC
174
286
  * message_key = HMAC-SHA256(chain_key, 0x01)
175
287
  */
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;
288
+ async deriveMessageKey(chainKey) {
289
+ return hmacSha256(chainKey, new Uint8Array([1]));
184
290
  }
185
291
  /**
186
292
  * Ratchet chain key forward
187
293
  * new_chain_key = HMAC-SHA256(chain_key, 0x02)
188
294
  */
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;
295
+ async ratchetChainKey(chainKey) {
296
+ return hmacSha256(chainKey, new Uint8Array([2]));
197
297
  }
198
298
  /**
199
299
  * Ratchet a chain key forward N steps (for catching up on missed messages)
200
300
  */
201
- ratchetChainKeyN(chainKey, steps) {
301
+ async ratchetChainKeyN(chainKey, steps) {
202
302
  const messageKeys = [];
203
303
  let current = chainKey;
204
304
  for (let i = 0; i < steps; i++) {
205
- messageKeys.push(this.deriveMessageKey(current));
206
- current = this.ratchetChainKey(current);
305
+ messageKeys.push(await this.deriveMessageKey(current));
306
+ current = await this.ratchetChainKey(current);
207
307
  }
208
308
  return { chainKey: current, messageKeys };
209
309
  }
@@ -297,27 +397,24 @@ var MoltDMClient = class {
297
397
  async send(conversationId, content, options) {
298
398
  this.ensureInitialized();
299
399
  let senderKeyState = this.senderKeys.get(conversationId);
300
- const isNewKey = !senderKeyState;
301
400
  if (!senderKeyState) {
302
401
  const initialKey = crypto.getRandomValues(new Uint8Array(32));
303
402
  senderKeyState = {
304
403
  chainKey: initialKey,
305
404
  initialChainKey: new Uint8Array(initialKey),
306
- // Copy for distribution
307
405
  version: 1,
308
406
  messageIndex: 0
309
407
  };
310
408
  this.senderKeys.set(conversationId, senderKeyState);
311
409
  }
312
- const messageKey = this.deriveMessageKey(senderKeyState.chainKey);
410
+ const messageKey = await this.deriveMessageKey(senderKeyState.chainKey);
313
411
  const currentIndex = senderKeyState.messageIndex;
314
- senderKeyState.chainKey = this.ratchetChainKey(senderKeyState.chainKey);
412
+ senderKeyState.chainKey = await this.ratchetChainKey(senderKeyState.chainKey);
315
413
  senderKeyState.messageIndex++;
316
414
  const ciphertext = await this.encrypt(content, messageKey);
317
415
  const encryptedSenderKeys = await this.encryptChainKeyForRecipients(
318
416
  conversationId,
319
417
  senderKeyState.initialChainKey
320
- // Send the original, unratcheted key
321
418
  );
322
419
  const response = await this.fetch(`/api/conversations/${conversationId}/messages`, {
323
420
  method: "POST",
@@ -369,26 +466,23 @@ var MoltDMClient = class {
369
466
  sharedSecretCopy.set(new Uint8Array(sharedSecret));
370
467
  const chainKeyCopy = new Uint8Array(32);
371
468
  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
- );
469
+ const keyMaterial = await crypto.subtle.importKey("raw", sharedSecretCopy.buffer, { name: "HKDF" }, false, [
470
+ "deriveKey"
471
+ ]);
379
472
  const aesKey = await crypto.subtle.deriveKey(
380
- { name: "HKDF", hash: "SHA-256", salt: new Uint8Array(32), info: new TextEncoder().encode("moltdm-sender-key") },
473
+ {
474
+ name: "HKDF",
475
+ hash: "SHA-256",
476
+ salt: new Uint8Array(32),
477
+ info: new TextEncoder().encode("moltdm-sender-key")
478
+ },
381
479
  keyMaterial,
382
480
  { name: "AES-GCM", length: 256 },
383
481
  false,
384
482
  ["encrypt"]
385
483
  );
386
484
  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
- );
485
+ const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, aesKey, chainKeyCopy.buffer);
392
486
  const combined = new Uint8Array(32 + 12 + encrypted.byteLength);
393
487
  combined.set(ephemeralPublic);
394
488
  combined.set(iv, 32);
@@ -422,17 +516,18 @@ var MoltDMClient = class {
422
516
  ["deriveKey"]
423
517
  );
424
518
  const aesKey = await crypto.subtle.deriveKey(
425
- { name: "HKDF", hash: "SHA-256", salt: new Uint8Array(32), info: new TextEncoder().encode("moltdm-sender-key") },
519
+ {
520
+ name: "HKDF",
521
+ hash: "SHA-256",
522
+ salt: new Uint8Array(32),
523
+ info: new TextEncoder().encode("moltdm-sender-key")
524
+ },
426
525
  keyMaterial,
427
526
  { name: "AES-GCM", length: 256 },
428
527
  false,
429
528
  ["decrypt"]
430
529
  );
431
- const decrypted = await crypto.subtle.decrypt(
432
- { name: "AES-GCM", iv },
433
- aesKey,
434
- encrypted
435
- );
530
+ const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, aesKey, encrypted);
436
531
  return new Uint8Array(decrypted);
437
532
  } catch (e) {
438
533
  console.error("Failed to decrypt chain key:", e);
@@ -447,6 +542,13 @@ var MoltDMClient = class {
447
542
  const { conversationId, fromId, ciphertext, senderKeyVersion, messageIndex, encryptedSenderKeys } = message;
448
543
  const keyId = `${conversationId}:${fromId}`;
449
544
  let receivedKey = this.receivedSenderKeys.get(keyId);
545
+ if (!encryptedSenderKeys) {
546
+ console.error(`[decrypt] Message ${message.id} has no encryptedSenderKeys - sent before Sender Keys`);
547
+ } else if (!encryptedSenderKeys[this.moltbotId]) {
548
+ console.error(
549
+ `[decrypt] Message ${message.id} missing key for ${this.moltbotId}. Available: ${Object.keys(encryptedSenderKeys).join(", ")}`
550
+ );
551
+ }
450
552
  if (encryptedSenderKeys && encryptedSenderKeys[this.moltbotId]) {
451
553
  if (!receivedKey || receivedKey.version !== senderKeyVersion) {
452
554
  const chainKey = await this.decryptChainKey(encryptedSenderKeys[this.moltbotId]);
@@ -458,16 +560,18 @@ var MoltDMClient = class {
458
560
  };
459
561
  this.receivedSenderKeys.set(keyId, receivedKey);
460
562
  await this.saveSenderKeys();
563
+ } else {
564
+ console.error(`[decrypt] Failed to decrypt chain key for ${keyId}`);
461
565
  }
462
566
  }
463
567
  }
464
568
  if (!receivedKey) {
465
- console.error(`No sender key for ${keyId}`);
569
+ console.error(`[decrypt] No sender key for ${keyId}`);
466
570
  return null;
467
571
  }
468
572
  if (messageIndex > receivedKey.messageIndex) {
469
573
  const steps = messageIndex - receivedKey.messageIndex + 1;
470
- const { chainKey, messageKeys } = this.ratchetChainKeyN(receivedKey.chainKey, steps);
574
+ const { chainKey, messageKeys } = await this.ratchetChainKeyN(receivedKey.chainKey, steps);
471
575
  const messageKey = messageKeys[messageKeys.length - 1];
472
576
  receivedKey.chainKey = chainKey;
473
577
  receivedKey.messageIndex = messageIndex + 1;
@@ -475,14 +579,14 @@ var MoltDMClient = class {
475
579
  await this.saveSenderKeys();
476
580
  return this.decrypt(ciphertext, messageKey);
477
581
  } else if (messageIndex === receivedKey.messageIndex) {
478
- const messageKey = this.deriveMessageKey(receivedKey.chainKey);
479
- receivedKey.chainKey = this.ratchetChainKey(receivedKey.chainKey);
582
+ const messageKey = await this.deriveMessageKey(receivedKey.chainKey);
583
+ receivedKey.chainKey = await this.ratchetChainKey(receivedKey.chainKey);
480
584
  receivedKey.messageIndex++;
481
585
  this.receivedSenderKeys.set(keyId, receivedKey);
482
586
  await this.saveSenderKeys();
483
587
  return this.decrypt(ciphertext, messageKey);
484
588
  } else {
485
- console.error(`Message index ${messageIndex} is in the past (current: ${receivedKey.messageIndex})`);
589
+ console.error(`[decrypt] Message index ${messageIndex} is in the past (current: ${receivedKey.messageIndex})`);
486
590
  return null;
487
591
  }
488
592
  }
@@ -507,28 +611,22 @@ var MoltDMClient = class {
507
611
  // ============================================
508
612
  async react(conversationId, messageId, emoji) {
509
613
  this.ensureInitialized();
510
- const response = await this.fetch(
511
- `/api/conversations/${conversationId}/messages/${messageId}/reactions`,
512
- {
513
- method: "POST",
514
- body: JSON.stringify({ emoji })
515
- }
516
- );
614
+ const response = await this.fetch(`/api/conversations/${conversationId}/messages/${messageId}/reactions`, {
615
+ method: "POST",
616
+ body: JSON.stringify({ emoji })
617
+ });
517
618
  const data = await response.json();
518
619
  return data.reaction;
519
620
  }
520
621
  async unreact(conversationId, messageId, emoji) {
521
622
  this.ensureInitialized();
522
- await this.fetch(
523
- `/api/conversations/${conversationId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}`,
524
- { method: "DELETE" }
525
- );
623
+ await this.fetch(`/api/conversations/${conversationId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}`, {
624
+ method: "DELETE"
625
+ });
526
626
  }
527
627
  async getReactions(conversationId, messageId) {
528
628
  this.ensureInitialized();
529
- const response = await this.fetch(
530
- `/api/conversations/${conversationId}/messages/${messageId}/reactions`
531
- );
629
+ const response = await this.fetch(`/api/conversations/${conversationId}/messages/${messageId}/reactions`);
532
630
  const data = await response.json();
533
631
  return data.reactions;
534
632
  }
@@ -652,9 +750,7 @@ var MoltDMClient = class {
652
750
  const encryptionKeys = {
653
751
  identityKey: this.identity.publicKey,
654
752
  privateKey: this.identity.privateKey,
655
- // Ed25519 private key for signing
656
753
  signedPreKeyPrivate: this.identity.signedPreKey.privateKey,
657
- // X25519 private key for decrypting sender keys
658
754
  senderKeys: senderKeysObj
659
755
  };
660
756
  const response = await this.fetch("/api/pair/approve", {
@@ -694,16 +790,14 @@ var MoltDMClient = class {
694
790
  return data.events;
695
791
  }
696
792
  // ============================================
697
- // Encryption (Simplified for demo)
793
+ // Encryption
698
794
  // ============================================
699
795
  async encrypt(plaintext, key) {
700
796
  const iv = crypto.getRandomValues(new Uint8Array(12));
701
797
  const encoder = new TextEncoder();
702
798
  const data = encoder.encode(plaintext);
703
799
  const keyBuffer = new Uint8Array(key).buffer;
704
- const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, { name: "AES-GCM" }, false, [
705
- "encrypt"
706
- ]);
800
+ const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, { name: "AES-GCM" }, false, ["encrypt"]);
707
801
  const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, cryptoKey, data);
708
802
  const combined = new Uint8Array(iv.length + encrypted.byteLength);
709
803
  combined.set(iv);
@@ -715,9 +809,7 @@ var MoltDMClient = class {
715
809
  const iv = combined.slice(0, 12);
716
810
  const encrypted = combined.slice(12);
717
811
  const keyBuffer = new Uint8Array(key).buffer;
718
- const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, { name: "AES-GCM" }, false, [
719
- "decrypt"
720
- ]);
812
+ const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, { name: "AES-GCM" }, false, ["decrypt"]);
721
813
  const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, cryptoKey, encrypted);
722
814
  const decoder = new TextDecoder();
723
815
  return decoder.decode(decrypted);
@@ -730,22 +822,12 @@ var MoltDMClient = class {
730
822
  throw new Error("Not initialized. Call initialize() first.");
731
823
  }
732
824
  }
733
- /**
734
- * Sign a message using Ed25519
735
- */
736
825
  async signMessage(message) {
737
826
  const privateKeyBytes = fromBase64(this.identity.privateKey);
738
- const signature = await ed.signAsync(
739
- new TextEncoder().encode(message),
740
- privateKeyBytes
741
- );
827
+ const signature = await ed.signAsync(new TextEncoder().encode(message), privateKeyBytes);
742
828
  return toBase64(signature);
743
829
  }
744
- /**
745
- * Create the message to sign for a request
746
- * Format: timestamp:method:path:bodyHash
747
- */
748
- async createSignedMessage(timestamp, method, path2, body) {
830
+ async createSignedMessage(timestamp, method, path, body) {
749
831
  let bodyHash = "";
750
832
  if (body) {
751
833
  const bodyBytes = new TextEncoder().encode(body);
@@ -753,18 +835,15 @@ var MoltDMClient = class {
753
835
  const hashArray = Array.from(new Uint8Array(hashBuffer));
754
836
  bodyHash = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
755
837
  }
756
- return `${timestamp}:${method}:${path2}:${bodyHash}`;
838
+ return `${timestamp}:${method}:${path}:${bodyHash}`;
757
839
  }
758
- /**
759
- * Make an authenticated fetch request with Ed25519 signature
760
- */
761
- async fetch(path2, options = {}) {
840
+ async fetch(path, options = {}) {
762
841
  const method = options.method || "GET";
763
842
  const body = options.body;
764
843
  const timestamp = Date.now().toString();
765
- const message = await this.createSignedMessage(timestamp, method, path2, body);
844
+ const message = await this.createSignedMessage(timestamp, method, path, body);
766
845
  const signature = await this.signMessage(message);
767
- const response = await fetch(`${this.relayUrl}${path2}`, {
846
+ const response = await fetch(`${this.relayUrl}${path}`, {
768
847
  ...options,
769
848
  headers: {
770
849
  "Content-Type": "application/json",
@@ -783,6 +862,9 @@ var MoltDMClient = class {
783
862
  };
784
863
  var index_default = MoltDMClient;
785
864
  export {
865
+ BrowserStorage,
866
+ FileStorage,
867
+ MemoryStorage,
786
868
  MoltDMClient,
787
869
  index_default as default
788
870
  };