@unicitylabs/sphere-sdk 0.3.8 → 0.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/connect/index.cjs +770 -0
- package/dist/connect/index.cjs.map +1 -0
- package/dist/connect/index.d.cts +312 -0
- package/dist/connect/index.d.ts +312 -0
- package/dist/connect/index.js +747 -0
- package/dist/connect/index.js.map +1 -0
- package/dist/core/index.cjs +2744 -56
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +277 -3
- package/dist/core/index.d.ts +277 -3
- package/dist/core/index.js +2740 -52
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +271 -0
- package/dist/impl/browser/connect/index.cjs.map +1 -0
- package/dist/impl/browser/connect/index.d.cts +137 -0
- package/dist/impl/browser/connect/index.d.ts +137 -0
- package/dist/impl/browser/connect/index.js +248 -0
- package/dist/impl/browser/connect/index.js.map +1 -0
- package/dist/impl/browser/index.cjs +583 -45
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +587 -46
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/browser/ipfs.cjs.map +1 -1
- package/dist/impl/browser/ipfs.js.map +1 -1
- package/dist/impl/nodejs/connect/index.cjs +372 -0
- package/dist/impl/nodejs/connect/index.cjs.map +1 -0
- package/dist/impl/nodejs/connect/index.d.cts +178 -0
- package/dist/impl/nodejs/connect/index.d.ts +178 -0
- package/dist/impl/nodejs/connect/index.js +333 -0
- package/dist/impl/nodejs/connect/index.js.map +1 -0
- package/dist/impl/nodejs/index.cjs +266 -12
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +96 -0
- package/dist/impl/nodejs/index.d.ts +96 -0
- package/dist/impl/nodejs/index.js +270 -13
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +2761 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +375 -5
- package/dist/index.d.ts +375 -5
- package/dist/index.js +2750 -52
- package/dist/index.js.map +1 -1
- package/dist/l1/index.cjs +5 -1
- package/dist/l1/index.cjs.map +1 -1
- package/dist/l1/index.d.cts +2 -1
- package/dist/l1/index.d.ts +2 -1
- package/dist/l1/index.js +5 -1
- package/dist/l1/index.js.map +1 -1
- package/package.json +31 -1
|
@@ -350,9 +350,264 @@ function createLocalStorageProvider(config) {
|
|
|
350
350
|
return new LocalStorageProvider(config);
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
// impl/browser/storage/
|
|
354
|
-
var DB_NAME = "sphere-
|
|
353
|
+
// impl/browser/storage/IndexedDBStorageProvider.ts
|
|
354
|
+
var DB_NAME = "sphere-storage";
|
|
355
355
|
var DB_VERSION = 1;
|
|
356
|
+
var STORE_NAME = "kv";
|
|
357
|
+
var IndexedDBStorageProvider = class {
|
|
358
|
+
id = "indexeddb-storage";
|
|
359
|
+
name = "IndexedDB Storage";
|
|
360
|
+
type = "local";
|
|
361
|
+
description = "Browser IndexedDB for large-capacity persistence";
|
|
362
|
+
prefix;
|
|
363
|
+
dbName;
|
|
364
|
+
debug;
|
|
365
|
+
identity = null;
|
|
366
|
+
status = "disconnected";
|
|
367
|
+
db = null;
|
|
368
|
+
constructor(config) {
|
|
369
|
+
this.prefix = config?.prefix ?? "sphere_";
|
|
370
|
+
this.dbName = config?.dbName ?? DB_NAME;
|
|
371
|
+
this.debug = config?.debug ?? false;
|
|
372
|
+
}
|
|
373
|
+
// ===========================================================================
|
|
374
|
+
// BaseProvider Implementation
|
|
375
|
+
// ===========================================================================
|
|
376
|
+
async connect() {
|
|
377
|
+
if (this.status === "connected" && this.db) return;
|
|
378
|
+
this.status = "connecting";
|
|
379
|
+
try {
|
|
380
|
+
this.db = await Promise.race([
|
|
381
|
+
this.openDatabase(),
|
|
382
|
+
new Promise(
|
|
383
|
+
(_, reject) => setTimeout(() => reject(new Error("IndexedDB open timed out after 5s")), 5e3)
|
|
384
|
+
)
|
|
385
|
+
]);
|
|
386
|
+
this.status = "connected";
|
|
387
|
+
this.log("Connected to IndexedDB");
|
|
388
|
+
} catch (error) {
|
|
389
|
+
this.status = "error";
|
|
390
|
+
throw new Error(`IndexedDB not available: ${error}`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async disconnect() {
|
|
394
|
+
if (this.db) {
|
|
395
|
+
this.db.close();
|
|
396
|
+
this.db = null;
|
|
397
|
+
}
|
|
398
|
+
this.status = "disconnected";
|
|
399
|
+
this.log("Disconnected from IndexedDB");
|
|
400
|
+
}
|
|
401
|
+
isConnected() {
|
|
402
|
+
return this.status === "connected" && this.db !== null;
|
|
403
|
+
}
|
|
404
|
+
getStatus() {
|
|
405
|
+
return this.status;
|
|
406
|
+
}
|
|
407
|
+
// ===========================================================================
|
|
408
|
+
// StorageProvider Implementation
|
|
409
|
+
// ===========================================================================
|
|
410
|
+
setIdentity(identity) {
|
|
411
|
+
this.identity = identity;
|
|
412
|
+
this.log("Identity set:", identity.l1Address);
|
|
413
|
+
}
|
|
414
|
+
async get(key) {
|
|
415
|
+
this.ensureConnected();
|
|
416
|
+
const fullKey = this.getFullKey(key);
|
|
417
|
+
const result = await this.idbGet(fullKey);
|
|
418
|
+
return result?.v ?? null;
|
|
419
|
+
}
|
|
420
|
+
async set(key, value) {
|
|
421
|
+
this.ensureConnected();
|
|
422
|
+
const fullKey = this.getFullKey(key);
|
|
423
|
+
await this.idbPut({ k: fullKey, v: value });
|
|
424
|
+
}
|
|
425
|
+
async remove(key) {
|
|
426
|
+
this.ensureConnected();
|
|
427
|
+
const fullKey = this.getFullKey(key);
|
|
428
|
+
await this.idbDelete(fullKey);
|
|
429
|
+
}
|
|
430
|
+
async has(key) {
|
|
431
|
+
this.ensureConnected();
|
|
432
|
+
const fullKey = this.getFullKey(key);
|
|
433
|
+
const count = await this.idbCount(fullKey);
|
|
434
|
+
return count > 0;
|
|
435
|
+
}
|
|
436
|
+
async keys(prefix) {
|
|
437
|
+
this.ensureConnected();
|
|
438
|
+
const basePrefix = this.getFullKey("");
|
|
439
|
+
const searchPrefix = prefix ? this.getFullKey(prefix) : basePrefix;
|
|
440
|
+
const allEntries = await this.idbGetAll();
|
|
441
|
+
const result = [];
|
|
442
|
+
for (const entry of allEntries) {
|
|
443
|
+
if (entry.k.startsWith(searchPrefix)) {
|
|
444
|
+
result.push(entry.k.slice(basePrefix.length));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
async clear(prefix) {
|
|
450
|
+
if (!prefix) {
|
|
451
|
+
if (this.db) {
|
|
452
|
+
this.db.close();
|
|
453
|
+
this.db = null;
|
|
454
|
+
}
|
|
455
|
+
this.status = "disconnected";
|
|
456
|
+
await new Promise((resolve) => {
|
|
457
|
+
try {
|
|
458
|
+
const req = indexedDB.deleteDatabase(this.dbName);
|
|
459
|
+
req.onsuccess = () => resolve();
|
|
460
|
+
req.onerror = () => resolve();
|
|
461
|
+
req.onblocked = () => resolve();
|
|
462
|
+
} catch {
|
|
463
|
+
resolve();
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
this.log("Database deleted:", this.dbName);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
this.ensureConnected();
|
|
470
|
+
const keysToRemove = await this.keys(prefix);
|
|
471
|
+
for (const key of keysToRemove) {
|
|
472
|
+
await this.remove(key);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
async saveTrackedAddresses(entries) {
|
|
476
|
+
await this.set(STORAGE_KEYS_GLOBAL.TRACKED_ADDRESSES, JSON.stringify({ version: 1, addresses: entries }));
|
|
477
|
+
}
|
|
478
|
+
async loadTrackedAddresses() {
|
|
479
|
+
const data = await this.get(STORAGE_KEYS_GLOBAL.TRACKED_ADDRESSES);
|
|
480
|
+
if (!data) return [];
|
|
481
|
+
try {
|
|
482
|
+
const parsed = JSON.parse(data);
|
|
483
|
+
return parsed.addresses ?? [];
|
|
484
|
+
} catch {
|
|
485
|
+
return [];
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
// ===========================================================================
|
|
489
|
+
// Helpers
|
|
490
|
+
// ===========================================================================
|
|
491
|
+
/**
|
|
492
|
+
* Get JSON data
|
|
493
|
+
*/
|
|
494
|
+
async getJSON(key) {
|
|
495
|
+
const value = await this.get(key);
|
|
496
|
+
if (!value) return null;
|
|
497
|
+
try {
|
|
498
|
+
return JSON.parse(value);
|
|
499
|
+
} catch {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Set JSON data
|
|
505
|
+
*/
|
|
506
|
+
async setJSON(key, value) {
|
|
507
|
+
await this.set(key, JSON.stringify(value));
|
|
508
|
+
}
|
|
509
|
+
// ===========================================================================
|
|
510
|
+
// Private: Key Scoping
|
|
511
|
+
// ===========================================================================
|
|
512
|
+
getFullKey(key) {
|
|
513
|
+
const isPerAddressKey = Object.values(STORAGE_KEYS_ADDRESS).includes(key);
|
|
514
|
+
if (isPerAddressKey && this.identity?.directAddress) {
|
|
515
|
+
const addressId = getAddressId(this.identity.directAddress);
|
|
516
|
+
return `${this.prefix}${addressId}_${key}`;
|
|
517
|
+
}
|
|
518
|
+
return `${this.prefix}${key}`;
|
|
519
|
+
}
|
|
520
|
+
ensureConnected() {
|
|
521
|
+
if (this.status !== "connected" || !this.db) {
|
|
522
|
+
throw new Error("IndexedDBStorageProvider not connected");
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// ===========================================================================
|
|
526
|
+
// Private: IndexedDB Operations
|
|
527
|
+
// ===========================================================================
|
|
528
|
+
openDatabase() {
|
|
529
|
+
return new Promise((resolve, reject) => {
|
|
530
|
+
const request = indexedDB.open(this.dbName, DB_VERSION);
|
|
531
|
+
request.onerror = () => reject(request.error);
|
|
532
|
+
request.onsuccess = () => resolve(request.result);
|
|
533
|
+
request.onblocked = () => {
|
|
534
|
+
console.warn("[IndexedDBStorageProvider] open blocked by another connection");
|
|
535
|
+
};
|
|
536
|
+
request.onupgradeneeded = (event) => {
|
|
537
|
+
const db = event.target.result;
|
|
538
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
539
|
+
db.createObjectStore(STORE_NAME, { keyPath: "k" });
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
idbGet(key) {
|
|
545
|
+
return new Promise((resolve, reject) => {
|
|
546
|
+
const tx = this.db.transaction(STORE_NAME, "readonly");
|
|
547
|
+
const store = tx.objectStore(STORE_NAME);
|
|
548
|
+
const request = store.get(key);
|
|
549
|
+
request.onerror = () => reject(request.error);
|
|
550
|
+
request.onsuccess = () => resolve(request.result ?? void 0);
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
idbPut(entry) {
|
|
554
|
+
return new Promise((resolve, reject) => {
|
|
555
|
+
const tx = this.db.transaction(STORE_NAME, "readwrite");
|
|
556
|
+
const store = tx.objectStore(STORE_NAME);
|
|
557
|
+
const request = store.put(entry);
|
|
558
|
+
request.onerror = () => reject(request.error);
|
|
559
|
+
request.onsuccess = () => resolve();
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
idbDelete(key) {
|
|
563
|
+
return new Promise((resolve, reject) => {
|
|
564
|
+
const tx = this.db.transaction(STORE_NAME, "readwrite");
|
|
565
|
+
const store = tx.objectStore(STORE_NAME);
|
|
566
|
+
const request = store.delete(key);
|
|
567
|
+
request.onerror = () => reject(request.error);
|
|
568
|
+
request.onsuccess = () => resolve();
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
idbCount(key) {
|
|
572
|
+
return new Promise((resolve, reject) => {
|
|
573
|
+
const tx = this.db.transaction(STORE_NAME, "readonly");
|
|
574
|
+
const store = tx.objectStore(STORE_NAME);
|
|
575
|
+
const request = store.count(key);
|
|
576
|
+
request.onerror = () => reject(request.error);
|
|
577
|
+
request.onsuccess = () => resolve(request.result);
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
idbGetAll() {
|
|
581
|
+
return new Promise((resolve, reject) => {
|
|
582
|
+
const tx = this.db.transaction(STORE_NAME, "readonly");
|
|
583
|
+
const store = tx.objectStore(STORE_NAME);
|
|
584
|
+
const request = store.getAll();
|
|
585
|
+
request.onerror = () => reject(request.error);
|
|
586
|
+
request.onsuccess = () => resolve(request.result ?? []);
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
idbClear() {
|
|
590
|
+
return new Promise((resolve, reject) => {
|
|
591
|
+
const tx = this.db.transaction(STORE_NAME, "readwrite");
|
|
592
|
+
const store = tx.objectStore(STORE_NAME);
|
|
593
|
+
const request = store.clear();
|
|
594
|
+
request.onerror = () => reject(request.error);
|
|
595
|
+
request.onsuccess = () => resolve();
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
log(...args) {
|
|
599
|
+
if (this.debug) {
|
|
600
|
+
console.log("[IndexedDBStorageProvider]", ...args);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
function createIndexedDBStorageProvider(config) {
|
|
605
|
+
return new IndexedDBStorageProvider(config);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// impl/browser/storage/IndexedDBTokenStorageProvider.ts
|
|
609
|
+
var DB_NAME2 = "sphere-token-storage";
|
|
610
|
+
var DB_VERSION2 = 1;
|
|
356
611
|
var STORE_TOKENS = "tokens";
|
|
357
612
|
var STORE_META = "meta";
|
|
358
613
|
var IndexedDBTokenStorageProvider = class {
|
|
@@ -365,7 +620,7 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
365
620
|
status = "disconnected";
|
|
366
621
|
identity = null;
|
|
367
622
|
constructor(config) {
|
|
368
|
-
this.dbNamePrefix = config?.dbNamePrefix ??
|
|
623
|
+
this.dbNamePrefix = config?.dbNamePrefix ?? DB_NAME2;
|
|
369
624
|
this.dbName = this.dbNamePrefix;
|
|
370
625
|
}
|
|
371
626
|
setIdentity(identity) {
|
|
@@ -379,6 +634,7 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
379
634
|
try {
|
|
380
635
|
this.db = await this.openDatabase();
|
|
381
636
|
this.status = "connected";
|
|
637
|
+
this.cleanupStaleDatabases();
|
|
382
638
|
return true;
|
|
383
639
|
} catch (error) {
|
|
384
640
|
console.error("[IndexedDBTokenStorage] Failed to initialize:", error);
|
|
@@ -536,37 +792,43 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
536
792
|
return meta !== null;
|
|
537
793
|
}
|
|
538
794
|
async clear() {
|
|
539
|
-
if (this.db) {
|
|
540
|
-
this.db.close();
|
|
541
|
-
this.db = null;
|
|
542
|
-
}
|
|
543
|
-
this.status = "disconnected";
|
|
544
|
-
const CLEAR_TIMEOUT = 1500;
|
|
545
|
-
const withTimeout = (promise, ms, label) => Promise.race([
|
|
546
|
-
promise,
|
|
547
|
-
new Promise(
|
|
548
|
-
(_, reject) => setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms)
|
|
549
|
-
)
|
|
550
|
-
]);
|
|
551
|
-
const deleteDb = (name) => new Promise((resolve) => {
|
|
552
|
-
const req = indexedDB.deleteDatabase(name);
|
|
553
|
-
req.onsuccess = () => resolve();
|
|
554
|
-
req.onerror = () => resolve();
|
|
555
|
-
req.onblocked = () => resolve();
|
|
556
|
-
});
|
|
557
795
|
try {
|
|
796
|
+
if (this.db) {
|
|
797
|
+
this.db.close();
|
|
798
|
+
this.db = null;
|
|
799
|
+
}
|
|
800
|
+
this.status = "disconnected";
|
|
801
|
+
const dbNames = [this.dbName];
|
|
558
802
|
if (typeof indexedDB.databases === "function") {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
803
|
+
try {
|
|
804
|
+
const dbs = await Promise.race([
|
|
805
|
+
indexedDB.databases(),
|
|
806
|
+
new Promise(
|
|
807
|
+
(_, reject) => setTimeout(() => reject(new Error("timeout")), 1500)
|
|
808
|
+
)
|
|
809
|
+
]);
|
|
810
|
+
for (const dbInfo of dbs) {
|
|
811
|
+
if (dbInfo.name && dbInfo.name.startsWith(this.dbNamePrefix) && dbInfo.name !== this.dbName) {
|
|
812
|
+
dbNames.push(dbInfo.name);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
} catch {
|
|
816
|
+
}
|
|
569
817
|
}
|
|
818
|
+
await Promise.all(dbNames.map(
|
|
819
|
+
(name) => new Promise((resolve) => {
|
|
820
|
+
try {
|
|
821
|
+
const req = indexedDB.deleteDatabase(name);
|
|
822
|
+
req.onsuccess = () => resolve();
|
|
823
|
+
req.onerror = () => resolve();
|
|
824
|
+
req.onblocked = () => {
|
|
825
|
+
resolve();
|
|
826
|
+
};
|
|
827
|
+
} catch {
|
|
828
|
+
resolve();
|
|
829
|
+
}
|
|
830
|
+
})
|
|
831
|
+
));
|
|
570
832
|
return true;
|
|
571
833
|
} catch (err) {
|
|
572
834
|
console.warn("[IndexedDBTokenStorage] clear() failed:", err);
|
|
@@ -576,9 +838,29 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
576
838
|
// =========================================================================
|
|
577
839
|
// Private IndexedDB helpers
|
|
578
840
|
// =========================================================================
|
|
841
|
+
/**
|
|
842
|
+
* Delete stale databases from other addresses (fire-and-forget, background).
|
|
843
|
+
* Called after the current database is already open, so deleteDatabase
|
|
844
|
+
* on other databases won't block anything.
|
|
845
|
+
*/
|
|
846
|
+
cleanupStaleDatabases() {
|
|
847
|
+
if (typeof indexedDB.databases !== "function") return;
|
|
848
|
+
indexedDB.databases().then((dbs) => {
|
|
849
|
+
for (const dbInfo of dbs) {
|
|
850
|
+
if (dbInfo.name && dbInfo.name.startsWith(this.dbNamePrefix) && dbInfo.name !== this.dbName) {
|
|
851
|
+
const req = indexedDB.deleteDatabase(dbInfo.name);
|
|
852
|
+
req.onerror = () => {
|
|
853
|
+
};
|
|
854
|
+
req.onblocked = () => {
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}).catch(() => {
|
|
859
|
+
});
|
|
860
|
+
}
|
|
579
861
|
openDatabase() {
|
|
580
862
|
return new Promise((resolve, reject) => {
|
|
581
|
-
const request = indexedDB.open(this.dbName,
|
|
863
|
+
const request = indexedDB.open(this.dbName, DB_VERSION2);
|
|
582
864
|
request.onerror = () => {
|
|
583
865
|
reject(request.error);
|
|
584
866
|
};
|
|
@@ -721,6 +1003,52 @@ function createView(arr) {
|
|
|
721
1003
|
function rotr(word, shift) {
|
|
722
1004
|
return word << 32 - shift | word >>> shift;
|
|
723
1005
|
}
|
|
1006
|
+
var hasHexBuiltin = /* @__PURE__ */ (() => (
|
|
1007
|
+
// @ts-ignore
|
|
1008
|
+
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
1009
|
+
))();
|
|
1010
|
+
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
1011
|
+
function bytesToHex(bytes) {
|
|
1012
|
+
abytes(bytes);
|
|
1013
|
+
if (hasHexBuiltin)
|
|
1014
|
+
return bytes.toHex();
|
|
1015
|
+
let hex = "";
|
|
1016
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1017
|
+
hex += hexes[bytes[i]];
|
|
1018
|
+
}
|
|
1019
|
+
return hex;
|
|
1020
|
+
}
|
|
1021
|
+
var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
|
|
1022
|
+
function asciiToBase16(ch) {
|
|
1023
|
+
if (ch >= asciis._0 && ch <= asciis._9)
|
|
1024
|
+
return ch - asciis._0;
|
|
1025
|
+
if (ch >= asciis.A && ch <= asciis.F)
|
|
1026
|
+
return ch - (asciis.A - 10);
|
|
1027
|
+
if (ch >= asciis.a && ch <= asciis.f)
|
|
1028
|
+
return ch - (asciis.a - 10);
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
function hexToBytes(hex) {
|
|
1032
|
+
if (typeof hex !== "string")
|
|
1033
|
+
throw new Error("hex string expected, got " + typeof hex);
|
|
1034
|
+
if (hasHexBuiltin)
|
|
1035
|
+
return Uint8Array.fromHex(hex);
|
|
1036
|
+
const hl = hex.length;
|
|
1037
|
+
const al = hl / 2;
|
|
1038
|
+
if (hl % 2)
|
|
1039
|
+
throw new Error("hex string expected, got unpadded hex of length " + hl);
|
|
1040
|
+
const array = new Uint8Array(al);
|
|
1041
|
+
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
|
1042
|
+
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
|
1043
|
+
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
|
1044
|
+
if (n1 === void 0 || n2 === void 0) {
|
|
1045
|
+
const char = hex[hi] + hex[hi + 1];
|
|
1046
|
+
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
|
1047
|
+
}
|
|
1048
|
+
array[ai] = n1 * 16 + n2;
|
|
1049
|
+
}
|
|
1050
|
+
return array;
|
|
1051
|
+
}
|
|
724
1052
|
function createHasher(hashCons, info = {}) {
|
|
725
1053
|
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
726
1054
|
const tmp = hashCons(void 0);
|
|
@@ -1110,11 +1438,14 @@ import {
|
|
|
1110
1438
|
NostrKeyManager,
|
|
1111
1439
|
NIP04,
|
|
1112
1440
|
NIP17,
|
|
1441
|
+
NIP44,
|
|
1113
1442
|
Event as NostrEventClass,
|
|
1114
1443
|
EventKinds,
|
|
1115
1444
|
hashNametag,
|
|
1116
1445
|
NostrClient,
|
|
1117
|
-
Filter
|
|
1446
|
+
Filter,
|
|
1447
|
+
isChatMessage,
|
|
1448
|
+
isReadReceipt
|
|
1118
1449
|
} from "@unicitylabs/nostr-js-sdk";
|
|
1119
1450
|
|
|
1120
1451
|
// core/crypto.ts
|
|
@@ -1225,7 +1556,7 @@ function publicKeyToAddress(publicKey, prefix = "alpha", witnessVersion = 0) {
|
|
|
1225
1556
|
const programBytes = hash160ToBytes(pubKeyHash);
|
|
1226
1557
|
return encodeBech32(prefix, witnessVersion, programBytes);
|
|
1227
1558
|
}
|
|
1228
|
-
function
|
|
1559
|
+
function hexToBytes2(hex) {
|
|
1229
1560
|
const matches = hex.match(/../g);
|
|
1230
1561
|
if (!matches) {
|
|
1231
1562
|
return new Uint8Array(0);
|
|
@@ -1252,6 +1583,8 @@ function defaultUUIDGenerator() {
|
|
|
1252
1583
|
}
|
|
1253
1584
|
|
|
1254
1585
|
// transport/NostrTransportProvider.ts
|
|
1586
|
+
var COMPOSING_INDICATOR_KIND = 25050;
|
|
1587
|
+
var TIMESTAMP_RANDOMIZATION = 2 * 24 * 60 * 60;
|
|
1255
1588
|
var EVENT_KINDS = NOSTR_EVENT_KINDS;
|
|
1256
1589
|
function hashAddressForTag(address) {
|
|
1257
1590
|
const bytes = new TextEncoder().encode("unicity:address:" + address);
|
|
@@ -1332,6 +1665,10 @@ var NostrTransportProvider = class {
|
|
|
1332
1665
|
transferHandlers = /* @__PURE__ */ new Set();
|
|
1333
1666
|
paymentRequestHandlers = /* @__PURE__ */ new Set();
|
|
1334
1667
|
paymentRequestResponseHandlers = /* @__PURE__ */ new Set();
|
|
1668
|
+
readReceiptHandlers = /* @__PURE__ */ new Set();
|
|
1669
|
+
typingIndicatorHandlers = /* @__PURE__ */ new Set();
|
|
1670
|
+
composingHandlers = /* @__PURE__ */ new Set();
|
|
1671
|
+
pendingMessages = [];
|
|
1335
1672
|
broadcastHandlers = /* @__PURE__ */ new Map();
|
|
1336
1673
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
1337
1674
|
constructor(config) {
|
|
@@ -1583,6 +1920,18 @@ var NostrTransportProvider = class {
|
|
|
1583
1920
|
const wrappedContent = senderNametag ? JSON.stringify({ senderNametag, text: content }) : content;
|
|
1584
1921
|
const giftWrap = NIP17.createGiftWrap(this.keyManager, nostrRecipient, wrappedContent);
|
|
1585
1922
|
await this.publishEvent(giftWrap);
|
|
1923
|
+
const selfWrapContent = JSON.stringify({
|
|
1924
|
+
selfWrap: true,
|
|
1925
|
+
originalId: giftWrap.id,
|
|
1926
|
+
recipientPubkey,
|
|
1927
|
+
senderNametag,
|
|
1928
|
+
text: content
|
|
1929
|
+
});
|
|
1930
|
+
const selfPubkey = this.keyManager.getPublicKeyHex();
|
|
1931
|
+
const selfGiftWrap = NIP17.createGiftWrap(this.keyManager, selfPubkey, selfWrapContent);
|
|
1932
|
+
this.publishEvent(selfGiftWrap).catch((err) => {
|
|
1933
|
+
this.log("Self-wrap publish failed:", err);
|
|
1934
|
+
});
|
|
1586
1935
|
this.emitEvent({
|
|
1587
1936
|
type: "message:sent",
|
|
1588
1937
|
timestamp: Date.now(),
|
|
@@ -1592,6 +1941,18 @@ var NostrTransportProvider = class {
|
|
|
1592
1941
|
}
|
|
1593
1942
|
onMessage(handler) {
|
|
1594
1943
|
this.messageHandlers.add(handler);
|
|
1944
|
+
if (this.pendingMessages.length > 0) {
|
|
1945
|
+
const pending = this.pendingMessages;
|
|
1946
|
+
this.pendingMessages = [];
|
|
1947
|
+
this.log("Flushing", pending.length, "buffered messages to new handler");
|
|
1948
|
+
for (const message of pending) {
|
|
1949
|
+
try {
|
|
1950
|
+
handler(message);
|
|
1951
|
+
} catch (error) {
|
|
1952
|
+
this.log("Message handler error (buffered):", error);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1595
1956
|
return () => this.messageHandlers.delete(handler);
|
|
1596
1957
|
}
|
|
1597
1958
|
async sendTokenTransfer(recipientPubkey, payload) {
|
|
@@ -1681,6 +2042,50 @@ var NostrTransportProvider = class {
|
|
|
1681
2042
|
this.paymentRequestResponseHandlers.add(handler);
|
|
1682
2043
|
return () => this.paymentRequestResponseHandlers.delete(handler);
|
|
1683
2044
|
}
|
|
2045
|
+
// ===========================================================================
|
|
2046
|
+
// Read Receipts
|
|
2047
|
+
// ===========================================================================
|
|
2048
|
+
async sendReadReceipt(recipientTransportPubkey, messageEventId) {
|
|
2049
|
+
if (!this.keyManager) throw new Error("Not initialized");
|
|
2050
|
+
const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
|
|
2051
|
+
const event = NIP17.createReadReceipt(this.keyManager, nostrRecipient, messageEventId);
|
|
2052
|
+
await this.publishEvent(event);
|
|
2053
|
+
this.log("Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
|
|
2054
|
+
}
|
|
2055
|
+
onReadReceipt(handler) {
|
|
2056
|
+
this.readReceiptHandlers.add(handler);
|
|
2057
|
+
return () => this.readReceiptHandlers.delete(handler);
|
|
2058
|
+
}
|
|
2059
|
+
// ===========================================================================
|
|
2060
|
+
// Typing Indicators
|
|
2061
|
+
// ===========================================================================
|
|
2062
|
+
async sendTypingIndicator(recipientTransportPubkey) {
|
|
2063
|
+
if (!this.keyManager) throw new Error("Not initialized");
|
|
2064
|
+
const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
|
|
2065
|
+
const content = JSON.stringify({
|
|
2066
|
+
type: "typing",
|
|
2067
|
+
senderNametag: this.identity?.nametag
|
|
2068
|
+
});
|
|
2069
|
+
const event = NIP17.createGiftWrap(this.keyManager, nostrRecipient, content);
|
|
2070
|
+
await this.publishEvent(event);
|
|
2071
|
+
}
|
|
2072
|
+
onTypingIndicator(handler) {
|
|
2073
|
+
this.typingIndicatorHandlers.add(handler);
|
|
2074
|
+
return () => this.typingIndicatorHandlers.delete(handler);
|
|
2075
|
+
}
|
|
2076
|
+
// ===========================================================================
|
|
2077
|
+
// Composing Indicators (NIP-59 kind 25050)
|
|
2078
|
+
// ===========================================================================
|
|
2079
|
+
onComposing(handler) {
|
|
2080
|
+
this.composingHandlers.add(handler);
|
|
2081
|
+
return () => this.composingHandlers.delete(handler);
|
|
2082
|
+
}
|
|
2083
|
+
async sendComposingIndicator(recipientPubkey, content) {
|
|
2084
|
+
this.ensureReady();
|
|
2085
|
+
const nostrRecipient = recipientPubkey.length === 66 && (recipientPubkey.startsWith("02") || recipientPubkey.startsWith("03")) ? recipientPubkey.slice(2) : recipientPubkey;
|
|
2086
|
+
const giftWrap = this.createCustomKindGiftWrap(nostrRecipient, content, COMPOSING_INDICATOR_KIND);
|
|
2087
|
+
await this.publishEvent(giftWrap);
|
|
2088
|
+
}
|
|
1684
2089
|
/**
|
|
1685
2090
|
* Resolve any identifier to full peer information.
|
|
1686
2091
|
* Routes to the appropriate specific resolve method based on identifier format.
|
|
@@ -2134,11 +2539,98 @@ var NostrTransportProvider = class {
|
|
|
2134
2539
|
const pm = NIP17.unwrap(event, this.keyManager);
|
|
2135
2540
|
this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
|
|
2136
2541
|
if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
|
|
2137
|
-
|
|
2542
|
+
try {
|
|
2543
|
+
const parsed = JSON.parse(pm.content);
|
|
2544
|
+
if (parsed?.selfWrap && parsed.recipientPubkey) {
|
|
2545
|
+
this.log("Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
|
|
2546
|
+
const message2 = {
|
|
2547
|
+
id: parsed.originalId || pm.eventId,
|
|
2548
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2549
|
+
senderNametag: parsed.senderNametag,
|
|
2550
|
+
recipientTransportPubkey: parsed.recipientPubkey,
|
|
2551
|
+
content: parsed.text ?? "",
|
|
2552
|
+
timestamp: pm.timestamp * 1e3,
|
|
2553
|
+
encrypted: true,
|
|
2554
|
+
isSelfWrap: true
|
|
2555
|
+
};
|
|
2556
|
+
for (const handler of this.messageHandlers) {
|
|
2557
|
+
try {
|
|
2558
|
+
handler(message2);
|
|
2559
|
+
} catch (e) {
|
|
2560
|
+
this.log("Self-wrap handler error:", e);
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2565
|
+
} catch {
|
|
2566
|
+
}
|
|
2567
|
+
this.log("Skipping own non-self-wrap message");
|
|
2138
2568
|
return;
|
|
2139
2569
|
}
|
|
2140
|
-
if (pm
|
|
2141
|
-
this.log("
|
|
2570
|
+
if (isReadReceipt(pm)) {
|
|
2571
|
+
this.log("Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
|
|
2572
|
+
if (pm.replyToEventId) {
|
|
2573
|
+
const receipt = {
|
|
2574
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2575
|
+
messageEventId: pm.replyToEventId,
|
|
2576
|
+
timestamp: pm.timestamp * 1e3
|
|
2577
|
+
};
|
|
2578
|
+
for (const handler of this.readReceiptHandlers) {
|
|
2579
|
+
try {
|
|
2580
|
+
handler(receipt);
|
|
2581
|
+
} catch (e) {
|
|
2582
|
+
this.log("Read receipt handler error:", e);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
return;
|
|
2587
|
+
}
|
|
2588
|
+
if (pm.kind === COMPOSING_INDICATOR_KIND) {
|
|
2589
|
+
let senderNametag2;
|
|
2590
|
+
let expiresIn = 3e4;
|
|
2591
|
+
try {
|
|
2592
|
+
const parsed = JSON.parse(pm.content);
|
|
2593
|
+
senderNametag2 = parsed.senderNametag || void 0;
|
|
2594
|
+
expiresIn = parsed.expiresIn ?? 3e4;
|
|
2595
|
+
} catch {
|
|
2596
|
+
}
|
|
2597
|
+
const indicator = {
|
|
2598
|
+
senderPubkey: pm.senderPubkey,
|
|
2599
|
+
senderNametag: senderNametag2,
|
|
2600
|
+
expiresIn
|
|
2601
|
+
};
|
|
2602
|
+
this.log("Composing indicator from:", indicator.senderNametag || pm.senderPubkey?.slice(0, 16));
|
|
2603
|
+
for (const handler of this.composingHandlers) {
|
|
2604
|
+
try {
|
|
2605
|
+
handler(indicator);
|
|
2606
|
+
} catch (e) {
|
|
2607
|
+
this.log("Composing handler error:", e);
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
try {
|
|
2613
|
+
const parsed = JSON.parse(pm.content);
|
|
2614
|
+
if (parsed?.type === "typing") {
|
|
2615
|
+
this.log("Typing indicator from:", pm.senderPubkey?.slice(0, 16));
|
|
2616
|
+
const indicator = {
|
|
2617
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2618
|
+
senderNametag: parsed.senderNametag,
|
|
2619
|
+
timestamp: pm.timestamp * 1e3
|
|
2620
|
+
};
|
|
2621
|
+
for (const handler of this.typingIndicatorHandlers) {
|
|
2622
|
+
try {
|
|
2623
|
+
handler(indicator);
|
|
2624
|
+
} catch (e) {
|
|
2625
|
+
this.log("Typing handler error:", e);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
return;
|
|
2629
|
+
}
|
|
2630
|
+
} catch {
|
|
2631
|
+
}
|
|
2632
|
+
if (!isChatMessage(pm)) {
|
|
2633
|
+
this.log("Skipping unknown message kind:", pm.kind);
|
|
2142
2634
|
return;
|
|
2143
2635
|
}
|
|
2144
2636
|
let content = pm.content;
|
|
@@ -2153,7 +2645,9 @@ var NostrTransportProvider = class {
|
|
|
2153
2645
|
}
|
|
2154
2646
|
this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
|
|
2155
2647
|
const message = {
|
|
2156
|
-
id
|
|
2648
|
+
// Use outer gift wrap event.id so it matches the sender's stored giftWrap.id.
|
|
2649
|
+
// This ensures read receipts reference an ID the sender recognizes.
|
|
2650
|
+
id: event.id,
|
|
2157
2651
|
senderTransportPubkey: pm.senderPubkey,
|
|
2158
2652
|
senderNametag,
|
|
2159
2653
|
content,
|
|
@@ -2161,12 +2655,17 @@ var NostrTransportProvider = class {
|
|
|
2161
2655
|
encrypted: true
|
|
2162
2656
|
};
|
|
2163
2657
|
this.emitEvent({ type: "message:received", timestamp: Date.now() });
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2658
|
+
if (this.messageHandlers.size === 0) {
|
|
2659
|
+
this.log("No message handlers registered, buffering message for later delivery");
|
|
2660
|
+
this.pendingMessages.push(message);
|
|
2661
|
+
} else {
|
|
2662
|
+
this.log("Dispatching to", this.messageHandlers.size, "handlers");
|
|
2663
|
+
for (const handler of this.messageHandlers) {
|
|
2664
|
+
try {
|
|
2665
|
+
handler(message);
|
|
2666
|
+
} catch (error) {
|
|
2667
|
+
this.log("Message handler error:", error);
|
|
2668
|
+
}
|
|
2170
2669
|
}
|
|
2171
2670
|
}
|
|
2172
2671
|
} catch (err) {
|
|
@@ -2570,6 +3069,39 @@ var NostrTransportProvider = class {
|
|
|
2570
3069
|
}
|
|
2571
3070
|
}
|
|
2572
3071
|
}
|
|
3072
|
+
/**
|
|
3073
|
+
* Create a NIP-17 gift wrap with a custom inner rumor kind.
|
|
3074
|
+
* Replicates the three-layer NIP-59 envelope (rumor → seal → gift wrap)
|
|
3075
|
+
* because NIP17.createGiftWrap hardcodes kind 14 for the inner rumor.
|
|
3076
|
+
*/
|
|
3077
|
+
createCustomKindGiftWrap(recipientPubkeyHex, content, rumorKind) {
|
|
3078
|
+
const senderPubkey = this.keyManager.getPublicKeyHex();
|
|
3079
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
3080
|
+
const rumorTags = [["p", recipientPubkeyHex]];
|
|
3081
|
+
const rumorSerialized = JSON.stringify([0, senderPubkey, now, rumorKind, rumorTags, content]);
|
|
3082
|
+
const rumorId = bytesToHex(sha256(new TextEncoder().encode(rumorSerialized)));
|
|
3083
|
+
const rumor = { id: rumorId, pubkey: senderPubkey, created_at: now, kind: rumorKind, tags: rumorTags, content };
|
|
3084
|
+
const recipientPubkeyBytes = hexToBytes(recipientPubkeyHex);
|
|
3085
|
+
const encryptedRumor = NIP44.encrypt(JSON.stringify(rumor), this.keyManager.getPrivateKey(), recipientPubkeyBytes);
|
|
3086
|
+
const sealTimestamp = now + Math.floor(Math.random() * 2 * TIMESTAMP_RANDOMIZATION) - TIMESTAMP_RANDOMIZATION;
|
|
3087
|
+
const seal = NostrEventClass.create(this.keyManager, {
|
|
3088
|
+
kind: EventKinds.SEAL,
|
|
3089
|
+
tags: [],
|
|
3090
|
+
content: encryptedRumor,
|
|
3091
|
+
created_at: sealTimestamp
|
|
3092
|
+
});
|
|
3093
|
+
const ephemeralKeys = NostrKeyManager.generate();
|
|
3094
|
+
const encryptedSeal = NIP44.encrypt(JSON.stringify(seal.toJSON()), ephemeralKeys.getPrivateKey(), recipientPubkeyBytes);
|
|
3095
|
+
const wrapTimestamp = now + Math.floor(Math.random() * 2 * TIMESTAMP_RANDOMIZATION) - TIMESTAMP_RANDOMIZATION;
|
|
3096
|
+
const giftWrap = NostrEventClass.create(ephemeralKeys, {
|
|
3097
|
+
kind: EventKinds.GIFT_WRAP,
|
|
3098
|
+
tags: [["p", recipientPubkeyHex]],
|
|
3099
|
+
content: encryptedSeal,
|
|
3100
|
+
created_at: wrapTimestamp
|
|
3101
|
+
});
|
|
3102
|
+
ephemeralKeys.clear();
|
|
3103
|
+
return giftWrap;
|
|
3104
|
+
}
|
|
2573
3105
|
log(...args) {
|
|
2574
3106
|
if (this.config.debug) {
|
|
2575
3107
|
console.log("[NostrTransportProvider]", ...args);
|
|
@@ -3199,7 +3731,7 @@ async function loadLibp2pModules() {
|
|
|
3199
3731
|
};
|
|
3200
3732
|
}
|
|
3201
3733
|
function deriveEd25519KeyMaterial(privateKeyHex, info = IPNS_HKDF_INFO) {
|
|
3202
|
-
const walletSecret =
|
|
3734
|
+
const walletSecret = hexToBytes2(privateKeyHex);
|
|
3203
3735
|
const infoBytes = new TextEncoder().encode(info);
|
|
3204
3736
|
return hkdf(sha256, walletSecret, void 0, infoBytes, 32);
|
|
3205
3737
|
}
|
|
@@ -5697,6 +6229,11 @@ function resolveGroupChatConfig(network, config) {
|
|
|
5697
6229
|
relays: config.relays ?? [...netConfig.groupRelays]
|
|
5698
6230
|
};
|
|
5699
6231
|
}
|
|
6232
|
+
function resolveMarketConfig(config) {
|
|
6233
|
+
if (!config) return void 0;
|
|
6234
|
+
if (config === true) return {};
|
|
6235
|
+
return { apiUrl: config.apiUrl, timeout: config.timeout };
|
|
6236
|
+
}
|
|
5700
6237
|
|
|
5701
6238
|
// impl/browser/index.ts
|
|
5702
6239
|
if (typeof globalThis.Buffer === "undefined") {
|
|
@@ -5754,7 +6291,7 @@ function createBrowserProviders(config) {
|
|
|
5754
6291
|
const oracleConfig = resolveOracleConfig(network, config?.oracle);
|
|
5755
6292
|
const l1Config = resolveL1Config(network, config?.l1);
|
|
5756
6293
|
const tokenSyncConfig = resolveTokenSyncConfig(network, config?.tokenSync);
|
|
5757
|
-
const storage =
|
|
6294
|
+
const storage = createIndexedDBStorageProvider(config?.storage);
|
|
5758
6295
|
const priceConfig = resolvePriceConfig(config?.price, storage);
|
|
5759
6296
|
const ipfsConfig = tokenSyncConfig?.ipfs;
|
|
5760
6297
|
const ipfsTokenStorage = ipfsConfig?.enabled ? createBrowserIpfsStorageProvider({
|
|
@@ -5763,11 +6300,13 @@ function createBrowserProviders(config) {
|
|
|
5763
6300
|
// reuse debug-like flag
|
|
5764
6301
|
}) : void 0;
|
|
5765
6302
|
const groupChat = resolveGroupChatConfig(network, config?.groupChat);
|
|
6303
|
+
const market = resolveMarketConfig(config?.market);
|
|
5766
6304
|
const networkConfig = getNetworkConfig(network);
|
|
5767
6305
|
TokenRegistry.configure({ remoteUrl: networkConfig.tokenRegistryUrl, storage });
|
|
5768
6306
|
return {
|
|
5769
6307
|
storage,
|
|
5770
6308
|
groupChat,
|
|
6309
|
+
market,
|
|
5771
6310
|
transport: createNostrTransportProvider({
|
|
5772
6311
|
relays: transportConfig.relays,
|
|
5773
6312
|
timeout: transportConfig.timeout,
|
|
@@ -5794,6 +6333,7 @@ function createBrowserProviders(config) {
|
|
|
5794
6333
|
}
|
|
5795
6334
|
export {
|
|
5796
6335
|
BrowserTrustBaseLoader,
|
|
6336
|
+
IndexedDBStorageProvider,
|
|
5797
6337
|
IndexedDBTokenStorageProvider,
|
|
5798
6338
|
LocalStorageProvider,
|
|
5799
6339
|
NostrTransportProvider,
|
|
@@ -5803,6 +6343,7 @@ export {
|
|
|
5803
6343
|
createBrowserProviders,
|
|
5804
6344
|
createBrowserTrustBaseLoader,
|
|
5805
6345
|
createBrowserWebSocket,
|
|
6346
|
+
createIndexedDBStorageProvider,
|
|
5806
6347
|
createIndexedDBTokenStorageProvider,
|
|
5807
6348
|
createLocalStorageProvider,
|
|
5808
6349
|
createNostrTransportProvider,
|