@unicitylabs/sphere-sdk 0.4.2 → 0.4.4
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/core/index.cjs +37 -10
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +37 -10
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +183 -104
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +183 -104
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/index.cjs +37 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +37 -10
- package/dist/index.js.map +1 -1
- package/dist/l1/index.cjs +21 -3
- package/dist/l1/index.cjs.map +1 -1
- package/dist/l1/index.js +21 -3
- package/dist/l1/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -354,6 +354,7 @@ function createLocalStorageProvider(config) {
|
|
|
354
354
|
var DB_NAME = "sphere-storage";
|
|
355
355
|
var DB_VERSION = 1;
|
|
356
356
|
var STORE_NAME = "kv";
|
|
357
|
+
var connectionSeq = 0;
|
|
357
358
|
var IndexedDBStorageProvider = class {
|
|
358
359
|
id = "indexeddb-storage";
|
|
359
360
|
name = "IndexedDB Storage";
|
|
@@ -365,6 +366,8 @@ var IndexedDBStorageProvider = class {
|
|
|
365
366
|
identity = null;
|
|
366
367
|
status = "disconnected";
|
|
367
368
|
db = null;
|
|
369
|
+
/** Monotonic connection ID for tracing open/close pairs */
|
|
370
|
+
connId = 0;
|
|
368
371
|
constructor(config) {
|
|
369
372
|
this.prefix = config?.prefix ?? "sphere_";
|
|
370
373
|
this.dbName = config?.dbName ?? DB_NAME;
|
|
@@ -375,24 +378,35 @@ var IndexedDBStorageProvider = class {
|
|
|
375
378
|
// ===========================================================================
|
|
376
379
|
async connect() {
|
|
377
380
|
if (this.status === "connected" && this.db) return;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
this.
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
381
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
382
|
+
this.status = "connecting";
|
|
383
|
+
const t0 = Date.now();
|
|
384
|
+
console.log(`[IndexedDBStorage] connect: opening db=${this.dbName}, attempt=${attempt + 1}/2`);
|
|
385
|
+
try {
|
|
386
|
+
this.db = await Promise.race([
|
|
387
|
+
this.openDatabase(),
|
|
388
|
+
new Promise(
|
|
389
|
+
(_, reject) => setTimeout(() => reject(new Error("IndexedDB open timed out after 5s")), 5e3)
|
|
390
|
+
)
|
|
391
|
+
]);
|
|
392
|
+
this.status = "connected";
|
|
393
|
+
console.log(`[IndexedDBStorage] connect: connected db=${this.dbName} connId=${this.connId} (${Date.now() - t0}ms)`);
|
|
394
|
+
return;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
console.warn(`[IndexedDBStorage] connect: open failed db=${this.dbName} attempt=${attempt + 1} (${Date.now() - t0}ms):`, error);
|
|
397
|
+
if (attempt === 0) {
|
|
398
|
+
this.status = "disconnected";
|
|
399
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
this.status = "error";
|
|
403
|
+
throw new Error(`IndexedDB not available: ${error}`);
|
|
404
|
+
}
|
|
392
405
|
}
|
|
393
406
|
}
|
|
394
407
|
async disconnect() {
|
|
395
|
-
|
|
408
|
+
const cid = this.connId;
|
|
409
|
+
console.log(`[IndexedDBStorage] disconnect: db=${this.dbName} connId=${cid} wasConnected=${!!this.db}`);
|
|
396
410
|
if (this.db) {
|
|
397
411
|
this.db.close();
|
|
398
412
|
this.db = null;
|
|
@@ -449,32 +463,36 @@ var IndexedDBStorageProvider = class {
|
|
|
449
463
|
}
|
|
450
464
|
async clear(prefix) {
|
|
451
465
|
if (!prefix) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
console.warn(`[IndexedDBStorage] clear: deleteDatabase blocked for db=${this.dbName}`);
|
|
471
|
-
resolve();
|
|
472
|
-
};
|
|
473
|
-
} catch {
|
|
474
|
-
resolve();
|
|
466
|
+
const t0 = Date.now();
|
|
467
|
+
const prevConnId = this.connId;
|
|
468
|
+
console.log(`[IndexedDBStorage] clear: starting db=${this.dbName} connId=${prevConnId} status=${this.status} hasDb=${!!this.db}`);
|
|
469
|
+
try {
|
|
470
|
+
if (!this.db || this.status !== "connected") {
|
|
471
|
+
if (this.db) {
|
|
472
|
+
console.log(`[IndexedDBStorage] clear: closing stale handle connId=${prevConnId}`);
|
|
473
|
+
this.db.close();
|
|
474
|
+
this.db = null;
|
|
475
|
+
}
|
|
476
|
+
console.log(`[IndexedDBStorage] clear: opening fresh connection for wipe`);
|
|
477
|
+
this.db = await Promise.race([
|
|
478
|
+
this.openDatabase(),
|
|
479
|
+
new Promise(
|
|
480
|
+
(_, reject) => setTimeout(() => reject(new Error("open timed out")), 3e3)
|
|
481
|
+
)
|
|
482
|
+
]);
|
|
483
|
+
this.status = "connected";
|
|
475
484
|
}
|
|
476
|
-
|
|
477
|
-
|
|
485
|
+
await this.idbClear();
|
|
486
|
+
console.log(`[IndexedDBStorage] clear: store cleared db=${this.dbName} connId=${this.connId} (${Date.now() - t0}ms)`);
|
|
487
|
+
} catch (err) {
|
|
488
|
+
console.warn(`[IndexedDBStorage] clear: failed db=${this.dbName} (${Date.now() - t0}ms)`, err);
|
|
489
|
+
} finally {
|
|
490
|
+
if (this.db) {
|
|
491
|
+
this.db.close();
|
|
492
|
+
this.db = null;
|
|
493
|
+
}
|
|
494
|
+
this.status = "disconnected";
|
|
495
|
+
}
|
|
478
496
|
return;
|
|
479
497
|
}
|
|
480
498
|
this.ensureConnected();
|
|
@@ -540,9 +558,22 @@ var IndexedDBStorageProvider = class {
|
|
|
540
558
|
return new Promise((resolve, reject) => {
|
|
541
559
|
const request = indexedDB.open(this.dbName, DB_VERSION);
|
|
542
560
|
request.onerror = () => reject(request.error);
|
|
543
|
-
request.onsuccess = () =>
|
|
561
|
+
request.onsuccess = () => {
|
|
562
|
+
const db = request.result;
|
|
563
|
+
const cid = ++connectionSeq;
|
|
564
|
+
this.connId = cid;
|
|
565
|
+
db.onversionchange = () => {
|
|
566
|
+
console.log(`[IndexedDBStorage] onversionchange: auto-closing db=${this.dbName} connId=${cid}`);
|
|
567
|
+
db.close();
|
|
568
|
+
if (this.db === db) {
|
|
569
|
+
this.db = null;
|
|
570
|
+
this.status = "disconnected";
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
resolve(db);
|
|
574
|
+
};
|
|
544
575
|
request.onblocked = () => {
|
|
545
|
-
console.warn(
|
|
576
|
+
console.warn(`[IndexedDBStorage] open blocked by another connection, db=${this.dbName}`);
|
|
546
577
|
};
|
|
547
578
|
request.onupgradeneeded = (event) => {
|
|
548
579
|
const db = event.target.result;
|
|
@@ -621,18 +652,23 @@ var DB_NAME2 = "sphere-token-storage";
|
|
|
621
652
|
var DB_VERSION2 = 1;
|
|
622
653
|
var STORE_TOKENS = "tokens";
|
|
623
654
|
var STORE_META = "meta";
|
|
655
|
+
var connectionSeq2 = 0;
|
|
624
656
|
var IndexedDBTokenStorageProvider = class {
|
|
625
657
|
id = "indexeddb-token-storage";
|
|
626
658
|
name = "IndexedDB Token Storage";
|
|
627
659
|
type = "local";
|
|
628
660
|
dbNamePrefix;
|
|
629
661
|
dbName;
|
|
662
|
+
debug;
|
|
630
663
|
db = null;
|
|
631
664
|
status = "disconnected";
|
|
632
665
|
identity = null;
|
|
666
|
+
/** Monotonic connection ID for tracing open/close pairs */
|
|
667
|
+
connId = 0;
|
|
633
668
|
constructor(config) {
|
|
634
669
|
this.dbNamePrefix = config?.dbNamePrefix ?? DB_NAME2;
|
|
635
670
|
this.dbName = this.dbNamePrefix;
|
|
671
|
+
this.debug = config?.debug ?? false;
|
|
636
672
|
}
|
|
637
673
|
setIdentity(identity) {
|
|
638
674
|
this.identity = identity;
|
|
@@ -640,28 +676,31 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
640
676
|
const addressId = getAddressId(identity.directAddress);
|
|
641
677
|
this.dbName = `${this.dbNamePrefix}-${addressId}`;
|
|
642
678
|
}
|
|
643
|
-
console.log(`[IndexedDBTokenStorage] setIdentity
|
|
679
|
+
console.log(`[IndexedDBTokenStorage] setIdentity: db=${this.dbName}`);
|
|
644
680
|
}
|
|
645
681
|
async initialize() {
|
|
682
|
+
const prevConnId = this.connId;
|
|
683
|
+
const t0 = Date.now();
|
|
646
684
|
try {
|
|
647
685
|
if (this.db) {
|
|
648
|
-
console.log(`[IndexedDBTokenStorage] initialize: closing existing
|
|
686
|
+
console.log(`[IndexedDBTokenStorage] initialize: closing existing connId=${prevConnId} before re-open (db=${this.dbName})`);
|
|
649
687
|
this.db.close();
|
|
650
688
|
this.db = null;
|
|
651
689
|
}
|
|
652
690
|
console.log(`[IndexedDBTokenStorage] initialize: opening db=${this.dbName}`);
|
|
653
691
|
this.db = await this.openDatabase();
|
|
654
692
|
this.status = "connected";
|
|
655
|
-
console.log(`[IndexedDBTokenStorage] initialize: connected
|
|
693
|
+
console.log(`[IndexedDBTokenStorage] initialize: connected db=${this.dbName} connId=${this.connId} (${Date.now() - t0}ms)`);
|
|
656
694
|
return true;
|
|
657
695
|
} catch (error) {
|
|
658
|
-
console.error(
|
|
696
|
+
console.error(`[IndexedDBTokenStorage] initialize: failed db=${this.dbName} (${Date.now() - t0}ms):`, error);
|
|
659
697
|
this.status = "error";
|
|
660
698
|
return false;
|
|
661
699
|
}
|
|
662
700
|
}
|
|
663
701
|
async shutdown() {
|
|
664
|
-
|
|
702
|
+
const cid = this.connId;
|
|
703
|
+
console.log(`[IndexedDBTokenStorage] shutdown: db=${this.dbName} connId=${cid} wasConnected=${!!this.db}`);
|
|
665
704
|
if (this.db) {
|
|
666
705
|
this.db.close();
|
|
667
706
|
this.db = null;
|
|
@@ -819,56 +858,32 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
819
858
|
return meta !== null;
|
|
820
859
|
}
|
|
821
860
|
async clear() {
|
|
861
|
+
const t0 = Date.now();
|
|
822
862
|
try {
|
|
823
|
-
console.log(`[IndexedDBTokenStorage] clear: starting, db=${this.dbName}, wasConnected=${!!this.db}`);
|
|
824
863
|
if (this.db) {
|
|
825
864
|
this.db.close();
|
|
826
865
|
this.db = null;
|
|
827
866
|
}
|
|
828
867
|
this.status = "disconnected";
|
|
829
|
-
const dbNames = [this.dbName];
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
const dbs = await Promise.race([
|
|
833
|
-
indexedDB.databases(),
|
|
834
|
-
new Promise(
|
|
835
|
-
(_, reject) => setTimeout(() => reject(new Error("timeout")), 1500)
|
|
836
|
-
)
|
|
837
|
-
]);
|
|
838
|
-
for (const dbInfo of dbs) {
|
|
839
|
-
if (dbInfo.name && dbInfo.name.startsWith(this.dbNamePrefix) && dbInfo.name !== this.dbName) {
|
|
840
|
-
dbNames.push(dbInfo.name);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
} catch {
|
|
844
|
-
}
|
|
868
|
+
const dbNames = /* @__PURE__ */ new Set([this.dbName]);
|
|
869
|
+
for (const name of await this.findPrefixedDatabases()) {
|
|
870
|
+
dbNames.add(name);
|
|
845
871
|
}
|
|
846
|
-
console.log(`[IndexedDBTokenStorage] clear:
|
|
847
|
-
await Promise.
|
|
848
|
-
(name) =>
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
req.onblocked = () => {
|
|
860
|
-
console.warn(`[IndexedDBTokenStorage] clear: deleteDatabase blocked for db=${name}`);
|
|
861
|
-
resolve();
|
|
862
|
-
};
|
|
863
|
-
} catch {
|
|
864
|
-
resolve();
|
|
865
|
-
}
|
|
866
|
-
})
|
|
867
|
-
));
|
|
868
|
-
console.log(`[IndexedDBTokenStorage] clear: done`);
|
|
869
|
-
return true;
|
|
872
|
+
console.log(`[IndexedDBTokenStorage] clear: clearing ${dbNames.size} database(s) (${[...dbNames].join(", ")})`);
|
|
873
|
+
const results = await Promise.allSettled(
|
|
874
|
+
[...dbNames].map((name) => this.clearDatabaseStores(name))
|
|
875
|
+
);
|
|
876
|
+
const failed = results.filter((r) => r.status === "rejected");
|
|
877
|
+
if (failed.length > 0) {
|
|
878
|
+
console.warn(
|
|
879
|
+
`[IndexedDBTokenStorage] clear: ${failed.length}/${dbNames.size} failed (${Date.now() - t0}ms)`,
|
|
880
|
+
failed.map((r) => r.reason)
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
console.log(`[IndexedDBTokenStorage] clear: done ${dbNames.size} database(s) (${Date.now() - t0}ms)`);
|
|
884
|
+
return failed.length === 0;
|
|
870
885
|
} catch (err) {
|
|
871
|
-
console.warn(
|
|
886
|
+
console.warn(`[IndexedDBTokenStorage] clear: failed (${Date.now() - t0}ms)`, err);
|
|
872
887
|
return false;
|
|
873
888
|
}
|
|
874
889
|
}
|
|
@@ -878,11 +893,23 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
878
893
|
openDatabase() {
|
|
879
894
|
return new Promise((resolve, reject) => {
|
|
880
895
|
const request = indexedDB.open(this.dbName, DB_VERSION2);
|
|
881
|
-
request.onerror = () =>
|
|
882
|
-
reject(request.error);
|
|
883
|
-
};
|
|
896
|
+
request.onerror = () => reject(request.error);
|
|
884
897
|
request.onsuccess = () => {
|
|
885
|
-
|
|
898
|
+
const db = request.result;
|
|
899
|
+
const cid = ++connectionSeq2;
|
|
900
|
+
this.connId = cid;
|
|
901
|
+
db.onversionchange = () => {
|
|
902
|
+
console.log(`[IndexedDBTokenStorage] onversionchange: auto-closing db=${this.dbName} connId=${cid}`);
|
|
903
|
+
db.close();
|
|
904
|
+
if (this.db === db) {
|
|
905
|
+
this.db = null;
|
|
906
|
+
this.status = "disconnected";
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
resolve(db);
|
|
910
|
+
};
|
|
911
|
+
request.onblocked = () => {
|
|
912
|
+
console.warn(`[IndexedDBTokenStorage] open blocked by another connection, db=${this.dbName}`);
|
|
886
913
|
};
|
|
887
914
|
request.onupgradeneeded = (event) => {
|
|
888
915
|
const db = event.target.result;
|
|
@@ -947,18 +974,70 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
947
974
|
request.onsuccess = () => resolve();
|
|
948
975
|
});
|
|
949
976
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
977
|
+
/**
|
|
978
|
+
* Find all IndexedDB databases with our prefix.
|
|
979
|
+
* Returns empty array if indexedDB.databases() is unavailable (older browsers).
|
|
980
|
+
*/
|
|
981
|
+
async findPrefixedDatabases() {
|
|
982
|
+
if (typeof indexedDB.databases !== "function") return [];
|
|
983
|
+
try {
|
|
984
|
+
const allDbs = await Promise.race([
|
|
985
|
+
indexedDB.databases(),
|
|
986
|
+
new Promise(
|
|
987
|
+
(_, reject) => setTimeout(() => reject(new Error("databases() timed out")), 1500)
|
|
988
|
+
)
|
|
989
|
+
]);
|
|
990
|
+
return allDbs.map((info) => info.name).filter((name) => !!name && name.startsWith(this.dbNamePrefix));
|
|
991
|
+
} catch {
|
|
992
|
+
return [];
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Clear all object stores in a single database.
|
|
997
|
+
* Opens a temporary connection, clears STORE_TOKENS and STORE_META, then closes.
|
|
998
|
+
* Uses IDBObjectStore.clear() which is a normal readwrite transaction — cannot
|
|
999
|
+
* be blocked by other connections (unlike deleteDatabase()).
|
|
1000
|
+
*/
|
|
1001
|
+
async clearDatabaseStores(dbName) {
|
|
1002
|
+
const db = await Promise.race([
|
|
1003
|
+
new Promise((resolve, reject) => {
|
|
1004
|
+
const req = indexedDB.open(dbName, DB_VERSION2);
|
|
1005
|
+
req.onerror = () => reject(req.error);
|
|
1006
|
+
req.onsuccess = () => {
|
|
1007
|
+
const db2 = req.result;
|
|
1008
|
+
db2.onversionchange = () => {
|
|
1009
|
+
db2.close();
|
|
1010
|
+
};
|
|
1011
|
+
resolve(db2);
|
|
1012
|
+
};
|
|
1013
|
+
req.onupgradeneeded = (event) => {
|
|
1014
|
+
const db2 = event.target.result;
|
|
1015
|
+
if (!db2.objectStoreNames.contains(STORE_TOKENS)) {
|
|
1016
|
+
db2.createObjectStore(STORE_TOKENS, { keyPath: "id" });
|
|
1017
|
+
}
|
|
1018
|
+
if (!db2.objectStoreNames.contains(STORE_META)) {
|
|
1019
|
+
db2.createObjectStore(STORE_META);
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
}),
|
|
1023
|
+
new Promise(
|
|
1024
|
+
(_, reject) => setTimeout(() => reject(new Error(`open timed out: ${dbName}`)), 3e3)
|
|
1025
|
+
)
|
|
1026
|
+
]);
|
|
1027
|
+
try {
|
|
1028
|
+
for (const storeName of [STORE_TOKENS, STORE_META]) {
|
|
1029
|
+
if (db.objectStoreNames.contains(storeName)) {
|
|
1030
|
+
await new Promise((resolve, reject) => {
|
|
1031
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
1032
|
+
const req = tx.objectStore(storeName).clear();
|
|
1033
|
+
req.onerror = () => reject(req.error);
|
|
1034
|
+
req.onsuccess = () => resolve();
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
955
1037
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
request.onerror = () => reject(request.error);
|
|
960
|
-
request.onsuccess = () => resolve();
|
|
961
|
-
});
|
|
1038
|
+
} finally {
|
|
1039
|
+
db.close();
|
|
1040
|
+
}
|
|
962
1041
|
}
|
|
963
1042
|
};
|
|
964
1043
|
function createIndexedDBTokenStorageProvider(config) {
|