@choksheak/ts-utils 0.2.9 → 0.3.1

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 (315) hide show
  1. package/README.md +2 -0
  2. package/{arrayBuffer.js → arrayBuffer.cjs} +0 -1
  3. package/arrayBuffer.d.mts +10 -0
  4. package/arrayBuffer.d.ts +4 -2
  5. package/arrayBuffer.min.cjs +2 -0
  6. package/arrayBuffer.min.cjs.map +1 -0
  7. package/arrayBuffer.min.mjs +2 -0
  8. package/{arrayBuffer.js.map → arrayBuffer.min.mjs.map} +1 -1
  9. package/arrayBuffer.mjs +14 -0
  10. package/{assert.js → assert.cjs} +0 -1
  11. package/assert.d.mts +7 -0
  12. package/assert.d.ts +3 -1
  13. package/assert.min.cjs +2 -0
  14. package/assert.min.cjs.map +1 -0
  15. package/assert.min.mjs +2 -0
  16. package/{assert.js.map → assert.min.mjs.map} +1 -1
  17. package/assert.mjs +11 -0
  18. package/{average.js → average.cjs} +0 -1
  19. package/average.d.mts +7 -0
  20. package/average.d.ts +3 -1
  21. package/average.min.cjs +2 -0
  22. package/{average.js.map → average.min.cjs.map} +1 -1
  23. package/average.min.mjs +2 -0
  24. package/average.min.mjs.map +1 -0
  25. package/average.mjs +20 -0
  26. package/{base64Url.js → base64Url.cjs} +0 -1
  27. package/base64Url.d.mts +10 -0
  28. package/base64Url.d.ts +4 -2
  29. package/base64Url.min.cjs +2 -0
  30. package/base64Url.min.cjs.map +1 -0
  31. package/base64Url.min.mjs +2 -0
  32. package/{base64Url.js.map → base64Url.min.mjs.map} +1 -1
  33. package/base64Url.mjs +14 -0
  34. package/{dateTimeStr.js → dateTimeStr.cjs} +0 -1
  35. package/dateTimeStr.d.mts +85 -0
  36. package/dateTimeStr.d.ts +15 -13
  37. package/dateTimeStr.min.cjs +2 -0
  38. package/dateTimeStr.min.cjs.map +1 -0
  39. package/dateTimeStr.min.mjs +2 -0
  40. package/{dateTimeStr.js.map → dateTimeStr.min.mjs.map} +1 -1
  41. package/dateTimeStr.mjs +83 -0
  42. package/{duration.js → duration.cjs} +9 -11
  43. package/duration.d.mts +78 -0
  44. package/duration.d.ts +15 -13
  45. package/duration.min.cjs +2 -0
  46. package/duration.min.cjs.map +1 -0
  47. package/duration.min.mjs +2 -0
  48. package/duration.min.mjs.map +1 -0
  49. package/duration.mjs +154 -0
  50. package/{isEmpty.js → isEmpty.cjs} +0 -1
  51. package/isEmpty.d.mts +6 -0
  52. package/isEmpty.d.ts +3 -1
  53. package/isEmpty.min.cjs +2 -0
  54. package/isEmpty.min.cjs.map +1 -0
  55. package/isEmpty.min.mjs +2 -0
  56. package/{isEmpty.js.map → isEmpty.min.mjs.map} +1 -1
  57. package/isEmpty.mjs +22 -0
  58. package/iterators.cjs +34 -0
  59. package/iterators.d.mts +4 -0
  60. package/iterators.d.ts +4 -0
  61. package/iterators.min.cjs +2 -0
  62. package/iterators.min.cjs.map +1 -0
  63. package/iterators.min.mjs +2 -0
  64. package/iterators.min.mjs.map +1 -0
  65. package/iterators.mjs +9 -0
  66. package/kvStore.cjs +365 -0
  67. package/kvStore.d.mts +139 -0
  68. package/kvStore.d.ts +95 -50
  69. package/kvStore.min.cjs +2 -0
  70. package/kvStore.min.cjs.map +1 -0
  71. package/kvStore.min.mjs +2 -0
  72. package/kvStore.min.mjs.map +1 -0
  73. package/kvStore.mjs +333 -0
  74. package/localStore.cjs +267 -0
  75. package/localStore.d.mts +119 -0
  76. package/localStore.d.ts +119 -0
  77. package/localStore.min.cjs +2 -0
  78. package/localStore.min.cjs.map +1 -0
  79. package/localStore.min.mjs +2 -0
  80. package/localStore.min.mjs.map +1 -0
  81. package/localStore.mjs +235 -0
  82. package/{logging.js → logging.cjs} +0 -1
  83. package/logging.d.mts +4 -0
  84. package/logging.d.ts +4 -2
  85. package/logging.min.cjs +2 -0
  86. package/logging.min.cjs.map +1 -0
  87. package/logging.min.mjs +2 -0
  88. package/{logging.js.map → logging.min.mjs.map} +1 -1
  89. package/logging.mjs +21 -0
  90. package/{nonEmpty.js → nonEmpty.cjs} +0 -1
  91. package/nonEmpty.d.mts +10 -0
  92. package/nonEmpty.d.ts +3 -1
  93. package/nonEmpty.min.cjs +2 -0
  94. package/{nonEmpty.js.map → nonEmpty.min.cjs.map} +1 -1
  95. package/nonEmpty.min.mjs +2 -0
  96. package/nonEmpty.min.mjs.map +1 -0
  97. package/nonEmpty.mjs +30 -0
  98. package/{nonNil.js → nonNil.cjs} +0 -1
  99. package/{src/nonNil.ts → nonNil.d.mts} +3 -6
  100. package/nonNil.d.ts +3 -1
  101. package/nonNil.min.cjs +2 -0
  102. package/nonNil.min.cjs.map +1 -0
  103. package/nonNil.min.mjs +2 -0
  104. package/{nonNil.js.map → nonNil.min.mjs.map} +1 -1
  105. package/nonNil.mjs +10 -0
  106. package/package.json +447 -24
  107. package/{round.js → round.cjs} +0 -1
  108. package/{src/round.ts → round.d.mts} +4 -8
  109. package/round.d.ts +4 -2
  110. package/round.min.cjs +2 -0
  111. package/round.min.cjs.map +1 -0
  112. package/round.min.mjs +2 -0
  113. package/{round.js.map → round.min.mjs.map} +1 -1
  114. package/round.mjs +12 -0
  115. package/{safeBtoa.js → safeBtoa.cjs} +0 -1
  116. package/safeBtoa.d.mts +6 -0
  117. package/safeBtoa.d.ts +3 -1
  118. package/safeBtoa.min.cjs +2 -0
  119. package/safeBtoa.min.cjs.map +1 -0
  120. package/safeBtoa.min.mjs +2 -0
  121. package/{safeBtoa.js.map → safeBtoa.min.mjs.map} +1 -1
  122. package/safeBtoa.mjs +9 -0
  123. package/{safeParseFloat.js → safeParseFloat.cjs} +0 -1
  124. package/safeParseFloat.d.mts +6 -0
  125. package/safeParseFloat.d.ts +3 -1
  126. package/safeParseFloat.min.cjs +2 -0
  127. package/safeParseFloat.min.cjs.map +1 -0
  128. package/safeParseFloat.min.mjs +2 -0
  129. package/{safeParseFloat.js.map → safeParseFloat.min.mjs.map} +1 -1
  130. package/safeParseFloat.mjs +8 -0
  131. package/{safeParseInt.js → safeParseInt.cjs} +0 -1
  132. package/safeParseInt.d.mts +6 -0
  133. package/safeParseInt.d.ts +3 -1
  134. package/safeParseInt.min.cjs +2 -0
  135. package/safeParseInt.min.cjs.map +1 -0
  136. package/safeParseInt.min.mjs +2 -0
  137. package/{safeParseInt.js.map → safeParseInt.min.mjs.map} +1 -1
  138. package/safeParseInt.mjs +8 -0
  139. package/sha256.cjs +35 -0
  140. package/sha256.d.mts +6 -0
  141. package/sha256.d.ts +3 -1
  142. package/sha256.min.cjs +2 -0
  143. package/sha256.min.cjs.map +1 -0
  144. package/sha256.min.mjs +2 -0
  145. package/{sha256.js.map → sha256.min.mjs.map} +1 -1
  146. package/sha256.mjs +10 -0
  147. package/{sleep.js → sleep.cjs} +0 -1
  148. package/{src/sleep.ts → sleep.d.mts} +3 -3
  149. package/sleep.d.ts +3 -1
  150. package/sleep.min.cjs +2 -0
  151. package/sleep.min.cjs.map +1 -0
  152. package/sleep.min.mjs +2 -0
  153. package/{sleep.js.map → sleep.min.mjs.map} +1 -1
  154. package/sleep.mjs +7 -0
  155. package/storageAdapter.cjs +18 -0
  156. package/storageAdapter.d.mts +33 -0
  157. package/storageAdapter.d.ts +33 -0
  158. package/storageAdapter.min.cjs +2 -0
  159. package/storageAdapter.min.cjs.map +1 -0
  160. package/storageAdapter.min.mjs +1 -0
  161. package/storageAdapter.min.mjs.map +1 -0
  162. package/storageAdapter.mjs +0 -0
  163. package/{sum.js → sum.cjs} +0 -1
  164. package/sum.d.mts +7 -0
  165. package/sum.d.ts +3 -1
  166. package/sum.min.cjs +2 -0
  167. package/sum.min.cjs.map +1 -0
  168. package/sum.min.mjs +2 -0
  169. package/{sum.js.map → sum.min.mjs.map} +1 -1
  170. package/sum.mjs +13 -0
  171. package/{timeConstants.js → timeConstants.cjs} +0 -1
  172. package/timeConstants.d.mts +20 -0
  173. package/timeConstants.d.ts +16 -14
  174. package/timeConstants.min.cjs +2 -0
  175. package/timeConstants.min.cjs.map +1 -0
  176. package/timeConstants.min.mjs +2 -0
  177. package/{timeConstants.js.map → timeConstants.min.mjs.map} +1 -1
  178. package/timeConstants.mjs +31 -0
  179. package/{timer.js → timer.cjs} +6 -6
  180. package/timer.d.mts +13 -0
  181. package/timer.d.ts +4 -2
  182. package/timer.min.cjs +2 -0
  183. package/timer.min.cjs.map +1 -0
  184. package/timer.min.mjs +2 -0
  185. package/timer.min.mjs.map +1 -0
  186. package/timer.mjs +161 -0
  187. package/docs/.nojekyll +0 -1
  188. package/docs/assets/hierarchy.js +0 -1
  189. package/docs/assets/highlight.css +0 -22
  190. package/docs/assets/icons.js +0 -18
  191. package/docs/assets/icons.svg +0 -1
  192. package/docs/assets/main.js +0 -60
  193. package/docs/assets/navigation.js +0 -1
  194. package/docs/assets/search.js +0 -1
  195. package/docs/assets/style.css +0 -1640
  196. package/docs/classes/kvStore.KVStore.html +0 -26
  197. package/docs/classes/kvStore.KVStoreField.html +0 -7
  198. package/docs/classes/timer.Timer.html +0 -8
  199. package/docs/functions/arrayBuffer.arrayBufferToBase64.html +0 -2
  200. package/docs/functions/arrayBuffer.arrayBufferToHex.html +0 -2
  201. package/docs/functions/assert.assert.html +0 -3
  202. package/docs/functions/average.average.html +0 -3
  203. package/docs/functions/base64Url.base64ToBase64URL.html +0 -2
  204. package/docs/functions/base64Url.base64UrlToBase64.html +0 -2
  205. package/docs/functions/dateTimeStr.getDisplayDateTime.html +0 -3
  206. package/docs/functions/dateTimeStr.getLongMonthNameOneIndexed.html +0 -4
  207. package/docs/functions/dateTimeStr.getLongMonthNameZeroIndexed.html +0 -4
  208. package/docs/functions/dateTimeStr.getShortMonthNameOneIndexed.html +0 -4
  209. package/docs/functions/dateTimeStr.getShortMonthNameZeroIndexed.html +0 -4
  210. package/docs/functions/dateTimeStr.hhMm.html +0 -4
  211. package/docs/functions/dateTimeStr.hhMmSs.html +0 -4
  212. package/docs/functions/dateTimeStr.hhMmSsMs.html +0 -5
  213. package/docs/functions/dateTimeStr.toDate.html +0 -4
  214. package/docs/functions/dateTimeStr.tzShort.html +0 -4
  215. package/docs/functions/dateTimeStr.yyyyMm.html +0 -4
  216. package/docs/functions/dateTimeStr.yyyyMmDd.html +0 -4
  217. package/docs/functions/duration.durationOrMsToMs.html +0 -2
  218. package/docs/functions/duration.durationToMs.html +0 -2
  219. package/docs/functions/duration.elapsed.html +0 -2
  220. package/docs/functions/duration.formatDuration.html +0 -4
  221. package/docs/functions/duration.msToDuration.html +0 -5
  222. package/docs/functions/duration.readableDuration.html +0 -4
  223. package/docs/functions/isEmpty.isEmpty.html +0 -2
  224. package/docs/functions/kvStore.kvStoreItem.html +0 -2
  225. package/docs/functions/localStorageCache.storeItem.html +0 -15
  226. package/docs/functions/logging.capLength.html +0 -1
  227. package/docs/functions/logging.stringify.html +0 -1
  228. package/docs/functions/nonEmpty.nonEmpty.html +0 -5
  229. package/docs/functions/nonNil.nonNil.html +0 -5
  230. package/docs/functions/round.round.html +0 -5
  231. package/docs/functions/round.roundS.html +0 -3
  232. package/docs/functions/safeBtoa.safeBtoa.html +0 -2
  233. package/docs/functions/safeParseFloat.safeParseFloat.html +0 -2
  234. package/docs/functions/safeParseInt.safeParseInt.html +0 -2
  235. package/docs/functions/sha256.sha256.html +0 -2
  236. package/docs/functions/sleep.sleep.html +0 -3
  237. package/docs/functions/sum.sum.html +0 -3
  238. package/docs/functions/timer.timer.html +0 -2
  239. package/docs/hierarchy.html +0 -1
  240. package/docs/index.html +0 -4
  241. package/docs/modules/arrayBuffer.html +0 -1
  242. package/docs/modules/assert.html +0 -1
  243. package/docs/modules/average.html +0 -1
  244. package/docs/modules/base64Url.html +0 -1
  245. package/docs/modules/dateTimeStr.html +0 -1
  246. package/docs/modules/duration.html +0 -1
  247. package/docs/modules/isEmpty.html +0 -1
  248. package/docs/modules/kvStore.html +0 -1
  249. package/docs/modules/localStorageCache.html +0 -1
  250. package/docs/modules/logging.html +0 -1
  251. package/docs/modules/nonEmpty.html +0 -1
  252. package/docs/modules/nonNil.html +0 -1
  253. package/docs/modules/round.html +0 -1
  254. package/docs/modules/safeBtoa.html +0 -1
  255. package/docs/modules/safeParseFloat.html +0 -1
  256. package/docs/modules/safeParseInt.html +0 -1
  257. package/docs/modules/sha256.html +0 -1
  258. package/docs/modules/sleep.html +0 -1
  259. package/docs/modules/sum.html +0 -1
  260. package/docs/modules/timeConstants.html +0 -1
  261. package/docs/modules/timer.html +0 -1
  262. package/docs/modules.html +0 -1
  263. package/docs/types/dateTimeStr.AnyDateTime.html +0 -1
  264. package/docs/types/duration.Duration.html +0 -6
  265. package/docs/types/duration.DurationStyle.html +0 -6
  266. package/docs/types/duration.DurationSuffixMap.html +0 -6
  267. package/docs/types/duration.DurationSuffixType.html +0 -1
  268. package/docs/types/duration.DurationType.html +0 -2
  269. package/docs/types/localStorageCache.StoredItem.html +0 -4
  270. package/docs/variables/duration.DURATION_STYLE_SUFFIX_MAP.html +0 -1
  271. package/docs/variables/duration.DURATION_TYPE_SEQUENCE.html +0 -2
  272. package/docs/variables/kvStore.DEFAULT_EXPIRY_DELTA_MS.html +0 -2
  273. package/docs/variables/kvStore.GC_INTERVAL_MS.html +0 -2
  274. package/docs/variables/kvStore.MILLIS_PER_DAY.html +0 -2
  275. package/docs/variables/kvStore.kvStore.html +0 -3
  276. package/docs/variables/timeConstants.HOURS_PER_DAY.html +0 -1
  277. package/docs/variables/timeConstants.HOURS_PER_WEEK.html +0 -1
  278. package/docs/variables/timeConstants.MINUTES_PER_DAY.html +0 -1
  279. package/docs/variables/timeConstants.MINUTES_PER_HOUR.html +0 -1
  280. package/docs/variables/timeConstants.MINUTES_PER_WEEK.html +0 -1
  281. package/docs/variables/timeConstants.MS_PER_DAY.html +0 -1
  282. package/docs/variables/timeConstants.MS_PER_HOUR.html +0 -1
  283. package/docs/variables/timeConstants.MS_PER_MINUTE.html +0 -1
  284. package/docs/variables/timeConstants.MS_PER_SECOND.html +0 -3
  285. package/docs/variables/timeConstants.MS_PER_WEEK.html +0 -1
  286. package/docs/variables/timeConstants.SECONDS_PER_DAY.html +0 -1
  287. package/docs/variables/timeConstants.SECONDS_PER_HOUR.html +0 -1
  288. package/docs/variables/timeConstants.SECONDS_PER_MINUTE.html +0 -1
  289. package/docs/variables/timeConstants.SECONDS_PER_WEEK.html +0 -1
  290. package/duration.js.map +0 -1
  291. package/kvStore.js +0 -383
  292. package/kvStore.js.map +0 -1
  293. package/localStorageCache.d.ts +0 -55
  294. package/localStorageCache.js +0 -121
  295. package/localStorageCache.js.map +0 -1
  296. package/sha256.js +0 -58
  297. package/src/arrayBuffer.ts +0 -29
  298. package/src/assert.ts +0 -14
  299. package/src/average.ts +0 -13
  300. package/src/base64Url.ts +0 -20
  301. package/src/dateTimeStr.ts +0 -184
  302. package/src/duration.ts +0 -260
  303. package/src/isEmpty.ts +0 -32
  304. package/src/kvStore.ts +0 -444
  305. package/src/localStorageCache.ts +0 -121
  306. package/src/logging.ts +0 -26
  307. package/src/nonEmpty.ts +0 -18
  308. package/src/safeBtoa.ts +0 -15
  309. package/src/safeParseFloat.ts +0 -10
  310. package/src/safeParseInt.ts +0 -10
  311. package/src/sha256.ts +0 -13
  312. package/src/sum.ts +0 -17
  313. package/src/timeConstants.ts +0 -22
  314. package/src/timer.ts +0 -33
  315. package/timer.js.map +0 -1
package/iterators.mjs ADDED
@@ -0,0 +1,9 @@
1
+ // src/iterators.ts
2
+ function* concatIterators(...iterators) {
3
+ for (const iterator of iterators) {
4
+ yield* iterator;
5
+ }
6
+ }
7
+ export {
8
+ concatIterators
9
+ };
package/kvStore.cjs ADDED
@@ -0,0 +1,365 @@
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);
19
+
20
+ // src/kvStore.ts
21
+ var kvStore_exports = {};
22
+ __export(kvStore_exports, {
23
+ KvStore: () => KvStore,
24
+ KvStoreConfig: () => KvStoreConfig,
25
+ KvStoreItem: () => KvStoreItem,
26
+ configureKvStore: () => configureKvStore,
27
+ kvStore: () => kvStore,
28
+ kvStoreItem: () => kvStoreItem
29
+ });
30
+ module.exports = __toCommonJS(kvStore_exports);
31
+
32
+ // src/timeConstants.ts
33
+ var MS_PER_SECOND = 1e3;
34
+ var MS_PER_MINUTE = 6e4;
35
+ var MS_PER_HOUR = 36e5;
36
+ var MS_PER_DAY = 864e5;
37
+
38
+ // src/duration.ts
39
+ function durationToMs(duration) {
40
+ const daysMs = (duration.days ?? 0) * MS_PER_DAY;
41
+ const hoursMs = (duration.hours ?? 0) * MS_PER_HOUR;
42
+ const minsMs = (duration.minutes ?? 0) * MS_PER_MINUTE;
43
+ const secsMs = (duration.seconds ?? 0) * MS_PER_SECOND;
44
+ const msMs = duration.milliseconds ?? 0;
45
+ return daysMs + hoursMs + minsMs + secsMs + msMs;
46
+ }
47
+ function durationOrMsToMs(duration) {
48
+ return typeof duration === "number" ? duration : durationToMs(duration);
49
+ }
50
+
51
+ // src/kvStore.ts
52
+ var KvStoreConfig = {
53
+ /**
54
+ * Name of the DB in the indexed DB.
55
+ * Updating the DB name will cause all old entries to be gone.
56
+ */
57
+ dbName: "KVStore",
58
+ /**
59
+ * Version of the DB schema. Most likely you will never want to change this.
60
+ * Updating the version will cause all old entries to be gone.
61
+ */
62
+ dbVersion: 1,
63
+ /**
64
+ * Name of the store within the indexed DB. Each DB can have multiple stores.
65
+ * In practice, it doesn't matter what you name this to be.
66
+ */
67
+ storeName: "kvStore",
68
+ /** 30 days in ms. */
69
+ expiryMs: MS_PER_DAY * 30,
70
+ /** Do GC once per day. */
71
+ gcIntervalMs: MS_PER_DAY
72
+ };
73
+ function configureKvStore(config) {
74
+ Object.assign(KvStoreConfig, config);
75
+ }
76
+ function validateStoredObject(obj) {
77
+ 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) {
78
+ return void 0;
79
+ }
80
+ return obj;
81
+ }
82
+ function withOnError(request, reject) {
83
+ request.onerror = (event) => {
84
+ reject(event);
85
+ };
86
+ return request;
87
+ }
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
+ );
112
+ request.onupgradeneeded = (event) => {
113
+ const db = event.target.result;
114
+ const objectStore = db.createObjectStore(this.storeName, {
115
+ keyPath: "key"
116
+ });
117
+ objectStore.createIndex("key", "key", {
118
+ unique: true
119
+ });
120
+ };
121
+ request.onsuccess = (event) => {
122
+ const db = event.target.result;
123
+ resolve(db);
124
+ };
125
+ });
126
+ }
127
+ return this.db;
128
+ }
129
+ async transact(mode, callback) {
130
+ const db = await this.getOrCreateDb();
131
+ return await new Promise((resolve, reject) => {
132
+ const transaction = withOnError(
133
+ db.transaction(this.storeName, mode),
134
+ reject
135
+ );
136
+ transaction.onabort = (event) => {
137
+ reject(event);
138
+ };
139
+ const objectStore = transaction.objectStore(this.storeName);
140
+ callback(objectStore, resolve, reject);
141
+ });
142
+ }
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);
156
+ request.onsuccess = () => {
157
+ 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();
170
+ };
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);
176
+ }
177
+ }
178
+ }
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();
200
+ return void 0;
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
+ );
231
+ }
232
+ }
233
+ cursor.continue();
234
+ } else {
235
+ resolve();
236
+ }
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
+ const keys = [];
255
+ await this.forEach((key) => {
256
+ keys.push(key);
257
+ });
258
+ await this.delete(keys);
259
+ }
260
+ /**
261
+ * Returns all items as map of key to value, mainly used for debugging dumps.
262
+ * The type T is applied to all values, even though they might not be of type
263
+ * T (in the case when you store different data types in the same store).
264
+ */
265
+ async asMap() {
266
+ const map = /* @__PURE__ */ new Map();
267
+ await this.forEach((key, value, expiryMs, storedMs) => {
268
+ map.set(key, { value, expiryMs, storedMs });
269
+ });
270
+ return map;
271
+ }
272
+ /** Returns the ms timestamp for the last GC (garbage collection). */
273
+ get lastGcMs() {
274
+ const lastGcMsStr = globalThis.localStorage.getItem(this.gcMsStorageKey);
275
+ if (!lastGcMsStr) return 0;
276
+ const ms = Number(lastGcMsStr);
277
+ return isNaN(ms) ? 0 : ms;
278
+ }
279
+ /** Set the ms timestamp for the last GC (garbage collection). */
280
+ set lastGcMs(ms) {
281
+ globalThis.localStorage.setItem(this.gcMsStorageKey, String(ms));
282
+ }
283
+ /** Perform garbage-collection if due, else do nothing. */
284
+ async gc() {
285
+ const lastGcMs = this.lastGcMs;
286
+ if (!lastGcMs) {
287
+ this.lastGcMs = Date.now();
288
+ return;
289
+ }
290
+ if (Date.now() < lastGcMs + this.gcIntervalMs) {
291
+ return;
292
+ }
293
+ await this.gcNow();
294
+ }
295
+ /**
296
+ * Perform garbage collection immediately without checking whether we are
297
+ * due for the next GC or not.
298
+ */
299
+ async gcNow() {
300
+ console.log(`Starting kvStore GC on ${this.dbName} v${this.dbVersion}...`);
301
+ this.lastGcMs = Date.now();
302
+ const keysToDelete = [];
303
+ await this.forEach(
304
+ async (key, value, expiryMs) => {
305
+ if (value === void 0 || Date.now() >= expiryMs) {
306
+ keysToDelete.push(key);
307
+ }
308
+ }
309
+ );
310
+ if (keysToDelete.length) {
311
+ await this.delete(keysToDelete);
312
+ }
313
+ console.log(
314
+ `Finished kvStore GC on ${this.dbName} v${this.dbVersion} - deleted ${keysToDelete.length} keys`
315
+ );
316
+ this.lastGcMs = Date.now();
317
+ }
318
+ /** Returns `this` casted into a StorageAdapter<T>. */
319
+ asStorageAdapter() {
320
+ return this;
321
+ }
322
+ };
323
+ var kvStore = new KvStore(KvStoreConfig.dbName);
324
+ var KvStoreItem = class {
325
+ constructor(key, defaultExpiryMs = KvStoreConfig.expiryMs, store = kvStore) {
326
+ this.key = key;
327
+ this.store = store;
328
+ this.defaultExpiryMs = defaultExpiryMs && durationOrMsToMs(defaultExpiryMs);
329
+ }
330
+ defaultExpiryMs;
331
+ /** Set a value in the store. */
332
+ async set(value, expiryDeltaMs = this.defaultExpiryMs) {
333
+ await this.store.set(this.key, value, expiryDeltaMs);
334
+ }
335
+ /**
336
+ * Example usage:
337
+ *
338
+ * const { value, storedMs, expiryMs, storedMs } =
339
+ * await myKvItem.getStoredObject();
340
+ */
341
+ async getStoredObject() {
342
+ return await this.store.getStoredObject(this.key);
343
+ }
344
+ /** Get a value by key, or undefined if it does not exist. */
345
+ async get() {
346
+ return await this.store.get(this.key);
347
+ }
348
+ /** Delete this key from the store. */
349
+ async delete() {
350
+ await this.store.delete(this.key);
351
+ }
352
+ };
353
+ function kvStoreItem(key, expiryMs, store = kvStore) {
354
+ expiryMs = expiryMs && durationOrMsToMs(expiryMs);
355
+ return new KvStoreItem(key, expiryMs, store);
356
+ }
357
+ // Annotate the CommonJS export names for ESM import in node:
358
+ 0 && (module.exports = {
359
+ KvStore,
360
+ KvStoreConfig,
361
+ KvStoreItem,
362
+ configureKvStore,
363
+ kvStore,
364
+ kvStoreItem
365
+ });
package/kvStore.d.mts ADDED
@@ -0,0 +1,139 @@
1
+ import { Duration } from './duration.mjs';
2
+ import { StoredObject, FullStorageAdapter, StorageAdapter } from './storageAdapter.mjs';
3
+
4
+ /**
5
+ * Indexed DB key-value store with support for auto-expirations.
6
+ *
7
+ * Why use this?
8
+ * 1. Extremely simple interface to use indexed DBs.
9
+ * 2. Auto-expirations with GC frees you from worrying about data clean-up.
10
+ * 3. Any serializable data type can be stored (except undefined).
11
+ *
12
+ * How to use?
13
+ * Just use the `kvStore` global constant like the local storage, but with
14
+ * async interface functions as required by indexed DB.
15
+ *
16
+ * Why not use the indexed DB directly?
17
+ * It will require you to write a lot of code to reinvent the wheel.
18
+ */
19
+
20
+ /** Global defaults can be updated directly. */
21
+ declare const 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: string;
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: number;
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: string;
37
+ /** 30 days in ms. */
38
+ expiryMs: number;
39
+ /** Do GC once per day. */
40
+ gcIntervalMs: number;
41
+ };
42
+ type KvStoreConfig = typeof KvStoreConfig;
43
+ /** Convenience function to update global defaults. */
44
+ declare function configureKvStore(config: Partial<KvStoreConfig>): void;
45
+ /** Type to represent a full object with metadata stored in the store. */
46
+ type KvStoredObject<T> = StoredObject<T> & {
47
+ key: string;
48
+ };
49
+ /**
50
+ * You can create multiple KvStores if you want, but most likely you will only
51
+ * need to use the default `kvStore` instance.
52
+ */
53
+ declare class KvStore implements FullStorageAdapter<any> {
54
+ readonly dbName: string;
55
+ /** We'll init the DB only on first use. */
56
+ private db;
57
+ /** Local storage key name for the last GC completed timestamp. */
58
+ readonly gcMsStorageKey: string;
59
+ readonly dbVersion: number;
60
+ readonly storeName: string;
61
+ readonly defaultExpiryMs: number;
62
+ readonly gcIntervalMs: number;
63
+ constructor(dbName: string, options?: {
64
+ dbVersion?: number;
65
+ storeName?: string;
66
+ defaultExpiryMs?: number | Duration;
67
+ gcIntervalMs?: number | Duration;
68
+ });
69
+ private getOrCreateDb;
70
+ private transact;
71
+ /** Set a value in the store. */
72
+ set<T>(key: string, value: T, expiryDeltaMs?: number | Duration): Promise<T>;
73
+ /** Delete one or multiple keys. */
74
+ delete(key: string | string[]): Promise<void>;
75
+ /** Mainly used to get the expiration timestamp of an object. */
76
+ getStoredObject<T>(key: string): Promise<KvStoredObject<T> | undefined>;
77
+ /** Get a value by key, or undefined if it does not exist. */
78
+ get<T>(key: string): Promise<T | undefined>;
79
+ /** Generic way to iterate through all entries. */
80
+ forEach<T>(callback: (key: string, value: T, expiryMs: number, storedMs: number) => void | Promise<void>): Promise<void>;
81
+ /**
82
+ * Returns the number of items in the store. Note that getting the size
83
+ * requires iterating through the entire store because the items could expire
84
+ * at any time, and hence the size is a dynamic number.
85
+ */
86
+ size(): Promise<number>;
87
+ /** Remove all items from the store. */
88
+ clear(): Promise<void>;
89
+ /**
90
+ * Returns all items as map of key to value, mainly used for debugging dumps.
91
+ * The type T is applied to all values, even though they might not be of type
92
+ * T (in the case when you store different data types in the same store).
93
+ */
94
+ asMap<T>(): Promise<Map<string, StoredObject<T>>>;
95
+ /** Returns the ms timestamp for the last GC (garbage collection). */
96
+ get lastGcMs(): number;
97
+ /** Set the ms timestamp for the last GC (garbage collection). */
98
+ set lastGcMs(ms: number);
99
+ /** Perform garbage-collection if due, else do nothing. */
100
+ gc(): Promise<void>;
101
+ /**
102
+ * Perform garbage collection immediately without checking whether we are
103
+ * due for the next GC or not.
104
+ */
105
+ gcNow(): Promise<void>;
106
+ /** Returns `this` casted into a StorageAdapter<T>. */
107
+ asStorageAdapter<T>(): StorageAdapter<T>;
108
+ }
109
+ /**
110
+ * Default KV store ready for immediate use. You can create new instances if
111
+ * you want, but most likely you will only need one store instance.
112
+ */
113
+ declare const kvStore: KvStore;
114
+ /**
115
+ * Class to represent one key in the store with a default expiration.
116
+ */
117
+ declare class KvStoreItem<T> {
118
+ readonly key: string;
119
+ readonly store: KvStore;
120
+ readonly defaultExpiryMs: number;
121
+ constructor(key: string, defaultExpiryMs?: number | Duration, store?: KvStore);
122
+ /** Set a value in the store. */
123
+ set(value: T, expiryDeltaMs?: number | undefined): Promise<void>;
124
+ /**
125
+ * Example usage:
126
+ *
127
+ * const { value, storedMs, expiryMs, storedMs } =
128
+ * await myKvItem.getStoredObject();
129
+ */
130
+ getStoredObject(): Promise<KvStoredObject<T> | undefined>;
131
+ /** Get a value by key, or undefined if it does not exist. */
132
+ get(): Promise<T | undefined>;
133
+ /** Delete this key from the store. */
134
+ delete(): Promise<void>;
135
+ }
136
+ /** Create a KV store item with a key and a default expiration. */
137
+ declare function kvStoreItem<T>(key: string, expiryMs?: number | Duration, store?: KvStore): KvStoreItem<T>;
138
+
139
+ export { KvStore, KvStoreConfig, KvStoreItem, type KvStoredObject, configureKvStore, kvStore, kvStoreItem };