@choksheak/ts-utils 0.3.4 → 0.3.5

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.
Files changed (72) hide show
  1. package/README.md +9 -3
  2. package/asNumber.cjs +3 -3
  3. package/asNumber.d.mts +1 -1
  4. package/asNumber.d.ts +1 -1
  5. package/asNumber.min.cjs +1 -1
  6. package/asNumber.min.cjs.map +1 -1
  7. package/asNumber.min.mjs +1 -1
  8. package/asNumber.min.mjs.map +1 -1
  9. package/asNumber.mjs +3 -3
  10. package/kvStore.cjs +230 -239
  11. package/kvStore.d.mts +142 -44
  12. package/kvStore.d.ts +142 -44
  13. package/kvStore.min.cjs +1 -1
  14. package/kvStore.min.cjs.map +1 -1
  15. package/kvStore.min.mjs +1 -1
  16. package/kvStore.min.mjs.map +1 -1
  17. package/kvStore.mjs +229 -237
  18. package/localStore.cjs +187 -186
  19. package/localStore.d.mts +135 -34
  20. package/localStore.d.ts +135 -34
  21. package/localStore.min.cjs +1 -1
  22. package/localStore.min.cjs.map +1 -1
  23. package/localStore.min.mjs +1 -1
  24. package/localStore.min.mjs.map +1 -1
  25. package/localStore.mjs +186 -184
  26. package/mean.cjs +3 -3
  27. package/mean.min.cjs +1 -1
  28. package/mean.min.cjs.map +1 -1
  29. package/mean.min.mjs +1 -1
  30. package/mean.min.mjs.map +1 -1
  31. package/mean.mjs +3 -3
  32. package/median.cjs +4 -4
  33. package/median.min.cjs +1 -1
  34. package/median.min.cjs.map +1 -1
  35. package/median.min.mjs +1 -1
  36. package/median.min.mjs.map +1 -1
  37. package/median.mjs +4 -4
  38. package/package.json +2 -34
  39. package/safeBtoa.d.mts +7 -0
  40. package/safeBtoa.d.ts +7 -0
  41. package/safeBtoa.min.cjs.map +1 -1
  42. package/safeBtoa.min.mjs.map +1 -1
  43. package/sum.cjs +3 -3
  44. package/sum.min.cjs +1 -1
  45. package/sum.min.cjs.map +1 -1
  46. package/sum.min.mjs +1 -1
  47. package/sum.min.mjs.map +1 -1
  48. package/sum.mjs +3 -3
  49. package/timer.cjs +19 -24
  50. package/timer.d.mts +9 -6
  51. package/timer.d.ts +9 -6
  52. package/timer.min.cjs +1 -1
  53. package/timer.min.cjs.map +1 -1
  54. package/timer.min.mjs +1 -1
  55. package/timer.min.mjs.map +1 -1
  56. package/timer.mjs +19 -23
  57. package/safeParseFloat.cjs +0 -33
  58. package/safeParseFloat.d.mts +0 -6
  59. package/safeParseFloat.d.ts +0 -6
  60. package/safeParseFloat.min.cjs +0 -2
  61. package/safeParseFloat.min.cjs.map +0 -1
  62. package/safeParseFloat.min.mjs +0 -2
  63. package/safeParseFloat.min.mjs.map +0 -1
  64. package/safeParseFloat.mjs +0 -8
  65. package/safeParseInt.cjs +0 -33
  66. package/safeParseInt.d.mts +0 -6
  67. package/safeParseInt.d.ts +0 -6
  68. package/safeParseInt.min.cjs +0 -2
  69. package/safeParseInt.min.cjs.map +0 -1
  70. package/safeParseInt.min.mjs +0 -2
  71. package/safeParseInt.min.mjs.map +0 -1
  72. package/safeParseInt.mjs +0 -8
package/README.md CHANGED
@@ -1,8 +1,14 @@
1
1
  # @choksheak/ts-utils
2
2
 
3
- This package is a random bunch of Typescript utilities that I have needed in almost every project that I have worked in. Hence making an easy way to share this code and also for my own personal and professional use. Feel free to use it in your own projects without any restrictions.
4
-
5
- The code supports full tree-shaking. Therefore your code will only grow in size by whatever you use. Any code that you are not using will not contribute to your code size.
3
+ This package is a time-tested collection of Typescript utilities that I have
4
+ personally needed in almost every project that I have worked in. Making this an
5
+ open source, public npm package allows me to share this code freely with others
6
+ as well as using it for my own personal and professional projects. Feel free to
7
+ use it in your own projects without any restrictions.
8
+
9
+ The code supports full tree-shaking. Therefore your code will only grow in size
10
+ by whatever you use. Any code that you are not using will not contribute to
11
+ your code size.
6
12
 
7
13
  Source code: https://github.com/choksheak/ts-utils
8
14
 
package/asNumber.cjs CHANGED
@@ -23,15 +23,15 @@ __export(asNumber_exports, {
23
23
  asNumber: () => asNumber
24
24
  });
25
25
  module.exports = __toCommonJS(asNumber_exports);
26
- function asNumber(u) {
26
+ function asNumber(u, defaultValue = 0) {
27
27
  if (typeof u === "number") {
28
- return isFinite(u) ? u : 0;
28
+ return isFinite(u) ? u : defaultValue;
29
29
  }
30
30
  u = Number(u);
31
31
  if (typeof u === "number" && isFinite(u)) {
32
32
  return u;
33
33
  }
34
- return 0;
34
+ return defaultValue;
35
35
  }
36
36
  // Annotate the CommonJS export names for ESM import in node:
37
37
  0 && (module.exports = {
package/asNumber.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Coerce `u` into a number if possible, otherwise just return 0.
3
3
  */
4
- declare function asNumber(u: unknown): number;
4
+ declare function asNumber(u: unknown, defaultValue?: number): number;
5
5
 
6
6
  export { asNumber };
package/asNumber.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Coerce `u` into a number if possible, otherwise just return 0.
3
3
  */
4
- declare function asNumber(u: unknown): number;
4
+ declare function asNumber(u: unknown, defaultValue?: number): number;
5
5
 
6
6
  export { asNumber };
package/asNumber.min.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var t=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var o=Object.prototype.hasOwnProperty;var p=(e,n)=>{for(var i in n)t(e,i,{get:n[i],enumerable:!0})},s=(e,n,i,b)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of m(n))!o.call(e,r)&&r!==i&&t(e,r,{get:()=>n[r],enumerable:!(b=f(n,r))||b.enumerable});return e};var u=e=>s(t({},"__esModule",{value:!0}),e);var F={};p(F,{asNumber:()=>y});module.exports=u(F);function y(e){return typeof e=="number"?isFinite(e)?e:0:(e=Number(e),typeof e=="number"&&isFinite(e)?e:0)}0&&(module.exports={asNumber});
1
+ "use strict";var t=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var o=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var p=(n,r)=>{for(var i in r)t(n,i,{get:r[i],enumerable:!0})},s=(n,r,i,b)=>{if(r&&typeof r=="object"||typeof r=="function")for(let e of o(r))!f.call(n,e)&&e!==i&&t(n,e,{get:()=>r[e],enumerable:!(b=m(r,e))||b.enumerable});return n};var y=n=>s(t({},"__esModule",{value:!0}),n);var N={};p(N,{asNumber:()=>F});module.exports=y(N);function F(n,r=0){return typeof n=="number"?isFinite(n)?n:r:(n=Number(n),typeof n=="number"&&isFinite(n)?n:r)}0&&(module.exports={asNumber});
2
2
  //# sourceMappingURL=asNumber.min.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/asNumber.ts"],"sourcesContent":["/**\n * Coerce `u` into a number if possible, otherwise just return 0.\n */\nexport function asNumber(u: unknown): number {\n // If u is a valid number, return it.\n if (typeof u === \"number\") {\n return isFinite(u) ? u : 0;\n }\n\n // Try to make into a number if not already a number.\n u = Number(u);\n\n // If u is a valid number, return it.\n if (typeof u === \"number\" && isFinite(u)) {\n return u;\n }\n\n // Return 0 for everything else. This is usually ok if want to just ignore\n // all other noise.\n return 0;\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,IAAA,eAAAC,EAAAH,GAGO,SAASE,EAASE,EAAoB,CAE3C,OAAI,OAAOA,GAAM,SACR,SAASA,CAAC,EAAIA,EAAI,GAI3BA,EAAI,OAAOA,CAAC,EAGR,OAAOA,GAAM,UAAY,SAASA,CAAC,EAC9BA,EAKF,EACT","names":["asNumber_exports","__export","asNumber","__toCommonJS","u"]}
1
+ {"version":3,"sources":["../src/asNumber.ts"],"sourcesContent":["/**\n * Coerce `u` into a number if possible, otherwise just return 0.\n */\nexport function asNumber(u: unknown, defaultValue = 0): number {\n // If u is a valid number, return it.\n if (typeof u === \"number\") {\n return isFinite(u) ? u : defaultValue;\n }\n\n // Try to make into a number if not already a number.\n u = Number(u);\n\n // If u is a valid number, return it.\n if (typeof u === \"number\" && isFinite(u)) {\n return u;\n }\n\n // Return `defaultValue` for everything else. This is usually ok if want to\n // just ignore all other noise.\n return defaultValue;\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,IAAA,eAAAC,EAAAH,GAGO,SAASE,EAASE,EAAYC,EAAe,EAAW,CAE7D,OAAI,OAAOD,GAAM,SACR,SAASA,CAAC,EAAIA,EAAIC,GAI3BD,EAAI,OAAOA,CAAC,EAGR,OAAOA,GAAM,UAAY,SAASA,CAAC,EAC9BA,EAKFC,EACT","names":["asNumber_exports","__export","asNumber","__toCommonJS","u","defaultValue"]}
package/asNumber.min.mjs CHANGED
@@ -1,2 +1,2 @@
1
- function n(e){return typeof e=="number"?isFinite(e)?e:0:(e=Number(e),typeof e=="number"&&isFinite(e)?e:0)}export{n as asNumber};
1
+ function e(n,r=0){return typeof n=="number"?isFinite(n)?n:r:(n=Number(n),typeof n=="number"&&isFinite(n)?n:r)}export{e as asNumber};
2
2
  //# sourceMappingURL=asNumber.min.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/asNumber.ts"],"sourcesContent":["/**\n * Coerce `u` into a number if possible, otherwise just return 0.\n */\nexport function asNumber(u: unknown): number {\n // If u is a valid number, return it.\n if (typeof u === \"number\") {\n return isFinite(u) ? u : 0;\n }\n\n // Try to make into a number if not already a number.\n u = Number(u);\n\n // If u is a valid number, return it.\n if (typeof u === \"number\" && isFinite(u)) {\n return u;\n }\n\n // Return 0 for everything else. This is usually ok if want to just ignore\n // all other noise.\n return 0;\n}\n"],"mappings":"AAGO,SAASA,EAASC,EAAoB,CAE3C,OAAI,OAAOA,GAAM,SACR,SAASA,CAAC,EAAIA,EAAI,GAI3BA,EAAI,OAAOA,CAAC,EAGR,OAAOA,GAAM,UAAY,SAASA,CAAC,EAC9BA,EAKF,EACT","names":["asNumber","u"]}
1
+ {"version":3,"sources":["../src/asNumber.ts"],"sourcesContent":["/**\n * Coerce `u` into a number if possible, otherwise just return 0.\n */\nexport function asNumber(u: unknown, defaultValue = 0): number {\n // If u is a valid number, return it.\n if (typeof u === \"number\") {\n return isFinite(u) ? u : defaultValue;\n }\n\n // Try to make into a number if not already a number.\n u = Number(u);\n\n // If u is a valid number, return it.\n if (typeof u === \"number\" && isFinite(u)) {\n return u;\n }\n\n // Return `defaultValue` for everything else. This is usually ok if want to\n // just ignore all other noise.\n return defaultValue;\n}\n"],"mappings":"AAGO,SAASA,EAASC,EAAYC,EAAe,EAAW,CAE7D,OAAI,OAAOD,GAAM,SACR,SAASA,CAAC,EAAIA,EAAIC,GAI3BD,EAAI,OAAOA,CAAC,EAGR,OAAOA,GAAM,UAAY,SAASA,CAAC,EAC9BA,EAKFC,EACT","names":["asNumber","u","defaultValue"]}
package/asNumber.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  // src/asNumber.ts
2
- function asNumber(u) {
2
+ function asNumber(u, defaultValue = 0) {
3
3
  if (typeof u === "number") {
4
- return isFinite(u) ? u : 0;
4
+ return isFinite(u) ? u : defaultValue;
5
5
  }
6
6
  u = Number(u);
7
7
  if (typeof u === "number" && isFinite(u)) {
8
8
  return u;
9
9
  }
10
- return 0;
10
+ return defaultValue;
11
11
  }
12
12
  export {
13
13
  asNumber
package/kvStore.cjs CHANGED
@@ -20,10 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/kvStore.ts
21
21
  var kvStore_exports = {};
22
22
  __export(kvStore_exports, {
23
- KvStore: () => KvStore,
24
23
  KvStoreConfig: () => KvStoreConfig,
25
- KvStoreItem: () => KvStoreItem,
26
24
  configureKvStore: () => configureKvStore,
25
+ createKvStore: () => createKvStore,
27
26
  kvStore: () => kvStore,
28
27
  kvStoreItem: () => kvStoreItem
29
28
  });
@@ -85,33 +84,20 @@ function withOnError(request, reject) {
85
84
  };
86
85
  return request;
87
86
  }
88
- var KvStore = class {
89
- constructor(dbName, options) {
90
- this.dbName = dbName;
91
- this.dbVersion = options?.dbVersion ?? KvStoreConfig.dbVersion;
92
- this.storeName = options?.storeName ?? KvStoreConfig.storeName;
93
- this.defaultExpiryMs = options?.defaultExpiryMs ? durationOrMsToMs(options.defaultExpiryMs) : KvStoreConfig.expiryMs;
94
- this.gcIntervalMs = options?.gcIntervalMs ? durationOrMsToMs(options.gcIntervalMs) : KvStoreConfig.gcIntervalMs;
95
- this.gcMsStorageKey = `__kvStore:lastGcMs:${dbName}:v${this.dbVersion}:${this.storeName}`;
96
- }
97
- /** We'll init the DB only on first use. */
98
- db;
99
- /** Local storage key name for the last GC completed timestamp. */
100
- gcMsStorageKey;
101
- dbVersion;
102
- storeName;
103
- defaultExpiryMs;
104
- gcIntervalMs;
105
- async getOrCreateDb() {
106
- if (!this.db) {
107
- this.db = await new Promise((resolve, reject) => {
108
- const request = withOnError(
109
- globalThis.indexedDB.open(this.dbName, this.dbVersion),
110
- reject
111
- );
87
+ function createKvStore(dbName, options) {
88
+ let db;
89
+ const dbVersion = options?.dbVersion ?? KvStoreConfig.dbVersion;
90
+ const storeName = options?.storeName ?? KvStoreConfig.storeName;
91
+ const defaultExpiryMs = options?.defaultExpiryMs ? durationOrMsToMs(options.defaultExpiryMs) : KvStoreConfig.expiryMs;
92
+ const gcIntervalMs = options?.gcIntervalMs ? durationOrMsToMs(options.gcIntervalMs) : KvStoreConfig.gcIntervalMs;
93
+ const gcMsStorageKey = `__kvStore:lastGcMs:${dbName}:v${dbVersion}:${storeName}`;
94
+ async function getOrCreateDb() {
95
+ if (!db) {
96
+ db = await new Promise((resolve, reject) => {
97
+ const request = withOnError(indexedDB.open(dbName, dbVersion), reject);
112
98
  request.onupgradeneeded = (event) => {
113
- const db = event.target.result;
114
- const objectStore = db.createObjectStore(this.storeName, {
99
+ const db2 = event.target.result;
100
+ const objectStore = db2.createObjectStore(storeName, {
115
101
  keyPath: "key"
116
102
  });
117
103
  objectStore.createIndex("key", "key", {
@@ -119,248 +105,253 @@ var KvStore = class {
119
105
  });
120
106
  };
121
107
  request.onsuccess = (event) => {
122
- const db = event.target.result;
123
- resolve(db);
108
+ const db2 = event.target.result;
109
+ resolve(db2);
124
110
  };
125
111
  });
126
112
  }
127
- return this.db;
113
+ return db;
128
114
  }
129
- async transact(mode, callback) {
130
- const db = await this.getOrCreateDb();
115
+ async function transact(mode, callback) {
116
+ const db2 = await getOrCreateDb();
131
117
  return await new Promise((resolve, reject) => {
132
- const transaction = withOnError(
133
- db.transaction(this.storeName, mode),
134
- reject
135
- );
118
+ const transaction = withOnError(db2.transaction(storeName, mode), reject);
136
119
  transaction.onabort = (event) => {
137
120
  reject(event);
138
121
  };
139
- const objectStore = transaction.objectStore(this.storeName);
122
+ const objectStore = transaction.objectStore(storeName);
140
123
  callback(objectStore, resolve, reject);
141
124
  });
142
125
  }
143
- /** Set a value in the store. */
144
- async set(key, value, expiryDeltaMs = this.defaultExpiryMs) {
145
- const nowMs = Date.now();
146
- const obj = {
147
- key,
148
- value,
149
- storedMs: nowMs,
150
- expiryMs: nowMs + durationOrMsToMs(expiryDeltaMs)
151
- };
152
- return await this.transact(
153
- "readwrite",
154
- (objectStore, resolve, reject) => {
155
- const request = withOnError(objectStore.put(obj), reject);
126
+ const obj = {
127
+ /** Input name for the DB. */
128
+ dbName,
129
+ /** Input version for the DB. */
130
+ dbVersion,
131
+ /** Input name for the DB store. */
132
+ storeName,
133
+ /** Default expiry to use if not specified in set(). */
134
+ defaultExpiryMs,
135
+ /** Time interval for when GC's occur. */
136
+ gcIntervalMs,
137
+ /** Local storage key name for the last GC completed timestamp. */
138
+ gcMsStorageKey,
139
+ /** Set a value in the store. */
140
+ async set(key, value, expiryDeltaMs) {
141
+ const nowMs = Date.now();
142
+ const stored = {
143
+ key,
144
+ value,
145
+ storedMs: nowMs,
146
+ expiryMs: nowMs + durationOrMsToMs(expiryDeltaMs ?? defaultExpiryMs)
147
+ };
148
+ return await transact("readwrite", (objectStore, resolve, reject) => {
149
+ const request = withOnError(objectStore.put(stored), reject);
156
150
  request.onsuccess = () => {
157
151
  resolve(value);
158
- this.gc();
159
- };
160
- }
161
- );
162
- }
163
- /** Delete one or multiple keys. */
164
- async delete(key) {
165
- return await this.transact(
166
- "readwrite",
167
- (objectStore, resolve, reject) => {
168
- objectStore.transaction.oncomplete = () => {
169
- resolve();
152
+ obj.gc();
170
153
  };
171
- if (typeof key === "string") {
172
- withOnError(objectStore.delete(key), reject);
173
- } else {
174
- for (const k of key) {
175
- withOnError(objectStore.delete(k), reject);
154
+ });
155
+ },
156
+ /** Delete one or multiple keys. */
157
+ async delete(key) {
158
+ return await transact(
159
+ "readwrite",
160
+ (objectStore, resolve, reject) => {
161
+ objectStore.transaction.oncomplete = () => {
162
+ resolve();
163
+ };
164
+ if (typeof key === "string") {
165
+ withOnError(objectStore.delete(key), reject);
166
+ } else {
167
+ for (const k of key) {
168
+ withOnError(objectStore.delete(k), reject);
169
+ }
176
170
  }
177
171
  }
172
+ );
173
+ },
174
+ /** Mainly used to get the expiration timestamp of an object. */
175
+ async getStoredObject(key) {
176
+ const stored = await transact(
177
+ "readonly",
178
+ (objectStore, resolve, reject) => {
179
+ const request = withOnError(objectStore.get(key), reject);
180
+ request.onsuccess = () => {
181
+ resolve(request.result);
182
+ };
183
+ }
184
+ );
185
+ if (!stored) {
186
+ return void 0;
178
187
  }
179
- );
180
- }
181
- /** Mainly used to get the expiration timestamp of an object. */
182
- async getStoredObject(key) {
183
- const stored = await this.transact(
184
- "readonly",
185
- (objectStore, resolve, reject) => {
186
- const request = withOnError(objectStore.get(key), reject);
187
- request.onsuccess = () => {
188
- resolve(request.result);
189
- };
190
- }
191
- );
192
- if (!stored) {
193
- return void 0;
194
- }
195
- try {
196
- const obj = validateStoredObject(stored);
197
- if (!obj) {
198
- await this.delete(key);
199
- this.gc();
188
+ try {
189
+ const valid = validateStoredObject(stored);
190
+ if (!valid) {
191
+ await obj.delete(key);
192
+ obj.gc();
193
+ return void 0;
194
+ }
195
+ return valid;
196
+ } catch (e) {
197
+ console.error(`Invalid kv value: ${key}=${JSON.stringify(stored)}:`, e);
198
+ await obj.delete(key);
199
+ obj.gc();
200
200
  return void 0;
201
201
  }
202
- return obj;
203
- } catch (e) {
204
- console.error(`Invalid kv value: ${key}=${JSON.stringify(stored)}:`, e);
205
- await this.delete(key);
206
- this.gc();
207
- return void 0;
208
- }
209
- }
210
- /** Get a value by key, or undefined if it does not exist. */
211
- async get(key) {
212
- const obj = await this.getStoredObject(key);
213
- return obj?.value;
214
- }
215
- /** Generic way to iterate through all entries. */
216
- async forEach(callback) {
217
- await this.transact("readonly", (objectStore, resolve, reject) => {
218
- const request = withOnError(objectStore.openCursor(), reject);
219
- request.onsuccess = async (event) => {
220
- const cursor = event.target.result;
221
- if (cursor) {
222
- if (cursor.key) {
223
- const obj = validateStoredObject(cursor.value);
224
- if (obj !== void 0) {
225
- await callback(
226
- String(cursor.key),
227
- obj.value,
228
- obj.expiryMs,
229
- obj.storedMs
230
- );
202
+ },
203
+ /** Get a value by key, or undefined if it does not exist. */
204
+ async get(key) {
205
+ const stored = await obj.getStoredObject(key);
206
+ return stored?.value;
207
+ },
208
+ /** Generic way to iterate through all entries. */
209
+ async forEach(callback) {
210
+ await transact("readonly", (objectStore, resolve, reject) => {
211
+ const request = withOnError(objectStore.openCursor(), reject);
212
+ request.onsuccess = async (event) => {
213
+ const cursor = event.target.result;
214
+ if (cursor) {
215
+ if (cursor.key) {
216
+ const valid = validateStoredObject(cursor.value);
217
+ if (valid !== void 0) {
218
+ await callback(
219
+ String(cursor.key),
220
+ valid.value,
221
+ valid.expiryMs,
222
+ valid.storedMs
223
+ );
224
+ }
231
225
  }
226
+ cursor.continue();
227
+ } else {
228
+ resolve();
232
229
  }
233
- cursor.continue();
234
- } else {
230
+ };
231
+ });
232
+ },
233
+ /**
234
+ * Returns the number of items in the store. Note that getting the size
235
+ * requires iterating through the entire store because the items could expire
236
+ * at any time, and hence the size is a dynamic number.
237
+ */
238
+ async size() {
239
+ let count = 0;
240
+ await obj.forEach(() => {
241
+ count++;
242
+ });
243
+ return count;
244
+ },
245
+ /** Remove all items from the store. */
246
+ async clear() {
247
+ await transact("readwrite", (objectStore, resolve, reject) => {
248
+ const request = withOnError(objectStore.clear(), reject);
249
+ request.onsuccess = () => {
235
250
  resolve();
251
+ };
252
+ });
253
+ },
254
+ /**
255
+ * Returns all items as map of key to value, mainly used for debugging dumps.
256
+ * The type T is applied to all values, even though they might not be of type
257
+ * T (in the case when you store different data types in the same store).
258
+ */
259
+ async asMap() {
260
+ const map = /* @__PURE__ */ new Map();
261
+ await obj.forEach((key, value, expiryMs, storedMs) => {
262
+ map.set(key, { value, expiryMs, storedMs });
263
+ });
264
+ return map;
265
+ },
266
+ /** Returns the ms timestamp for the last GC (garbage collection). */
267
+ getLastGcMs() {
268
+ const lastGcMsStr = localStorage.getItem(gcMsStorageKey);
269
+ if (!lastGcMsStr) return 0;
270
+ const ms = Number(lastGcMsStr);
271
+ return isNaN(ms) ? 0 : ms;
272
+ },
273
+ /** Set the ms timestamp for the last GC (garbage collection). */
274
+ setLastGcMs(ms) {
275
+ localStorage.setItem(gcMsStorageKey, String(ms));
276
+ },
277
+ /** Perform garbage-collection if due, else do nothing. */
278
+ async gc() {
279
+ const lastGcMs = obj.getLastGcMs();
280
+ if (!lastGcMs) {
281
+ obj.setLastGcMs(Date.now());
282
+ return;
283
+ }
284
+ if (Date.now() < lastGcMs + gcIntervalMs) {
285
+ return;
286
+ }
287
+ await obj.gcNow();
288
+ },
289
+ /**
290
+ * Perform garbage collection immediately without checking whether we are
291
+ * due for the next GC or not.
292
+ */
293
+ async gcNow() {
294
+ console.log(`Starting kvStore GC on ${dbName} v${dbVersion}...`);
295
+ obj.setLastGcMs(Date.now());
296
+ const keysToDelete = [];
297
+ await obj.forEach(
298
+ async (key, value, expiryMs) => {
299
+ if (value === void 0 || Date.now() >= expiryMs) {
300
+ keysToDelete.push(key);
301
+ }
236
302
  }
237
- };
238
- });
239
- }
240
- /**
241
- * Returns the number of items in the store. Note that getting the size
242
- * requires iterating through the entire store because the items could expire
243
- * at any time, and hence the size is a dynamic number.
244
- */
245
- async size() {
246
- let count = 0;
247
- await this.forEach(() => {
248
- count++;
249
- });
250
- return count;
251
- }
252
- /** Remove all items from the store. */
253
- async clear() {
254
- await this.transact("readwrite", (objectStore, resolve, reject) => {
255
- const request = withOnError(objectStore.clear(), reject);
256
- request.onsuccess = () => {
257
- resolve();
258
- };
259
- });
260
- }
261
- /**
262
- * Returns all items as map of key to value, mainly used for debugging dumps.
263
- * The type T is applied to all values, even though they might not be of type
264
- * T (in the case when you store different data types in the same store).
265
- */
266
- async asMap() {
267
- const map = /* @__PURE__ */ new Map();
268
- await this.forEach((key, value, expiryMs, storedMs) => {
269
- map.set(key, { value, expiryMs, storedMs });
270
- });
271
- return map;
272
- }
273
- /** Returns the ms timestamp for the last GC (garbage collection). */
274
- get lastGcMs() {
275
- const lastGcMsStr = globalThis.localStorage.getItem(this.gcMsStorageKey);
276
- if (!lastGcMsStr) return 0;
277
- const ms = Number(lastGcMsStr);
278
- return isNaN(ms) ? 0 : ms;
279
- }
280
- /** Set the ms timestamp for the last GC (garbage collection). */
281
- set lastGcMs(ms) {
282
- globalThis.localStorage.setItem(this.gcMsStorageKey, String(ms));
283
- }
284
- /** Perform garbage-collection if due, else do nothing. */
285
- async gc() {
286
- const lastGcMs = this.lastGcMs;
287
- if (!lastGcMs) {
288
- this.lastGcMs = Date.now();
289
- return;
290
- }
291
- if (Date.now() < lastGcMs + this.gcIntervalMs) {
292
- return;
293
- }
294
- await this.gcNow();
295
- }
296
- /**
297
- * Perform garbage collection immediately without checking whether we are
298
- * due for the next GC or not.
299
- */
300
- async gcNow() {
301
- console.log(`Starting kvStore GC on ${this.dbName} v${this.dbVersion}...`);
302
- this.lastGcMs = Date.now();
303
- const keysToDelete = [];
304
- await this.forEach(
305
- async (key, value, expiryMs) => {
306
- if (value === void 0 || Date.now() >= expiryMs) {
307
- keysToDelete.push(key);
308
- }
303
+ );
304
+ if (keysToDelete.length) {
305
+ await obj.delete(keysToDelete);
309
306
  }
310
- );
311
- if (keysToDelete.length) {
312
- await this.delete(keysToDelete);
307
+ console.log(
308
+ `Finished kvStore GC on ${dbName} v${dbVersion} - deleted ${keysToDelete.length} keys`
309
+ );
310
+ obj.setLastGcMs(Date.now());
311
+ },
312
+ /** Returns `this` casted into a StorageAdapter<T>. */
313
+ asStorageAdapter() {
314
+ return obj;
313
315
  }
314
- console.log(
315
- `Finished kvStore GC on ${this.dbName} v${this.dbVersion} - deleted ${keysToDelete.length} keys`
316
- );
317
- this.lastGcMs = Date.now();
318
- }
319
- /** Returns `this` casted into a StorageAdapter<T>. */
320
- asStorageAdapter() {
321
- return this;
322
- }
323
- };
324
- var kvStore = new KvStore(KvStoreConfig.dbName);
325
- var KvStoreItem = class {
326
- constructor(key, defaultExpiryMs = KvStoreConfig.expiryMs, store = kvStore) {
327
- this.key = key;
328
- this.store = store;
329
- this.defaultExpiryMs = defaultExpiryMs && durationOrMsToMs(defaultExpiryMs);
330
- }
331
- defaultExpiryMs;
332
- /** Set a value in the store. */
333
- async set(value, expiryDeltaMs = this.defaultExpiryMs) {
334
- await this.store.set(this.key, value, expiryDeltaMs);
335
- }
336
- /**
337
- * Example usage:
338
- *
339
- * const { value, storedMs, expiryMs, storedMs } =
340
- * await myKvItem.getStoredObject();
341
- */
342
- async getStoredObject() {
343
- return await this.store.getStoredObject(this.key);
344
- }
345
- /** Get a value by key, or undefined if it does not exist. */
346
- async get() {
347
- return await this.store.get(this.key);
348
- }
349
- /** Delete this key from the store. */
350
- async delete() {
351
- await this.store.delete(this.key);
352
- }
353
- };
316
+ };
317
+ return obj;
318
+ }
319
+ var kvStore = createKvStore(KvStoreConfig.dbName);
354
320
  function kvStoreItem(key, expiryMs, store = kvStore) {
355
- expiryMs = expiryMs && durationOrMsToMs(expiryMs);
356
- return new KvStoreItem(key, expiryMs, store);
321
+ const defaultExpiryMs = expiryMs && durationOrMsToMs(expiryMs);
322
+ const obj = {
323
+ key,
324
+ defaultExpiryMs,
325
+ store,
326
+ /** Set a value in the store. */
327
+ async set(value, expiryDeltaMs) {
328
+ await store.set(key, value, expiryDeltaMs ?? defaultExpiryMs);
329
+ },
330
+ /**
331
+ * Example usage:
332
+ *
333
+ * const { value, storedMs, expiryMs, storedMs } =
334
+ * await myKvItem.getStoredObject();
335
+ */
336
+ async getStoredObject() {
337
+ return await store.getStoredObject(key);
338
+ },
339
+ /** Get a value by key, or undefined if it does not exist. */
340
+ async get() {
341
+ return await store.get(key);
342
+ },
343
+ /** Delete this key from the store. */
344
+ async delete() {
345
+ await store.delete(key);
346
+ }
347
+ };
348
+ return obj;
357
349
  }
358
350
  // Annotate the CommonJS export names for ESM import in node:
359
351
  0 && (module.exports = {
360
- KvStore,
361
352
  KvStoreConfig,
362
- KvStoreItem,
363
353
  configureKvStore,
354
+ createKvStore,
364
355
  kvStore,
365
356
  kvStoreItem
366
357
  });