@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
|
@@ -414,6 +414,7 @@ function createLocalStorageProvider(config) {
|
|
|
414
414
|
var DB_NAME = "sphere-storage";
|
|
415
415
|
var DB_VERSION = 1;
|
|
416
416
|
var STORE_NAME = "kv";
|
|
417
|
+
var connectionSeq = 0;
|
|
417
418
|
var IndexedDBStorageProvider = class {
|
|
418
419
|
id = "indexeddb-storage";
|
|
419
420
|
name = "IndexedDB Storage";
|
|
@@ -425,6 +426,8 @@ var IndexedDBStorageProvider = class {
|
|
|
425
426
|
identity = null;
|
|
426
427
|
status = "disconnected";
|
|
427
428
|
db = null;
|
|
429
|
+
/** Monotonic connection ID for tracing open/close pairs */
|
|
430
|
+
connId = 0;
|
|
428
431
|
constructor(config) {
|
|
429
432
|
this.prefix = config?.prefix ?? "sphere_";
|
|
430
433
|
this.dbName = config?.dbName ?? DB_NAME;
|
|
@@ -435,24 +438,35 @@ var IndexedDBStorageProvider = class {
|
|
|
435
438
|
// ===========================================================================
|
|
436
439
|
async connect() {
|
|
437
440
|
if (this.status === "connected" && this.db) return;
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
this.
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
(
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
441
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
442
|
+
this.status = "connecting";
|
|
443
|
+
const t0 = Date.now();
|
|
444
|
+
console.log(`[IndexedDBStorage] connect: opening db=${this.dbName}, attempt=${attempt + 1}/2`);
|
|
445
|
+
try {
|
|
446
|
+
this.db = await Promise.race([
|
|
447
|
+
this.openDatabase(),
|
|
448
|
+
new Promise(
|
|
449
|
+
(_, reject) => setTimeout(() => reject(new Error("IndexedDB open timed out after 5s")), 5e3)
|
|
450
|
+
)
|
|
451
|
+
]);
|
|
452
|
+
this.status = "connected";
|
|
453
|
+
console.log(`[IndexedDBStorage] connect: connected db=${this.dbName} connId=${this.connId} (${Date.now() - t0}ms)`);
|
|
454
|
+
return;
|
|
455
|
+
} catch (error) {
|
|
456
|
+
console.warn(`[IndexedDBStorage] connect: open failed db=${this.dbName} attempt=${attempt + 1} (${Date.now() - t0}ms):`, error);
|
|
457
|
+
if (attempt === 0) {
|
|
458
|
+
this.status = "disconnected";
|
|
459
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
this.status = "error";
|
|
463
|
+
throw new Error(`IndexedDB not available: ${error}`);
|
|
464
|
+
}
|
|
452
465
|
}
|
|
453
466
|
}
|
|
454
467
|
async disconnect() {
|
|
455
|
-
|
|
468
|
+
const cid = this.connId;
|
|
469
|
+
console.log(`[IndexedDBStorage] disconnect: db=${this.dbName} connId=${cid} wasConnected=${!!this.db}`);
|
|
456
470
|
if (this.db) {
|
|
457
471
|
this.db.close();
|
|
458
472
|
this.db = null;
|
|
@@ -509,32 +523,36 @@ var IndexedDBStorageProvider = class {
|
|
|
509
523
|
}
|
|
510
524
|
async clear(prefix) {
|
|
511
525
|
if (!prefix) {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
console.warn(`[IndexedDBStorage] clear: deleteDatabase blocked for db=${this.dbName}`);
|
|
531
|
-
resolve();
|
|
532
|
-
};
|
|
533
|
-
} catch {
|
|
534
|
-
resolve();
|
|
526
|
+
const t0 = Date.now();
|
|
527
|
+
const prevConnId = this.connId;
|
|
528
|
+
console.log(`[IndexedDBStorage] clear: starting db=${this.dbName} connId=${prevConnId} status=${this.status} hasDb=${!!this.db}`);
|
|
529
|
+
try {
|
|
530
|
+
if (!this.db || this.status !== "connected") {
|
|
531
|
+
if (this.db) {
|
|
532
|
+
console.log(`[IndexedDBStorage] clear: closing stale handle connId=${prevConnId}`);
|
|
533
|
+
this.db.close();
|
|
534
|
+
this.db = null;
|
|
535
|
+
}
|
|
536
|
+
console.log(`[IndexedDBStorage] clear: opening fresh connection for wipe`);
|
|
537
|
+
this.db = await Promise.race([
|
|
538
|
+
this.openDatabase(),
|
|
539
|
+
new Promise(
|
|
540
|
+
(_, reject) => setTimeout(() => reject(new Error("open timed out")), 3e3)
|
|
541
|
+
)
|
|
542
|
+
]);
|
|
543
|
+
this.status = "connected";
|
|
535
544
|
}
|
|
536
|
-
|
|
537
|
-
|
|
545
|
+
await this.idbClear();
|
|
546
|
+
console.log(`[IndexedDBStorage] clear: store cleared db=${this.dbName} connId=${this.connId} (${Date.now() - t0}ms)`);
|
|
547
|
+
} catch (err) {
|
|
548
|
+
console.warn(`[IndexedDBStorage] clear: failed db=${this.dbName} (${Date.now() - t0}ms)`, err);
|
|
549
|
+
} finally {
|
|
550
|
+
if (this.db) {
|
|
551
|
+
this.db.close();
|
|
552
|
+
this.db = null;
|
|
553
|
+
}
|
|
554
|
+
this.status = "disconnected";
|
|
555
|
+
}
|
|
538
556
|
return;
|
|
539
557
|
}
|
|
540
558
|
this.ensureConnected();
|
|
@@ -600,9 +618,22 @@ var IndexedDBStorageProvider = class {
|
|
|
600
618
|
return new Promise((resolve, reject) => {
|
|
601
619
|
const request = indexedDB.open(this.dbName, DB_VERSION);
|
|
602
620
|
request.onerror = () => reject(request.error);
|
|
603
|
-
request.onsuccess = () =>
|
|
621
|
+
request.onsuccess = () => {
|
|
622
|
+
const db = request.result;
|
|
623
|
+
const cid = ++connectionSeq;
|
|
624
|
+
this.connId = cid;
|
|
625
|
+
db.onversionchange = () => {
|
|
626
|
+
console.log(`[IndexedDBStorage] onversionchange: auto-closing db=${this.dbName} connId=${cid}`);
|
|
627
|
+
db.close();
|
|
628
|
+
if (this.db === db) {
|
|
629
|
+
this.db = null;
|
|
630
|
+
this.status = "disconnected";
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
resolve(db);
|
|
634
|
+
};
|
|
604
635
|
request.onblocked = () => {
|
|
605
|
-
console.warn(
|
|
636
|
+
console.warn(`[IndexedDBStorage] open blocked by another connection, db=${this.dbName}`);
|
|
606
637
|
};
|
|
607
638
|
request.onupgradeneeded = (event) => {
|
|
608
639
|
const db = event.target.result;
|
|
@@ -681,18 +712,23 @@ var DB_NAME2 = "sphere-token-storage";
|
|
|
681
712
|
var DB_VERSION2 = 1;
|
|
682
713
|
var STORE_TOKENS = "tokens";
|
|
683
714
|
var STORE_META = "meta";
|
|
715
|
+
var connectionSeq2 = 0;
|
|
684
716
|
var IndexedDBTokenStorageProvider = class {
|
|
685
717
|
id = "indexeddb-token-storage";
|
|
686
718
|
name = "IndexedDB Token Storage";
|
|
687
719
|
type = "local";
|
|
688
720
|
dbNamePrefix;
|
|
689
721
|
dbName;
|
|
722
|
+
debug;
|
|
690
723
|
db = null;
|
|
691
724
|
status = "disconnected";
|
|
692
725
|
identity = null;
|
|
726
|
+
/** Monotonic connection ID for tracing open/close pairs */
|
|
727
|
+
connId = 0;
|
|
693
728
|
constructor(config) {
|
|
694
729
|
this.dbNamePrefix = config?.dbNamePrefix ?? DB_NAME2;
|
|
695
730
|
this.dbName = this.dbNamePrefix;
|
|
731
|
+
this.debug = config?.debug ?? false;
|
|
696
732
|
}
|
|
697
733
|
setIdentity(identity) {
|
|
698
734
|
this.identity = identity;
|
|
@@ -700,28 +736,31 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
700
736
|
const addressId = getAddressId(identity.directAddress);
|
|
701
737
|
this.dbName = `${this.dbNamePrefix}-${addressId}`;
|
|
702
738
|
}
|
|
703
|
-
console.log(`[IndexedDBTokenStorage] setIdentity
|
|
739
|
+
console.log(`[IndexedDBTokenStorage] setIdentity: db=${this.dbName}`);
|
|
704
740
|
}
|
|
705
741
|
async initialize() {
|
|
742
|
+
const prevConnId = this.connId;
|
|
743
|
+
const t0 = Date.now();
|
|
706
744
|
try {
|
|
707
745
|
if (this.db) {
|
|
708
|
-
console.log(`[IndexedDBTokenStorage] initialize: closing existing
|
|
746
|
+
console.log(`[IndexedDBTokenStorage] initialize: closing existing connId=${prevConnId} before re-open (db=${this.dbName})`);
|
|
709
747
|
this.db.close();
|
|
710
748
|
this.db = null;
|
|
711
749
|
}
|
|
712
750
|
console.log(`[IndexedDBTokenStorage] initialize: opening db=${this.dbName}`);
|
|
713
751
|
this.db = await this.openDatabase();
|
|
714
752
|
this.status = "connected";
|
|
715
|
-
console.log(`[IndexedDBTokenStorage] initialize: connected
|
|
753
|
+
console.log(`[IndexedDBTokenStorage] initialize: connected db=${this.dbName} connId=${this.connId} (${Date.now() - t0}ms)`);
|
|
716
754
|
return true;
|
|
717
755
|
} catch (error) {
|
|
718
|
-
console.error(
|
|
756
|
+
console.error(`[IndexedDBTokenStorage] initialize: failed db=${this.dbName} (${Date.now() - t0}ms):`, error);
|
|
719
757
|
this.status = "error";
|
|
720
758
|
return false;
|
|
721
759
|
}
|
|
722
760
|
}
|
|
723
761
|
async shutdown() {
|
|
724
|
-
|
|
762
|
+
const cid = this.connId;
|
|
763
|
+
console.log(`[IndexedDBTokenStorage] shutdown: db=${this.dbName} connId=${cid} wasConnected=${!!this.db}`);
|
|
725
764
|
if (this.db) {
|
|
726
765
|
this.db.close();
|
|
727
766
|
this.db = null;
|
|
@@ -879,56 +918,32 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
879
918
|
return meta !== null;
|
|
880
919
|
}
|
|
881
920
|
async clear() {
|
|
921
|
+
const t0 = Date.now();
|
|
882
922
|
try {
|
|
883
|
-
console.log(`[IndexedDBTokenStorage] clear: starting, db=${this.dbName}, wasConnected=${!!this.db}`);
|
|
884
923
|
if (this.db) {
|
|
885
924
|
this.db.close();
|
|
886
925
|
this.db = null;
|
|
887
926
|
}
|
|
888
927
|
this.status = "disconnected";
|
|
889
|
-
const dbNames = [this.dbName];
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
const dbs = await Promise.race([
|
|
893
|
-
indexedDB.databases(),
|
|
894
|
-
new Promise(
|
|
895
|
-
(_, reject) => setTimeout(() => reject(new Error("timeout")), 1500)
|
|
896
|
-
)
|
|
897
|
-
]);
|
|
898
|
-
for (const dbInfo of dbs) {
|
|
899
|
-
if (dbInfo.name && dbInfo.name.startsWith(this.dbNamePrefix) && dbInfo.name !== this.dbName) {
|
|
900
|
-
dbNames.push(dbInfo.name);
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
} catch {
|
|
904
|
-
}
|
|
928
|
+
const dbNames = /* @__PURE__ */ new Set([this.dbName]);
|
|
929
|
+
for (const name of await this.findPrefixedDatabases()) {
|
|
930
|
+
dbNames.add(name);
|
|
905
931
|
}
|
|
906
|
-
console.log(`[IndexedDBTokenStorage] clear:
|
|
907
|
-
await Promise.
|
|
908
|
-
(name) =>
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
req.onblocked = () => {
|
|
920
|
-
console.warn(`[IndexedDBTokenStorage] clear: deleteDatabase blocked for db=${name}`);
|
|
921
|
-
resolve();
|
|
922
|
-
};
|
|
923
|
-
} catch {
|
|
924
|
-
resolve();
|
|
925
|
-
}
|
|
926
|
-
})
|
|
927
|
-
));
|
|
928
|
-
console.log(`[IndexedDBTokenStorage] clear: done`);
|
|
929
|
-
return true;
|
|
932
|
+
console.log(`[IndexedDBTokenStorage] clear: clearing ${dbNames.size} database(s) (${[...dbNames].join(", ")})`);
|
|
933
|
+
const results = await Promise.allSettled(
|
|
934
|
+
[...dbNames].map((name) => this.clearDatabaseStores(name))
|
|
935
|
+
);
|
|
936
|
+
const failed = results.filter((r) => r.status === "rejected");
|
|
937
|
+
if (failed.length > 0) {
|
|
938
|
+
console.warn(
|
|
939
|
+
`[IndexedDBTokenStorage] clear: ${failed.length}/${dbNames.size} failed (${Date.now() - t0}ms)`,
|
|
940
|
+
failed.map((r) => r.reason)
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
console.log(`[IndexedDBTokenStorage] clear: done ${dbNames.size} database(s) (${Date.now() - t0}ms)`);
|
|
944
|
+
return failed.length === 0;
|
|
930
945
|
} catch (err) {
|
|
931
|
-
console.warn(
|
|
946
|
+
console.warn(`[IndexedDBTokenStorage] clear: failed (${Date.now() - t0}ms)`, err);
|
|
932
947
|
return false;
|
|
933
948
|
}
|
|
934
949
|
}
|
|
@@ -938,11 +953,23 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
938
953
|
openDatabase() {
|
|
939
954
|
return new Promise((resolve, reject) => {
|
|
940
955
|
const request = indexedDB.open(this.dbName, DB_VERSION2);
|
|
941
|
-
request.onerror = () =>
|
|
942
|
-
reject(request.error);
|
|
943
|
-
};
|
|
956
|
+
request.onerror = () => reject(request.error);
|
|
944
957
|
request.onsuccess = () => {
|
|
945
|
-
|
|
958
|
+
const db = request.result;
|
|
959
|
+
const cid = ++connectionSeq2;
|
|
960
|
+
this.connId = cid;
|
|
961
|
+
db.onversionchange = () => {
|
|
962
|
+
console.log(`[IndexedDBTokenStorage] onversionchange: auto-closing db=${this.dbName} connId=${cid}`);
|
|
963
|
+
db.close();
|
|
964
|
+
if (this.db === db) {
|
|
965
|
+
this.db = null;
|
|
966
|
+
this.status = "disconnected";
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
resolve(db);
|
|
970
|
+
};
|
|
971
|
+
request.onblocked = () => {
|
|
972
|
+
console.warn(`[IndexedDBTokenStorage] open blocked by another connection, db=${this.dbName}`);
|
|
946
973
|
};
|
|
947
974
|
request.onupgradeneeded = (event) => {
|
|
948
975
|
const db = event.target.result;
|
|
@@ -1007,18 +1034,70 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
1007
1034
|
request.onsuccess = () => resolve();
|
|
1008
1035
|
});
|
|
1009
1036
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1037
|
+
/**
|
|
1038
|
+
* Find all IndexedDB databases with our prefix.
|
|
1039
|
+
* Returns empty array if indexedDB.databases() is unavailable (older browsers).
|
|
1040
|
+
*/
|
|
1041
|
+
async findPrefixedDatabases() {
|
|
1042
|
+
if (typeof indexedDB.databases !== "function") return [];
|
|
1043
|
+
try {
|
|
1044
|
+
const allDbs = await Promise.race([
|
|
1045
|
+
indexedDB.databases(),
|
|
1046
|
+
new Promise(
|
|
1047
|
+
(_, reject) => setTimeout(() => reject(new Error("databases() timed out")), 1500)
|
|
1048
|
+
)
|
|
1049
|
+
]);
|
|
1050
|
+
return allDbs.map((info) => info.name).filter((name) => !!name && name.startsWith(this.dbNamePrefix));
|
|
1051
|
+
} catch {
|
|
1052
|
+
return [];
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Clear all object stores in a single database.
|
|
1057
|
+
* Opens a temporary connection, clears STORE_TOKENS and STORE_META, then closes.
|
|
1058
|
+
* Uses IDBObjectStore.clear() which is a normal readwrite transaction — cannot
|
|
1059
|
+
* be blocked by other connections (unlike deleteDatabase()).
|
|
1060
|
+
*/
|
|
1061
|
+
async clearDatabaseStores(dbName) {
|
|
1062
|
+
const db = await Promise.race([
|
|
1063
|
+
new Promise((resolve, reject) => {
|
|
1064
|
+
const req = indexedDB.open(dbName, DB_VERSION2);
|
|
1065
|
+
req.onerror = () => reject(req.error);
|
|
1066
|
+
req.onsuccess = () => {
|
|
1067
|
+
const db2 = req.result;
|
|
1068
|
+
db2.onversionchange = () => {
|
|
1069
|
+
db2.close();
|
|
1070
|
+
};
|
|
1071
|
+
resolve(db2);
|
|
1072
|
+
};
|
|
1073
|
+
req.onupgradeneeded = (event) => {
|
|
1074
|
+
const db2 = event.target.result;
|
|
1075
|
+
if (!db2.objectStoreNames.contains(STORE_TOKENS)) {
|
|
1076
|
+
db2.createObjectStore(STORE_TOKENS, { keyPath: "id" });
|
|
1077
|
+
}
|
|
1078
|
+
if (!db2.objectStoreNames.contains(STORE_META)) {
|
|
1079
|
+
db2.createObjectStore(STORE_META);
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
}),
|
|
1083
|
+
new Promise(
|
|
1084
|
+
(_, reject) => setTimeout(() => reject(new Error(`open timed out: ${dbName}`)), 3e3)
|
|
1085
|
+
)
|
|
1086
|
+
]);
|
|
1087
|
+
try {
|
|
1088
|
+
for (const storeName of [STORE_TOKENS, STORE_META]) {
|
|
1089
|
+
if (db.objectStoreNames.contains(storeName)) {
|
|
1090
|
+
await new Promise((resolve, reject) => {
|
|
1091
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
1092
|
+
const req = tx.objectStore(storeName).clear();
|
|
1093
|
+
req.onerror = () => reject(req.error);
|
|
1094
|
+
req.onsuccess = () => resolve();
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1015
1097
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
request.onerror = () => reject(request.error);
|
|
1020
|
-
request.onsuccess = () => resolve();
|
|
1021
|
-
});
|
|
1098
|
+
} finally {
|
|
1099
|
+
db.close();
|
|
1100
|
+
}
|
|
1022
1101
|
}
|
|
1023
1102
|
};
|
|
1024
1103
|
function createIndexedDBTokenStorageProvider(config) {
|