@choksheak/ts-utils 0.3.6 → 0.3.7
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/arrayBuffer.cjs +39 -10
- package/arrayBuffer.min.cjs +1 -1
- package/arrayBuffer.min.cjs.map +1 -1
- package/arrayBuffer.min.mjs +1 -1
- package/arrayBuffer.min.mjs.map +1 -1
- package/arrayBuffer.mjs +10 -7
- package/asNumber.cjs +38 -6
- package/asNumber.min.cjs +1 -1
- package/asNumber.min.cjs.map +1 -1
- package/asNumber.min.mjs +1 -1
- package/asNumber.min.mjs.map +1 -1
- package/asNumber.mjs +11 -4
- package/assert.cjs +27 -4
- package/assert.min.cjs +1 -1
- package/assert.min.cjs.map +1 -1
- package/assert.min.mjs +1 -1
- package/assert.min.mjs.map +1 -1
- package/assert.mjs +0 -2
- package/base64Url.cjs +29 -5
- package/base64Url.min.cjs +1 -1
- package/base64Url.min.cjs.map +1 -1
- package/base64Url.min.mjs +1 -1
- package/base64Url.min.mjs.map +1 -1
- package/base64Url.mjs +0 -2
- package/capLength.cjs +71 -7
- package/capLength.min.cjs +5 -1
- package/capLength.min.cjs.map +1 -1
- package/capLength.min.mjs +5 -1
- package/capLength.min.mjs.map +1 -1
- package/capLength.mjs +41 -4
- package/concatIterators.cjs +27 -4
- package/concatIterators.min.cjs +1 -1
- package/concatIterators.min.cjs.map +1 -1
- package/concatIterators.min.mjs +1 -1
- package/concatIterators.min.mjs.map +1 -1
- package/concatIterators.mjs +0 -2
- package/dateTimeStr.cjs +119 -31
- package/dateTimeStr.min.cjs +1 -1
- package/dateTimeStr.min.cjs.map +1 -1
- package/dateTimeStr.min.mjs +1 -1
- package/dateTimeStr.min.mjs.map +1 -1
- package/dateTimeStr.mjs +69 -17
- package/duration.cjs +188 -24
- package/duration.min.cjs +1 -1
- package/duration.min.cjs.map +1 -1
- package/duration.min.mjs +1 -1
- package/duration.min.mjs.map +1 -1
- package/duration.mjs +144 -14
- package/getEnv.cjs +31 -7
- package/getEnv.min.cjs +1 -1
- package/getEnv.min.cjs.map +1 -1
- package/getEnv.min.mjs +1 -1
- package/getEnv.min.mjs.map +1 -1
- package/getEnv.mjs +0 -2
- package/isEmpty.cjs +46 -8
- package/isEmpty.min.cjs +1 -1
- package/isEmpty.min.cjs.map +1 -1
- package/isEmpty.min.mjs +1 -1
- package/isEmpty.min.mjs.map +1 -1
- package/isEmpty.mjs +19 -6
- package/isPromise.cjs +29 -5
- package/isPromise.min.cjs +1 -1
- package/isPromise.min.cjs.map +1 -1
- package/isPromise.min.mjs +1 -1
- package/isPromise.min.mjs.map +1 -1
- package/isPromise.mjs +0 -2
- package/kvStore.cjs +353 -15
- package/kvStore.min.cjs +1 -1
- package/kvStore.min.cjs.map +1 -1
- package/kvStore.min.mjs +1 -1
- package/kvStore.min.mjs.map +1 -1
- package/kvStore.mjs +319 -12
- package/localStore.cjs +264 -15
- package/localStore.min.cjs +1 -1
- package/localStore.min.cjs.map +1 -1
- package/localStore.min.mjs +1 -1
- package/localStore.min.mjs.map +1 -1
- package/localStore.mjs +230 -12
- package/mean.cjs +48 -8
- package/mean.min.cjs +1 -1
- package/mean.min.cjs.map +1 -1
- package/mean.min.mjs +1 -1
- package/mean.min.mjs.map +1 -1
- package/mean.mjs +18 -5
- package/median.cjs +41 -7
- package/median.min.cjs +1 -1
- package/median.min.cjs.map +1 -1
- package/median.min.mjs +1 -1
- package/median.min.mjs.map +1 -1
- package/median.mjs +11 -4
- package/nonEmpty.cjs +48 -8
- package/nonEmpty.min.cjs +1 -1
- package/nonEmpty.min.cjs.map +1 -1
- package/nonEmpty.min.mjs +1 -1
- package/nonEmpty.min.mjs.map +1 -1
- package/nonEmpty.mjs +19 -6
- package/nonNil.cjs +27 -4
- package/nonNil.min.cjs +1 -1
- package/nonNil.min.cjs.map +1 -1
- package/nonNil.min.mjs +1 -1
- package/nonNil.min.mjs.map +1 -1
- package/nonNil.mjs +0 -2
- package/package.json +1 -257
- package/round.cjs +32 -6
- package/round.min.cjs +1 -1
- package/round.min.cjs.map +1 -1
- package/round.min.mjs +1 -1
- package/round.min.mjs.map +1 -1
- package/round.mjs +5 -4
- package/roundToString.cjs +35 -7
- package/roundToString.min.cjs +1 -1
- package/roundToString.min.cjs.map +1 -1
- package/roundToString.min.mjs +1 -1
- package/roundToString.min.mjs.map +1 -1
- package/roundToString.mjs +5 -4
- package/safeBtoa.cjs +27 -4
- package/safeBtoa.min.cjs +1 -1
- package/safeBtoa.min.cjs.map +1 -1
- package/safeBtoa.min.mjs +1 -1
- package/safeBtoa.min.mjs.map +1 -1
- package/safeBtoa.mjs +0 -2
- package/sha256.cjs +34 -8
- package/sha256.min.cjs +1 -1
- package/sha256.min.cjs.map +1 -1
- package/sha256.min.mjs +1 -1
- package/sha256.min.mjs.map +1 -1
- package/sha256.mjs +7 -6
- package/sleep.cjs +27 -4
- package/sleep.min.cjs +1 -1
- package/sleep.min.cjs.map +1 -1
- package/sleep.min.mjs +1 -1
- package/sleep.min.mjs.map +1 -1
- package/sleep.mjs +0 -2
- package/storageAdapter.cjs +18 -1
- package/storageAdapter.min.cjs +2 -1
- package/storageAdapter.min.cjs.map +1 -1
- package/sum.cjs +45 -5
- package/sum.min.cjs +1 -1
- package/sum.min.cjs.map +1 -1
- package/sum.min.mjs +1 -1
- package/sum.min.mjs.map +1 -1
- package/sum.mjs +18 -5
- package/timeConstants.cjs +69 -35
- package/timeConstants.min.cjs +1 -1
- package/timeConstants.min.cjs.map +1 -1
- package/timeConstants.min.mjs +1 -1
- package/timeConstants.min.mjs.map +1 -1
- package/timeConstants.mjs +15 -19
- package/timer.cjs +180 -7
- package/timer.min.cjs +1 -1
- package/timer.min.cjs.map +1 -1
- package/timer.min.mjs +1 -1
- package/timer.min.mjs.map +1 -1
- package/timer.mjs +154 -8
- package/toReadableString.cjs +68 -6
- package/toReadableString.min.cjs +5 -1
- package/toReadableString.min.cjs.map +1 -1
- package/toReadableString.min.mjs +5 -1
- package/toReadableString.min.mjs.map +1 -1
- package/toReadableString.mjs +41 -4
- package/chunk-22JDWCOS.min.cjs +0 -2
- package/chunk-22JDWCOS.min.cjs.map +0 -1
- package/chunk-244NBT4Q.min.mjs +0 -2
- package/chunk-244NBT4Q.min.mjs.map +0 -1
- package/chunk-27MBP3ES.min.cjs +0 -2
- package/chunk-27MBP3ES.min.cjs.map +0 -1
- package/chunk-34ENP2B3.min.mjs +0 -438
- package/chunk-34ENP2B3.min.mjs.map +0 -1
- package/chunk-3EBQ2GO2.min.cjs +0 -2
- package/chunk-3EBQ2GO2.min.cjs.map +0 -1
- package/chunk-4GLOLTJ5.cjs +0 -167
- package/chunk-6TQBMXTL.min.cjs +0 -2
- package/chunk-6TQBMXTL.min.cjs.map +0 -1
- package/chunk-AWZBCFMG.min.cjs +0 -2
- package/chunk-AWZBCFMG.min.cjs.map +0 -1
- package/chunk-AXNETZET.cjs +0 -20
- package/chunk-BKZM6NWX.min.cjs +0 -2
- package/chunk-BKZM6NWX.min.cjs.map +0 -1
- package/chunk-BZKQXX3A.cjs +0 -40
- package/chunk-CERFUU5I.cjs +0 -93
- package/chunk-CSTKFJ6G.mjs +0 -239
- package/chunk-DUN4UY2Q.cjs +0 -239
- package/chunk-EDJJUP4K.min.cjs +0 -6
- package/chunk-EDJJUP4K.min.cjs.map +0 -1
- package/chunk-FFNQBZH5.cjs +0 -14
- package/chunk-FZZRSHSH.min.mjs +0 -6
- package/chunk-FZZRSHSH.min.mjs.map +0 -1
- package/chunk-GAP2HS5M.min.cjs +0 -2
- package/chunk-GAP2HS5M.min.cjs.map +0 -1
- package/chunk-GLYMAPS4.min.mjs +0 -2
- package/chunk-GLYMAPS4.min.mjs.map +0 -1
- package/chunk-I65KPVMO.min.cjs +0 -438
- package/chunk-I65KPVMO.min.cjs.map +0 -1
- package/chunk-ILGTU46T.cjs +0 -39
- package/chunk-IOKRXHKE.min.mjs +0 -2
- package/chunk-IOKRXHKE.min.mjs.map +0 -1
- package/chunk-ISP4SMRC.min.cjs +0 -2
- package/chunk-ISP4SMRC.min.cjs.map +0 -1
- package/chunk-KETP5HBF.cjs +0 -24
- package/chunk-KLHNGJ4Y.min.mjs +0 -2
- package/chunk-KLHNGJ4Y.min.mjs.map +0 -1
- package/chunk-KMNTU3DJ.mjs +0 -45
- package/chunk-LDVEXETI.cjs +0 -45
- package/chunk-LZENHV35.min.cjs +0 -2
- package/chunk-LZENHV35.min.cjs.map +0 -1
- package/chunk-M5PIM2HB.mjs +0 -42
- package/chunk-M6PYQYOX.mjs +0 -39
- package/chunk-MN5EYNZN.min.mjs +0 -2
- package/chunk-MN5EYNZN.min.mjs.map +0 -1
- package/chunk-NRIBJ2OJ.mjs +0 -16031
- package/chunk-NVLYXWLX.cjs +0 -32
- package/chunk-O352F2MT.mjs +0 -24
- package/chunk-O6B2TKFK.min.mjs +0 -2
- package/chunk-O6B2TKFK.min.mjs.map +0 -1
- package/chunk-OGF34H4T.min.cjs +0 -2
- package/chunk-OGF34H4T.min.cjs.map +0 -1
- package/chunk-OXSWWWOM.min.mjs +0 -2
- package/chunk-OXSWWWOM.min.mjs.map +0 -1
- package/chunk-PRUGHVRT.mjs +0 -14
- package/chunk-Q4WCMSOW.min.mjs +0 -2
- package/chunk-Q4WCMSOW.min.mjs.map +0 -1
- package/chunk-QH74JZCK.mjs +0 -9
- package/chunk-QNNJNLGK.min.cjs +0 -2
- package/chunk-QNNJNLGK.min.cjs.map +0 -1
- package/chunk-QWCFN7ZM.mjs +0 -15
- package/chunk-SDM2OPT6.mjs +0 -32
- package/chunk-SHKRZCF2.cjs +0 -16031
- package/chunk-SJDJDNDN.min.cjs +0 -2
- package/chunk-SJDJDNDN.min.cjs.map +0 -1
- package/chunk-SULNMALN.cjs +0 -328
- package/chunk-SV35RBZ7.min.mjs +0 -2
- package/chunk-SV35RBZ7.min.mjs.map +0 -1
- package/chunk-TJFYGFOW.mjs +0 -328
- package/chunk-UHRYBUUX.min.mjs +0 -2
- package/chunk-UHRYBUUX.min.mjs.map +0 -1
- package/chunk-UOU6IP3S.min.mjs +0 -2
- package/chunk-UOU6IP3S.min.mjs.map +0 -1
- package/chunk-V76XVNZ5.mjs +0 -20
- package/chunk-VFYQ7I5V.min.mjs +0 -2
- package/chunk-VFYQ7I5V.min.mjs.map +0 -1
- package/chunk-VG7VV7J2.mjs +0 -167
- package/chunk-VJCV56DO.cjs +0 -15
- package/chunk-VREA6AKG.cjs +0 -9
- package/chunk-W5I6Y5FK.min.mjs +0 -2
- package/chunk-W5I6Y5FK.min.mjs.map +0 -1
- package/chunk-Y7MC73BZ.cjs +0 -42
- package/chunk-YVWROQKU.mjs +0 -40
- package/chunk-ZKIZ5SWK.min.cjs +0 -2
- package/chunk-ZKIZ5SWK.min.cjs.map +0 -1
- package/chunk-ZZZB7NJX.mjs +0 -93
- package/magic-string.es-4UY437WL.min.mjs +0 -14
- package/magic-string.es-4UY437WL.min.mjs.map +0 -1
- package/magic-string.es-OAQWZQTY.mjs +0 -1323
- package/magic-string.es-UE2UVQEL.cjs +0 -1323
- package/magic-string.es-X6DNUB6Y.min.cjs +0 -14
- package/magic-string.es-X6DNUB6Y.min.cjs.map +0 -1
package/kvStore.mjs
CHANGED
|
@@ -1,15 +1,322 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
// src/timeConstants.ts
|
|
2
|
+
var MS_PER_SECOND = 1e3;
|
|
3
|
+
var MS_PER_MINUTE = 6e4;
|
|
4
|
+
var MS_PER_HOUR = 36e5;
|
|
5
|
+
var MS_PER_DAY = 864e5;
|
|
6
|
+
|
|
7
|
+
// src/duration.ts
|
|
8
|
+
function durationToMs(duration) {
|
|
9
|
+
const daysMs = (duration.days ?? 0) * MS_PER_DAY;
|
|
10
|
+
const hoursMs = (duration.hours ?? 0) * MS_PER_HOUR;
|
|
11
|
+
const minsMs = (duration.minutes ?? 0) * MS_PER_MINUTE;
|
|
12
|
+
const secsMs = (duration.seconds ?? 0) * MS_PER_SECOND;
|
|
13
|
+
const msMs = duration.milliseconds ?? 0;
|
|
14
|
+
return daysMs + hoursMs + minsMs + secsMs + msMs;
|
|
15
|
+
}
|
|
16
|
+
function durationOrMsToMs(duration) {
|
|
17
|
+
return typeof duration === "number" ? duration : durationToMs(duration);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/kvStore.ts
|
|
21
|
+
var KvStoreConfig = {
|
|
22
|
+
/**
|
|
23
|
+
* Name of the DB in the indexed DB.
|
|
24
|
+
* Updating the DB name will cause all old entries to be gone.
|
|
25
|
+
*/
|
|
26
|
+
dbName: "KVStore",
|
|
27
|
+
/**
|
|
28
|
+
* Version of the DB schema. Most likely you will never want to change this.
|
|
29
|
+
* Updating the version will cause all old entries to be gone.
|
|
30
|
+
*/
|
|
31
|
+
dbVersion: 1,
|
|
32
|
+
/**
|
|
33
|
+
* Name of the store within the indexed DB. Each DB can have multiple stores.
|
|
34
|
+
* In practice, it doesn't matter what you name this to be.
|
|
35
|
+
*/
|
|
36
|
+
storeName: "kvStore",
|
|
37
|
+
/** 30 days in ms. */
|
|
38
|
+
expiryMs: MS_PER_DAY * 30,
|
|
39
|
+
/** Do GC once per day. */
|
|
40
|
+
gcIntervalMs: MS_PER_DAY
|
|
41
|
+
};
|
|
42
|
+
function configureKvStore(config) {
|
|
43
|
+
Object.assign(KvStoreConfig, config);
|
|
44
|
+
}
|
|
45
|
+
function validateStoredObject(obj) {
|
|
46
|
+
if (!obj || typeof obj !== "object" || typeof obj.key !== "string" || obj.value === void 0 || typeof obj.storedMs !== "number" || typeof obj.expiryMs !== "number" || Date.now() >= obj.expiryMs) {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
function withOnError(request, reject) {
|
|
52
|
+
request.onerror = (event) => {
|
|
53
|
+
reject(event);
|
|
54
|
+
};
|
|
55
|
+
return request;
|
|
56
|
+
}
|
|
57
|
+
function createKvStore(dbName, options) {
|
|
58
|
+
let db;
|
|
59
|
+
const dbVersion = options?.dbVersion ?? KvStoreConfig.dbVersion;
|
|
60
|
+
const storeName = options?.storeName ?? KvStoreConfig.storeName;
|
|
61
|
+
const defaultExpiryMs = options?.defaultExpiryMs ? durationOrMsToMs(options.defaultExpiryMs) : KvStoreConfig.expiryMs;
|
|
62
|
+
const gcIntervalMs = options?.gcIntervalMs ? durationOrMsToMs(options.gcIntervalMs) : KvStoreConfig.gcIntervalMs;
|
|
63
|
+
const gcMsStorageKey = `__kvStore:lastGcMs:${dbName}:v${dbVersion}:${storeName}`;
|
|
64
|
+
async function getOrCreateDb() {
|
|
65
|
+
if (!db) {
|
|
66
|
+
db = await new Promise((resolve, reject) => {
|
|
67
|
+
const request = withOnError(indexedDB.open(dbName, dbVersion), reject);
|
|
68
|
+
request.onupgradeneeded = (event) => {
|
|
69
|
+
const db2 = event.target.result;
|
|
70
|
+
const objectStore = db2.createObjectStore(storeName, {
|
|
71
|
+
keyPath: "key"
|
|
72
|
+
});
|
|
73
|
+
objectStore.createIndex("key", "key", {
|
|
74
|
+
unique: true
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
request.onsuccess = (event) => {
|
|
78
|
+
const db2 = event.target.result;
|
|
79
|
+
resolve(db2);
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return db;
|
|
84
|
+
}
|
|
85
|
+
async function transact(mode, callback) {
|
|
86
|
+
const db2 = await getOrCreateDb();
|
|
87
|
+
return await new Promise((resolve, reject) => {
|
|
88
|
+
const transaction = withOnError(db2.transaction(storeName, mode), reject);
|
|
89
|
+
transaction.onabort = (event) => {
|
|
90
|
+
reject(event);
|
|
91
|
+
};
|
|
92
|
+
const objectStore = transaction.objectStore(storeName);
|
|
93
|
+
callback(objectStore, resolve, reject);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const obj = {
|
|
97
|
+
/** Input name for the DB. */
|
|
98
|
+
dbName,
|
|
99
|
+
/** Input version for the DB. */
|
|
100
|
+
dbVersion,
|
|
101
|
+
/** Input name for the DB store. */
|
|
102
|
+
storeName,
|
|
103
|
+
/** Default expiry to use if not specified in set(). */
|
|
104
|
+
defaultExpiryMs,
|
|
105
|
+
/** Time interval for when GC's occur. */
|
|
106
|
+
gcIntervalMs,
|
|
107
|
+
/** Local storage key name for the last GC completed timestamp. */
|
|
108
|
+
gcMsStorageKey,
|
|
109
|
+
/** Set a value in the store. */
|
|
110
|
+
async set(key, value, expiryDeltaMs) {
|
|
111
|
+
const nowMs = Date.now();
|
|
112
|
+
const stored = {
|
|
113
|
+
key,
|
|
114
|
+
value,
|
|
115
|
+
storedMs: nowMs,
|
|
116
|
+
expiryMs: nowMs + durationOrMsToMs(expiryDeltaMs ?? defaultExpiryMs)
|
|
117
|
+
};
|
|
118
|
+
return await transact("readwrite", (objectStore, resolve, reject) => {
|
|
119
|
+
const request = withOnError(objectStore.put(stored), reject);
|
|
120
|
+
request.onsuccess = () => {
|
|
121
|
+
resolve(value);
|
|
122
|
+
obj.gc();
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
/** Delete one or multiple keys. */
|
|
127
|
+
async delete(key) {
|
|
128
|
+
return await transact(
|
|
129
|
+
"readwrite",
|
|
130
|
+
(objectStore, resolve, reject) => {
|
|
131
|
+
objectStore.transaction.oncomplete = () => {
|
|
132
|
+
resolve();
|
|
133
|
+
};
|
|
134
|
+
if (typeof key === "string") {
|
|
135
|
+
withOnError(objectStore.delete(key), reject);
|
|
136
|
+
} else {
|
|
137
|
+
for (const k of key) {
|
|
138
|
+
withOnError(objectStore.delete(k), reject);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
},
|
|
144
|
+
/** Mainly used to get the expiration timestamp of an object. */
|
|
145
|
+
async getStoredObject(key) {
|
|
146
|
+
const stored = await transact(
|
|
147
|
+
"readonly",
|
|
148
|
+
(objectStore, resolve, reject) => {
|
|
149
|
+
const request = withOnError(objectStore.get(key), reject);
|
|
150
|
+
request.onsuccess = () => {
|
|
151
|
+
resolve(request.result);
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
if (!stored) {
|
|
156
|
+
return void 0;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const valid = validateStoredObject(stored);
|
|
160
|
+
if (!valid) {
|
|
161
|
+
await obj.delete(key);
|
|
162
|
+
obj.gc();
|
|
163
|
+
return void 0;
|
|
164
|
+
}
|
|
165
|
+
return valid;
|
|
166
|
+
} catch (e) {
|
|
167
|
+
console.error(`Invalid kv value: ${key}=${JSON.stringify(stored)}:`, e);
|
|
168
|
+
await obj.delete(key);
|
|
169
|
+
obj.gc();
|
|
170
|
+
return void 0;
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
/** Get a value by key, or undefined if it does not exist. */
|
|
174
|
+
async get(key) {
|
|
175
|
+
const stored = await obj.getStoredObject(key);
|
|
176
|
+
return stored?.value;
|
|
177
|
+
},
|
|
178
|
+
/** Generic way to iterate through all entries. */
|
|
179
|
+
async forEach(callback) {
|
|
180
|
+
await transact("readonly", (objectStore, resolve, reject) => {
|
|
181
|
+
const request = withOnError(objectStore.openCursor(), reject);
|
|
182
|
+
request.onsuccess = async (event) => {
|
|
183
|
+
const cursor = event.target.result;
|
|
184
|
+
if (cursor) {
|
|
185
|
+
if (cursor.key) {
|
|
186
|
+
const valid = validateStoredObject(cursor.value);
|
|
187
|
+
if (valid !== void 0) {
|
|
188
|
+
await callback(
|
|
189
|
+
String(cursor.key),
|
|
190
|
+
valid.value,
|
|
191
|
+
valid.expiryMs,
|
|
192
|
+
valid.storedMs
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
cursor.continue();
|
|
197
|
+
} else {
|
|
198
|
+
resolve();
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
/**
|
|
204
|
+
* Returns the number of items in the store. Note that getting the size
|
|
205
|
+
* requires iterating through the entire store because the items could expire
|
|
206
|
+
* at any time, and hence the size is a dynamic number.
|
|
207
|
+
*/
|
|
208
|
+
async size() {
|
|
209
|
+
let count = 0;
|
|
210
|
+
await obj.forEach(() => {
|
|
211
|
+
count++;
|
|
212
|
+
});
|
|
213
|
+
return count;
|
|
214
|
+
},
|
|
215
|
+
/** Remove all items from the store. */
|
|
216
|
+
async clear() {
|
|
217
|
+
await transact("readwrite", (objectStore, resolve, reject) => {
|
|
218
|
+
const request = withOnError(objectStore.clear(), reject);
|
|
219
|
+
request.onsuccess = () => {
|
|
220
|
+
resolve();
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
},
|
|
224
|
+
/**
|
|
225
|
+
* Returns all items as map of key to value, mainly used for debugging dumps.
|
|
226
|
+
* The type T is applied to all values, even though they might not be of type
|
|
227
|
+
* T (in the case when you store different data types in the same store).
|
|
228
|
+
*/
|
|
229
|
+
async asMap() {
|
|
230
|
+
const map = /* @__PURE__ */ new Map();
|
|
231
|
+
await obj.forEach((key, value, expiryMs, storedMs) => {
|
|
232
|
+
map.set(key, { value, expiryMs, storedMs });
|
|
233
|
+
});
|
|
234
|
+
return map;
|
|
235
|
+
},
|
|
236
|
+
/** Returns the ms timestamp for the last GC (garbage collection). */
|
|
237
|
+
getLastGcMs() {
|
|
238
|
+
const lastGcMsStr = localStorage.getItem(gcMsStorageKey);
|
|
239
|
+
if (!lastGcMsStr) return 0;
|
|
240
|
+
const ms = Number(lastGcMsStr);
|
|
241
|
+
return isNaN(ms) ? 0 : ms;
|
|
242
|
+
},
|
|
243
|
+
/** Set the ms timestamp for the last GC (garbage collection). */
|
|
244
|
+
setLastGcMs(ms) {
|
|
245
|
+
localStorage.setItem(gcMsStorageKey, String(ms));
|
|
246
|
+
},
|
|
247
|
+
/** Perform garbage-collection if due, else do nothing. */
|
|
248
|
+
async gc() {
|
|
249
|
+
const lastGcMs = obj.getLastGcMs();
|
|
250
|
+
if (!lastGcMs) {
|
|
251
|
+
obj.setLastGcMs(Date.now());
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (Date.now() < lastGcMs + gcIntervalMs) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
await obj.gcNow();
|
|
258
|
+
},
|
|
259
|
+
/**
|
|
260
|
+
* Perform garbage collection immediately without checking whether we are
|
|
261
|
+
* due for the next GC or not.
|
|
262
|
+
*/
|
|
263
|
+
async gcNow() {
|
|
264
|
+
console.log(`Starting kvStore GC on ${dbName} v${dbVersion}...`);
|
|
265
|
+
obj.setLastGcMs(Date.now());
|
|
266
|
+
const keysToDelete = [];
|
|
267
|
+
await obj.forEach(
|
|
268
|
+
async (key, value, expiryMs) => {
|
|
269
|
+
if (value === void 0 || Date.now() >= expiryMs) {
|
|
270
|
+
keysToDelete.push(key);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
if (keysToDelete.length) {
|
|
275
|
+
await obj.delete(keysToDelete);
|
|
276
|
+
}
|
|
277
|
+
console.log(
|
|
278
|
+
`Finished kvStore GC on ${dbName} v${dbVersion} - deleted ${keysToDelete.length} keys`
|
|
279
|
+
);
|
|
280
|
+
obj.setLastGcMs(Date.now());
|
|
281
|
+
},
|
|
282
|
+
/** Returns `this` casted into a StorageAdapter<T>. */
|
|
283
|
+
asStorageAdapter() {
|
|
284
|
+
return obj;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
return obj;
|
|
288
|
+
}
|
|
289
|
+
var kvStore = createKvStore(KvStoreConfig.dbName);
|
|
290
|
+
function kvStoreItem(key, expiryMs, store = kvStore) {
|
|
291
|
+
const defaultExpiryMs = expiryMs && durationOrMsToMs(expiryMs);
|
|
292
|
+
const obj = {
|
|
293
|
+
key,
|
|
294
|
+
defaultExpiryMs,
|
|
295
|
+
store,
|
|
296
|
+
/** Set a value in the store. */
|
|
297
|
+
async set(value, expiryDeltaMs) {
|
|
298
|
+
await store.set(key, value, expiryDeltaMs ?? defaultExpiryMs);
|
|
299
|
+
},
|
|
300
|
+
/**
|
|
301
|
+
* Example usage:
|
|
302
|
+
*
|
|
303
|
+
* const { value, storedMs, expiryMs, storedMs } =
|
|
304
|
+
* await myKvItem.getStoredObject();
|
|
305
|
+
*/
|
|
306
|
+
async getStoredObject() {
|
|
307
|
+
return await store.getStoredObject(key);
|
|
308
|
+
},
|
|
309
|
+
/** Get a value by key, or undefined if it does not exist. */
|
|
310
|
+
async get() {
|
|
311
|
+
return await store.get(key);
|
|
312
|
+
},
|
|
313
|
+
/** Delete this key from the store. */
|
|
314
|
+
async delete() {
|
|
315
|
+
await store.delete(key);
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
return obj;
|
|
319
|
+
}
|
|
13
320
|
export {
|
|
14
321
|
KvStoreConfig,
|
|
15
322
|
configureKvStore,
|
package/localStore.cjs
CHANGED
|
@@ -1,19 +1,268 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
2
19
|
|
|
20
|
+
// src/localStore.ts
|
|
21
|
+
var localStore_exports = {};
|
|
22
|
+
__export(localStore_exports, {
|
|
23
|
+
LocalStoreConfig: () => LocalStoreConfig,
|
|
24
|
+
configureLocalStore: () => configureLocalStore,
|
|
25
|
+
createLocalStore: () => createLocalStore,
|
|
26
|
+
localStore: () => localStore,
|
|
27
|
+
localStoreItem: () => localStoreItem
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(localStore_exports);
|
|
3
30
|
|
|
31
|
+
// src/timeConstants.ts
|
|
32
|
+
var MS_PER_SECOND = 1e3;
|
|
33
|
+
var MS_PER_MINUTE = 6e4;
|
|
34
|
+
var MS_PER_HOUR = 36e5;
|
|
35
|
+
var MS_PER_DAY = 864e5;
|
|
4
36
|
|
|
37
|
+
// src/duration.ts
|
|
38
|
+
function durationToMs(duration) {
|
|
39
|
+
const daysMs = (duration.days ?? 0) * MS_PER_DAY;
|
|
40
|
+
const hoursMs = (duration.hours ?? 0) * MS_PER_HOUR;
|
|
41
|
+
const minsMs = (duration.minutes ?? 0) * MS_PER_MINUTE;
|
|
42
|
+
const secsMs = (duration.seconds ?? 0) * MS_PER_SECOND;
|
|
43
|
+
const msMs = duration.milliseconds ?? 0;
|
|
44
|
+
return daysMs + hoursMs + minsMs + secsMs + msMs;
|
|
45
|
+
}
|
|
46
|
+
function durationOrMsToMs(duration) {
|
|
47
|
+
return typeof duration === "number" ? duration : durationToMs(duration);
|
|
48
|
+
}
|
|
5
49
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
50
|
+
// src/localStore.ts
|
|
51
|
+
var LocalStoreConfig = {
|
|
52
|
+
/** All items with the same store name will share the same storage space. */
|
|
53
|
+
storeName: "ts-utils",
|
|
54
|
+
/** 30 days in ms. */
|
|
55
|
+
expiryMs: MS_PER_DAY * 30,
|
|
56
|
+
/** Do GC once per day. */
|
|
57
|
+
gcIntervalMs: MS_PER_DAY
|
|
58
|
+
};
|
|
59
|
+
function configureLocalStore(config) {
|
|
60
|
+
Object.assign(LocalStoreConfig, config);
|
|
61
|
+
}
|
|
62
|
+
function validateStoredObject(obj) {
|
|
63
|
+
if (!obj || typeof obj !== "object" || obj.value === void 0 || typeof obj.storedMs !== "number" || typeof obj.expiryMs !== "number" || Date.now() >= obj.expiryMs) {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
return obj;
|
|
67
|
+
}
|
|
68
|
+
function createLocalStore(storeName, options) {
|
|
69
|
+
const keyPrefix = storeName + ":";
|
|
70
|
+
const defaultExpiryMs = options?.defaultExpiryMs ? durationOrMsToMs(options.defaultExpiryMs) : LocalStoreConfig.expiryMs;
|
|
71
|
+
const gcIntervalMs = options?.gcIntervalMs ? durationOrMsToMs(options.gcIntervalMs) : LocalStoreConfig.gcIntervalMs;
|
|
72
|
+
const gcMsStorageKey = `__localStore:lastGcMs:${storeName}`;
|
|
73
|
+
const obj = {
|
|
74
|
+
/** Input name for the store. */
|
|
75
|
+
storeName,
|
|
76
|
+
/**
|
|
77
|
+
* The prefix string for the local storage key which identifies items
|
|
78
|
+
* belonging to this namespace.
|
|
79
|
+
*/
|
|
80
|
+
keyPrefix,
|
|
81
|
+
/** Default expiry to use if not specified in set(). */
|
|
82
|
+
defaultExpiryMs,
|
|
83
|
+
/** Time interval for when GC's occur. */
|
|
84
|
+
gcIntervalMs,
|
|
85
|
+
/** Local storage key name for the last GC completed timestamp. */
|
|
86
|
+
gcMsStorageKey,
|
|
87
|
+
/** Set a value in the store. */
|
|
88
|
+
set(key, value, expiryDeltaMs) {
|
|
89
|
+
const nowMs = Date.now();
|
|
90
|
+
const stored = {
|
|
91
|
+
value,
|
|
92
|
+
storedMs: nowMs,
|
|
93
|
+
expiryMs: nowMs + durationOrMsToMs(expiryDeltaMs ?? defaultExpiryMs)
|
|
94
|
+
};
|
|
95
|
+
localStorage.setItem(keyPrefix + key, JSON.stringify(stored));
|
|
96
|
+
obj.gc();
|
|
97
|
+
return value;
|
|
98
|
+
},
|
|
99
|
+
/** Delete one or multiple keys. */
|
|
100
|
+
delete(key) {
|
|
101
|
+
if (typeof key === "string") {
|
|
102
|
+
localStorage.removeItem(keyPrefix + key);
|
|
103
|
+
} else {
|
|
104
|
+
for (const k of key) {
|
|
105
|
+
localStorage.removeItem(keyPrefix + k);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
/** Mainly used to get the expiration timestamp of an object. */
|
|
110
|
+
getStoredObject(key) {
|
|
111
|
+
const k = keyPrefix + key;
|
|
112
|
+
const stored = localStorage.getItem(k);
|
|
113
|
+
if (!stored) {
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const parsed = JSON.parse(stored);
|
|
118
|
+
const valid = validateStoredObject(parsed);
|
|
119
|
+
if (!valid) {
|
|
120
|
+
obj.delete(k);
|
|
121
|
+
obj.gc();
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
return valid;
|
|
125
|
+
} catch (e) {
|
|
126
|
+
console.error(`Invalid local value: ${k}=${stored}:`, e);
|
|
127
|
+
obj.delete(k);
|
|
128
|
+
obj.gc();
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
/** Get a value by key, or undefined if it does not exist. */
|
|
133
|
+
get(key) {
|
|
134
|
+
const stored = obj.getStoredObject(key);
|
|
135
|
+
return stored?.value;
|
|
136
|
+
},
|
|
137
|
+
/** Generic way to iterate through all entries. */
|
|
138
|
+
forEach(callback) {
|
|
139
|
+
for (const k of Object.keys(localStorage)) {
|
|
140
|
+
if (!k.startsWith(keyPrefix)) continue;
|
|
141
|
+
const key = k.slice(keyPrefix.length);
|
|
142
|
+
const stored = obj.getStoredObject(key);
|
|
143
|
+
if (!stored) continue;
|
|
144
|
+
callback(key, stored.value, stored.expiryMs, stored.storedMs);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* Returns the number of items in the store. Note that getting the size
|
|
149
|
+
* requires iterating through the entire store because the items could expire
|
|
150
|
+
* at any time, and hence the size is a dynamic number.
|
|
151
|
+
*/
|
|
152
|
+
size() {
|
|
153
|
+
let count = 0;
|
|
154
|
+
obj.forEach(() => {
|
|
155
|
+
count++;
|
|
156
|
+
});
|
|
157
|
+
return count;
|
|
158
|
+
},
|
|
159
|
+
/** Remove all items from the store. */
|
|
160
|
+
clear() {
|
|
161
|
+
for (const key of Object.keys(localStorage)) {
|
|
162
|
+
if (key.startsWith(keyPrefix)) {
|
|
163
|
+
localStorage.removeItem(key);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* Returns all items as map of key to value, mainly used for debugging dumps.
|
|
169
|
+
* The type T is applied to all values, even though they might not be of type
|
|
170
|
+
* T (in the case when you store different data types in the same store).
|
|
171
|
+
*/
|
|
172
|
+
asMap() {
|
|
173
|
+
const map = /* @__PURE__ */ new Map();
|
|
174
|
+
obj.forEach(
|
|
175
|
+
(key, value, expiryMs, storedMs) => {
|
|
176
|
+
map.set(key, { value, expiryMs, storedMs });
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
return map;
|
|
180
|
+
},
|
|
181
|
+
/** Returns the ms timestamp for the last GC (garbage collection). */
|
|
182
|
+
getLastGcMs() {
|
|
183
|
+
const lastGcMsStr = localStorage.getItem(gcMsStorageKey);
|
|
184
|
+
if (!lastGcMsStr) return 0;
|
|
185
|
+
const ms = Number(lastGcMsStr);
|
|
186
|
+
return isNaN(ms) ? 0 : ms;
|
|
187
|
+
},
|
|
188
|
+
/** Set the ms timestamp for the last GC (garbage collection). */
|
|
189
|
+
setLastGcMs(ms) {
|
|
190
|
+
localStorage.setItem(gcMsStorageKey, String(ms));
|
|
191
|
+
},
|
|
192
|
+
/** Perform garbage-collection if due, else do nothing. */
|
|
193
|
+
gc() {
|
|
194
|
+
const lastGcMs = obj.getLastGcMs();
|
|
195
|
+
if (!lastGcMs) {
|
|
196
|
+
obj.setLastGcMs(Date.now());
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (Date.now() < lastGcMs + gcIntervalMs) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
obj.gcNow();
|
|
203
|
+
},
|
|
204
|
+
/**
|
|
205
|
+
* Perform garbage collection immediately without checking whether we are
|
|
206
|
+
* due for the next GC or not.
|
|
207
|
+
*/
|
|
208
|
+
gcNow() {
|
|
209
|
+
console.log(`Starting localStore GC on ${storeName}`);
|
|
210
|
+
obj.setLastGcMs(Date.now());
|
|
211
|
+
let count = 0;
|
|
212
|
+
obj.forEach((key, value, expiryMs) => {
|
|
213
|
+
if (Date.now() >= expiryMs) {
|
|
214
|
+
obj.delete(key);
|
|
215
|
+
count++;
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
console.log(
|
|
219
|
+
`Finished localStore GC on ${storeName} - deleted ${count} keys`
|
|
220
|
+
);
|
|
221
|
+
obj.setLastGcMs(Date.now());
|
|
222
|
+
},
|
|
223
|
+
/** Returns `this` casted into a StorageAdapter<T>. */
|
|
224
|
+
asStorageAdapter() {
|
|
225
|
+
return obj;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
return obj;
|
|
229
|
+
}
|
|
230
|
+
var localStore = createLocalStore(LocalStoreConfig.storeName);
|
|
231
|
+
function localStoreItem(key, expiryMs, store = localStore) {
|
|
232
|
+
const defaultExpiryMs = expiryMs && durationOrMsToMs(expiryMs);
|
|
233
|
+
const obj = {
|
|
234
|
+
key,
|
|
235
|
+
defaultExpiryMs,
|
|
236
|
+
store,
|
|
237
|
+
/** Set a value in the store. */
|
|
238
|
+
set(value, expiryDeltaMs) {
|
|
239
|
+
store.set(key, value, expiryDeltaMs ?? defaultExpiryMs);
|
|
240
|
+
},
|
|
241
|
+
/**
|
|
242
|
+
* Example usage:
|
|
243
|
+
*
|
|
244
|
+
* const { value, storedMs, expiryMs, storedMs } =
|
|
245
|
+
* await myLocalItem.getStoredObject();
|
|
246
|
+
*/
|
|
247
|
+
getStoredObject() {
|
|
248
|
+
return store.getStoredObject(key);
|
|
249
|
+
},
|
|
250
|
+
/** Get a value by key, or undefined if it does not exist. */
|
|
251
|
+
get() {
|
|
252
|
+
return store.get(key);
|
|
253
|
+
},
|
|
254
|
+
/** Delete this key from the store. */
|
|
255
|
+
delete() {
|
|
256
|
+
store.delete(key);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
return obj;
|
|
260
|
+
}
|
|
261
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
262
|
+
0 && (module.exports = {
|
|
263
|
+
LocalStoreConfig,
|
|
264
|
+
configureLocalStore,
|
|
265
|
+
createLocalStore,
|
|
266
|
+
localStore,
|
|
267
|
+
localStoreItem
|
|
268
|
+
});
|
package/localStore.min.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(
|
|
1
|
+
"use strict";var p=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var D=(t,s)=>{for(var r in s)p(t,r,{get:s[r],enumerable:!0})},h=(t,s,r,c)=>{if(s&&typeof s=="object"||typeof s=="function")for(let i of T(s))!b.call(t,i)&&i!==r&&p(t,i,{get:()=>s[i],enumerable:!(c=y(s,i))||c.enumerable});return t};var x=t=>h(p({},"__esModule",{value:!0}),t);var _={};D(_,{LocalStoreConfig:()=>g,configureLocalStore:()=>v,createLocalStore:()=>m,localStore:()=>M,localStoreItem:()=>I});module.exports=x(_);function O(t){let s=(t.days??0)*864e5,r=(t.hours??0)*36e5,c=(t.minutes??0)*6e4,i=(t.seconds??0)*1e3,l=t.milliseconds??0;return s+r+c+i+l}function f(t){return typeof t=="number"?t:O(t)}var g={storeName:"ts-utils",expiryMs:864e5*30,gcIntervalMs:864e5};function v(t){Object.assign(g,t)}function E(t){if(!(!t||typeof t!="object"||t.value===void 0||typeof t.storedMs!="number"||typeof t.expiryMs!="number"||Date.now()>=t.expiryMs))return t}function m(t,s){let r=t+":",c=s?.defaultExpiryMs?f(s.defaultExpiryMs):g.expiryMs,i=s?.gcIntervalMs?f(s.gcIntervalMs):g.gcIntervalMs,l=`__localStore:lastGcMs:${t}`,o={storeName:t,keyPrefix:r,defaultExpiryMs:c,gcIntervalMs:i,gcMsStorageKey:l,set(e,n,u){let a=Date.now(),d={value:n,storedMs:a,expiryMs:a+f(u??c)};return localStorage.setItem(r+e,JSON.stringify(d)),o.gc(),n},delete(e){if(typeof e=="string")localStorage.removeItem(r+e);else for(let n of e)localStorage.removeItem(r+n)},getStoredObject(e){let n=r+e,u=localStorage.getItem(n);if(u)try{let a=JSON.parse(u),d=E(a);if(!d){o.delete(n),o.gc();return}return d}catch(a){console.error(`Invalid local value: ${n}=${u}:`,a),o.delete(n),o.gc();return}},get(e){return o.getStoredObject(e)?.value},forEach(e){for(let n of Object.keys(localStorage)){if(!n.startsWith(r))continue;let u=n.slice(r.length),a=o.getStoredObject(u);a&&e(u,a.value,a.expiryMs,a.storedMs)}},size(){let e=0;return o.forEach(()=>{e++}),e},clear(){for(let e of Object.keys(localStorage))e.startsWith(r)&&localStorage.removeItem(e)},asMap(){let e=new Map;return o.forEach((n,u,a,d)=>{e.set(n,{value:u,expiryMs:a,storedMs:d})}),e},getLastGcMs(){let e=localStorage.getItem(l);if(!e)return 0;let n=Number(e);return isNaN(n)?0:n},setLastGcMs(e){localStorage.setItem(l,String(e))},gc(){let e=o.getLastGcMs();if(!e){o.setLastGcMs(Date.now());return}Date.now()<e+i||o.gcNow()},gcNow(){console.log(`Starting localStore GC on ${t}`),o.setLastGcMs(Date.now());let e=0;o.forEach((n,u,a)=>{Date.now()>=a&&(o.delete(n),e++)}),console.log(`Finished localStore GC on ${t} - deleted ${e} keys`),o.setLastGcMs(Date.now())},asStorageAdapter(){return o}};return o}var M=m(g.storeName);function I(t,s,r=M){let c=s&&f(s);return{key:t,defaultExpiryMs:c,store:r,set(l,o){r.set(t,l,o??c)},getStoredObject(){return r.getStoredObject(t)},get(){return r.get(t)},delete(){r.delete(t)}}}0&&(module.exports={LocalStoreConfig,configureLocalStore,createLocalStore,localStore,localStoreItem});
|
|
2
2
|
//# sourceMappingURL=localStore.min.cjs.map
|
package/localStore.min.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/choksheaklau/src/ts-utils/dist/localStore.min.cjs"],"names":[],"mappings":"AAAA,wIAAiD,oCAAiC,oCAAiC,oCAAiC,oCAAE,CAAE,CAAC,yPAAgH","file":"/Users/choksheaklau/src/ts-utils/dist/localStore.min.cjs"}
|
|
1
|
+
{"version":3,"sources":["../src/localStore.ts","../src/duration.ts"],"sourcesContent":["/**\n * Local storage key-value store with support for auto-expirations.\n *\n * Why use this?\n * 1. Extremely simple interface to use local storage.\n * 2. Auto-expirations with GC frees you from worrying about data clean-up.\n * 3. Any serializable data type can be stored (except undefined).\n *\n * How to use?\n * Just use the `localStore` global constant like the local storage.\n *\n * Why not use the localStorage directly?\n * localStorage does not provide auto-expirations with GC. If you don't need\n * this (items never expire), then just use localStorage directly.\n */\n\nimport { Duration, durationOrMsToMs } from \"./duration\";\nimport {\n FullStorageAdapter,\n StorageAdapter,\n StoredObject,\n} from \"./storageAdapter\";\nimport { MS_PER_DAY } from \"./timeConstants\";\n\n/** Global defaults can be updated directly. */\nexport const LocalStoreConfig = {\n /** All items with the same store name will share the same storage space. */\n storeName: \"ts-utils\",\n\n /** 30 days in ms. */\n expiryMs: MS_PER_DAY * 30,\n\n /** Do GC once per day. */\n gcIntervalMs: MS_PER_DAY,\n};\n\nexport type LocalStoreConfig = typeof LocalStoreConfig;\n\n/** Convenience function to update global defaults. */\nexport function configureLocalStore(config: Partial<LocalStoreConfig>) {\n Object.assign(LocalStoreConfig, config);\n}\n\n/**\n * Parse a stored value string. Returns undefined if invalid or expired.\n * Throws an error if the string cannot be parsed as JSON.\n */\nfunction validateStoredObject<T>(\n obj: StoredObject<T>,\n): StoredObject<T> | undefined {\n if (\n !obj ||\n typeof obj !== \"object\" ||\n obj.value === undefined ||\n typeof obj.storedMs !== \"number\" ||\n typeof obj.expiryMs !== \"number\" ||\n Date.now() >= obj.expiryMs\n ) {\n return undefined;\n }\n\n return obj;\n}\n\n/**\n * You can create multiple LocalStores if you want, but most likely you will only\n * need to use the default `localStore` instance.\n */\n// Using `any` because the store could store any type of data for each key,\n// but the caller can specify a more specific type when calling each of the\n// methods.\n\nexport function createLocalStore(\n storeName: string,\n options?: {\n defaultExpiryMs?: number | Duration;\n gcIntervalMs?: number | Duration;\n },\n) {\n const keyPrefix = storeName + \":\";\n\n const defaultExpiryMs = options?.defaultExpiryMs\n ? durationOrMsToMs(options.defaultExpiryMs)\n : LocalStoreConfig.expiryMs;\n\n const gcIntervalMs = options?.gcIntervalMs\n ? durationOrMsToMs(options.gcIntervalMs)\n : LocalStoreConfig.gcIntervalMs;\n\n const gcMsStorageKey = `__localStore:lastGcMs:${storeName}`;\n\n const obj = {\n /** Input name for the store. */\n storeName,\n\n /**\n * The prefix string for the local storage key which identifies items\n * belonging to this namespace.\n */\n keyPrefix,\n\n /** Default expiry to use if not specified in set(). */\n defaultExpiryMs,\n\n /** Time interval for when GC's occur. */\n gcIntervalMs,\n\n /** Local storage key name for the last GC completed timestamp. */\n gcMsStorageKey,\n\n /** Set a value in the store. */\n set<T>(key: string, value: T, expiryDeltaMs?: number | Duration): T {\n const nowMs = Date.now();\n const stored: StoredObject<T> = {\n value,\n storedMs: nowMs,\n expiryMs: nowMs + durationOrMsToMs(expiryDeltaMs ?? defaultExpiryMs),\n };\n\n localStorage.setItem(keyPrefix + key, JSON.stringify(stored));\n\n obj.gc(); // check GC on every write\n\n return value;\n },\n\n /** Delete one or multiple keys. */\n delete(key: string | string[]): void {\n if (typeof key === \"string\") {\n localStorage.removeItem(keyPrefix + key);\n } else {\n for (const k of key) {\n localStorage.removeItem(keyPrefix + k);\n }\n }\n },\n\n /** Mainly used to get the expiration timestamp of an object. */\n getStoredObject<T>(key: string): StoredObject<T> | undefined {\n const k = keyPrefix + key;\n const stored = localStorage.getItem(k);\n\n if (!stored) {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(stored);\n const valid = validateStoredObject(parsed);\n if (!valid) {\n obj.delete(k);\n\n obj.gc(); // check GC on every read of an expired key\n\n return undefined;\n }\n\n return valid as StoredObject<T>;\n } catch (e) {\n console.error(`Invalid local value: ${k}=${stored}:`, e);\n obj.delete(k);\n\n obj.gc(); // check GC on every read of an invalid key\n\n return undefined;\n }\n },\n\n /** Get a value by key, or undefined if it does not exist. */\n get<T>(key: string): T | undefined {\n const stored = obj.getStoredObject<T>(key);\n\n return stored?.value;\n },\n\n /** Generic way to iterate through all entries. */\n forEach<T>(\n callback: (\n key: string,\n value: T,\n expiryMs: number,\n storedMs: number,\n ) => void,\n ): void {\n for (const k of Object.keys(localStorage)) {\n if (!k.startsWith(keyPrefix)) continue;\n\n const key = k.slice(keyPrefix.length);\n const stored = obj.getStoredObject(key);\n\n if (!stored) continue;\n\n callback(key, stored.value as T, stored.expiryMs, stored.storedMs);\n }\n },\n\n /**\n * Returns the number of items in the store. Note that getting the size\n * requires iterating through the entire store because the items could expire\n * at any time, and hence the size is a dynamic number.\n */\n size(): number {\n let count = 0;\n obj.forEach(() => {\n count++;\n });\n return count;\n },\n\n /** Remove all items from the store. */\n clear(): void {\n // Note that we don't need to use obj.forEach() because we are just\n // going to delete all the items without checking for expiration.\n for (const key of Object.keys(localStorage)) {\n if (key.startsWith(keyPrefix)) {\n localStorage.removeItem(key);\n }\n }\n },\n\n /**\n * Returns all items as map of key to value, mainly used for debugging dumps.\n * The type T is applied to all values, even though they might not be of type\n * T (in the case when you store different data types in the same store).\n */\n asMap<T>(): Map<string, StoredObject<T>> {\n const map = new Map<string, StoredObject<T>>();\n obj.forEach(\n (key: string, value: T, expiryMs: number, storedMs: number) => {\n map.set(key, { value: value as T, expiryMs, storedMs });\n },\n );\n return map;\n },\n\n /** Returns the ms timestamp for the last GC (garbage collection). */\n getLastGcMs(): number {\n const lastGcMsStr = localStorage.getItem(gcMsStorageKey);\n if (!lastGcMsStr) return 0;\n\n const ms = Number(lastGcMsStr);\n return isNaN(ms) ? 0 : ms;\n },\n\n /** Set the ms timestamp for the last GC (garbage collection). */\n setLastGcMs(ms: number) {\n localStorage.setItem(gcMsStorageKey, String(ms));\n },\n\n /** Perform garbage-collection if due, else do nothing. */\n gc(): void {\n const lastGcMs = obj.getLastGcMs();\n\n // Set initial timestamp - no need GC now.\n if (!lastGcMs) {\n obj.setLastGcMs(Date.now());\n return;\n }\n\n if (Date.now() < lastGcMs + gcIntervalMs) {\n return; // not due for next GC yet\n }\n\n // GC is due now, so run it.\n obj.gcNow();\n },\n\n /**\n * Perform garbage collection immediately without checking whether we are\n * due for the next GC or not.\n */\n gcNow(): void {\n console.log(`Starting localStore GC on ${storeName}`);\n\n // Prevent concurrent GC runs.\n obj.setLastGcMs(Date.now());\n let count = 0;\n\n obj.forEach((key: string, value: unknown, expiryMs: number) => {\n if (Date.now() >= expiryMs) {\n obj.delete(key);\n count++;\n }\n });\n\n console.log(\n `Finished localStore GC on ${storeName} - deleted ${count} keys`,\n );\n\n // Mark the end time as last GC time.\n obj.setLastGcMs(Date.now());\n },\n\n /** Returns `this` casted into a StorageAdapter<T>. */\n asStorageAdapter<T>(): StorageAdapter<T> {\n return obj as StorageAdapter<T>;\n },\n } as const;\n\n // Using `any` because the store could store any type of data for each key,\n // but the caller can specify a more specific type when calling each of the\n // methods.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return obj satisfies FullStorageAdapter<any>;\n}\n\nexport type LocalStore = ReturnType<typeof createLocalStore>;\n\n/**\n * Default local store ready for immediate use. You can create new instances if\n * you want, but most likely you will only need one store instance.\n */\nexport const localStore = createLocalStore(LocalStoreConfig.storeName);\n\n/** Create a local store item with a key and a default expiration. */\nexport function localStoreItem<T>(\n key: string,\n expiryMs?: number | Duration,\n store: LocalStore = localStore,\n) {\n const defaultExpiryMs = expiryMs && durationOrMsToMs(expiryMs);\n\n const obj = {\n key,\n defaultExpiryMs,\n store,\n\n /** Set a value in the store. */\n set(value: T, expiryDeltaMs?: number | undefined): void {\n store.set(key, value, expiryDeltaMs ?? defaultExpiryMs);\n },\n\n /**\n * Example usage:\n *\n * const { value, storedMs, expiryMs, storedMs } =\n * await myLocalItem.getStoredObject();\n */\n getStoredObject(): StoredObject<T> | undefined {\n return store.getStoredObject(key);\n },\n\n /** Get a value by key, or undefined if it does not exist. */\n get(): T | undefined {\n return store.get(key);\n },\n\n /** Delete this key from the store. */\n delete(): void {\n store.delete(key);\n },\n };\n\n return obj;\n}\n\nexport type LocalStoreItem<T> = ReturnType<typeof localStoreItem<T>>;\n","/**\n * Bunch of miscellaneous constants and utility functions related to handling\n * date and time durations.\n *\n * Note that month and year do not have fixed durations, and hence are excluded\n * from this file. Weeks have fixed durations, but are excluded because we\n * use days as the max duration supported.\n */\n\nimport {\n HOURS_PER_DAY,\n MINUTES_PER_HOUR,\n MS_PER_DAY,\n MS_PER_HOUR,\n MS_PER_MINUTE,\n MS_PER_SECOND,\n SECONDS_PER_MINUTE,\n} from \"./timeConstants\";\n\nexport type Duration = {\n days?: number;\n hours?: number;\n minutes?: number;\n seconds?: number;\n milliseconds?: number;\n};\n\n/**\n * One of: days, hours, minutes, seconds, milliseconds\n */\nexport type DurationType = keyof Duration;\n\n/**\n * Order in which the duration type appears in the duration string.\n */\nexport const DURATION_TYPE_SEQUENCE: DurationType[] = [\n \"days\",\n \"hours\",\n \"minutes\",\n \"seconds\",\n \"milliseconds\",\n];\n\n/**\n * Follows the same format as Intl.DurationFormat.prototype.format().\n *\n * Short: 1 yr, 2 mths, 3 wks, 3 days, 4 hr, 5 min, 6 sec, 7 ms, 8 μs, 9 ns\n * Long: 1 year, 2 months, 3 weeks, 3 days, 4 hours, 5 minutes, 6 seconds,\n * 7 milliseconds, 8 microseconds, 9 nanoseconds\n * Narrow: 1y 2mo 3w 3d 4h 5m 6s 7ms 8μs 9ns\n */\nexport type DurationStyle = \"short\" | \"long\" | \"narrow\";\n\nexport type DurationSuffixMap = {\n short: string;\n shorts: string;\n long: string;\n longs: string;\n narrow: string;\n};\n\nexport type DurationSuffixType = keyof DurationSuffixMap;\n\nexport const DURATION_STYLE_SUFFIX_MAP: Record<\n DurationType,\n DurationSuffixMap\n> = {\n days: {\n short: \"day\",\n shorts: \"days\",\n long: \"day\",\n longs: \"days\",\n narrow: \"d\",\n },\n hours: {\n short: \"hr\",\n shorts: \"hrs\",\n long: \"hour\",\n longs: \"hours\",\n narrow: \"h\",\n },\n minutes: {\n short: \"min\",\n shorts: \"mins\",\n long: \"minute\",\n longs: \"minutes\",\n narrow: \"m\",\n },\n seconds: {\n short: \"sec\",\n shorts: \"secs\",\n long: \"second\",\n longs: \"seconds\",\n narrow: \"s\",\n },\n milliseconds: {\n short: \"ms\",\n shorts: \"ms\",\n long: \"millisecond\",\n longs: \"milliseconds\",\n narrow: \"ms\",\n },\n};\n\nfunction getDurationStyleForPlural(style: DurationStyle): DurationSuffixType {\n return style == \"short\" ? \"shorts\" : style === \"long\" ? \"longs\" : style;\n}\n\nfunction getValueAndUnitSeparator(style: DurationStyle): string {\n return style === \"narrow\" ? \"\" : \" \";\n}\n\nfunction getDurationTypeSeparator(style: DurationStyle): string {\n return style === \"narrow\" ? \" \" : \", \";\n}\n\n/**\n * Convert a milliseconds duration into a Duration object. If the given ms is\n * zero, then return an object with a single field of zero with duration type\n * of durationTypeForZero.\n *\n * @param durationTypeForZero Defaults to 'milliseconds'\n */\nexport function msToDuration(\n ms: number,\n durationTypeForZero?: DurationType,\n): Duration {\n if (ms === 0) {\n durationTypeForZero = durationTypeForZero ?? \"milliseconds\";\n return { [durationTypeForZero]: 0 };\n }\n\n const duration: Duration = {};\n\n for (let i = 0; i < 1; i++) {\n let seconds = Math.floor(ms / MS_PER_SECOND);\n const millis = ms - seconds * MS_PER_SECOND;\n\n if (millis > 0) {\n duration[\"milliseconds\"] = millis;\n }\n\n if (seconds === 0) {\n break;\n }\n\n let minutes = Math.floor(seconds / SECONDS_PER_MINUTE);\n seconds -= minutes * SECONDS_PER_MINUTE;\n\n if (seconds > 0) {\n duration[\"seconds\"] = seconds;\n }\n\n if (minutes === 0) {\n break;\n }\n\n let hours = Math.floor(minutes / MINUTES_PER_HOUR);\n minutes -= hours * MINUTES_PER_HOUR;\n\n if (minutes > 0) {\n duration[\"minutes\"] = minutes;\n }\n\n if (hours === 0) {\n break;\n }\n\n const days = Math.floor(hours / HOURS_PER_DAY);\n hours -= days * HOURS_PER_DAY;\n\n if (hours > 0) {\n duration[\"hours\"] = hours;\n }\n\n if (days > 0) {\n duration[\"days\"] = days;\n }\n }\n\n return duration;\n}\n\n/**\n * Returns the number of milliseconds for the given duration.\n */\nexport function durationToMs(duration: Duration): number {\n const daysMs = (duration.days ?? 0) * MS_PER_DAY;\n const hoursMs = (duration.hours ?? 0) * MS_PER_HOUR;\n const minsMs = (duration.minutes ?? 0) * MS_PER_MINUTE;\n const secsMs = (duration.seconds ?? 0) * MS_PER_SECOND;\n const msMs = duration.milliseconds ?? 0;\n\n return daysMs + hoursMs + minsMs + secsMs + msMs;\n}\n\n/**\n * Convenience function to return a duration given an ms or Duration.\n */\nexport function durationOrMsToMs(duration: number | Duration): number {\n return typeof duration === \"number\" ? duration : durationToMs(duration);\n}\n\n/**\n * Format a given Duration object into a string. If the object has no fields,\n * then returns an empty string.\n *\n * @param style Defaults to 'short'\n */\nexport function formatDuration(duration: Duration, style?: DurationStyle) {\n style = style ?? \"short\";\n const stylePlural = getDurationStyleForPlural(style);\n\n const space = getValueAndUnitSeparator(style);\n\n const a: string[] = [];\n\n for (const unit of DURATION_TYPE_SEQUENCE) {\n const value = duration[unit];\n if (value === undefined) continue;\n\n const suffixMap = DURATION_STYLE_SUFFIX_MAP[unit];\n const suffix = value === 1 ? suffixMap[style] : suffixMap[stylePlural];\n a.push(value + space + suffix);\n }\n\n const separator = getDurationTypeSeparator(style);\n return a.join(separator);\n}\n\n/**\n * Convert a millisecond duration into a human-readable duration string.\n *\n * @param options.durationTypeForZero - Defaults to 'milliseconds'\n * @param options.style - Defaults to 'short'\n */\nexport function readableDuration(\n ms: number,\n options?: { durationTypeForZero?: DurationType; style?: DurationStyle },\n): string {\n const duration = msToDuration(ms, options?.durationTypeForZero);\n\n return formatDuration(duration, options?.style);\n}\n\n/** A shortened duration string useful for logging timings. */\nexport function elapsed(ms: number): string {\n // Use long format for 1 minute or over.\n if (ms > MS_PER_MINUTE) {\n return readableDuration(ms);\n }\n\n // Use seconds format for over 100ms.\n if (ms > 100) {\n return `${(ms / 1000).toFixed(3)}s`;\n }\n\n // Use milliseconds format.\n return ms + \"ms\";\n}\n"],"mappings":"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","names":["localStore_exports","__export","LocalStoreConfig","configureLocalStore","createLocalStore","localStore","localStoreItem","__toCommonJS","durationToMs","duration","daysMs","hoursMs","minsMs","secsMs","msMs","durationOrMsToMs","LocalStoreConfig","configureLocalStore","config","validateStoredObject","obj","createLocalStore","storeName","options","keyPrefix","defaultExpiryMs","durationOrMsToMs","gcIntervalMs","gcMsStorageKey","key","value","expiryDeltaMs","nowMs","stored","k","parsed","valid","e","callback","count","map","expiryMs","storedMs","lastGcMsStr","ms","lastGcMs","localStore","localStoreItem","store"]}
|