@ls-stack/utils 2.12.0 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cache.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var cache_exports = {};
22
22
  __export(cache_exports, {
23
23
  RejectValue: () => RejectValue,
24
+ WithExpiration: () => WithExpiration,
24
25
  cachedGetter: () => cachedGetter,
25
26
  createCache: () => createCache
26
27
  });
@@ -34,6 +35,22 @@ function isPromise(value) {
34
35
  return isObject(value) && "then" in value;
35
36
  }
36
37
 
38
+ // src/time.ts
39
+ var MINUTE_AS_MS = 60 * 1e3;
40
+ var HOUR_AS_MS = 60 * MINUTE_AS_MS;
41
+ var DAY_AS_MS = 24 * HOUR_AS_MS;
42
+ var WEEK_AS_MS = 7 * DAY_AS_MS;
43
+ var MONTH_AS_MS = 30 * DAY_AS_MS;
44
+ var YEAR_AS_MS = 365 * DAY_AS_MS;
45
+ var HOUR_AS_SECS = 60 * 60;
46
+ var DAY_AS_SECS = 24 * HOUR_AS_SECS;
47
+ var WEEK_AS_SECS = 7 * DAY_AS_SECS;
48
+ var MONTH_AS_SECS = 30 * DAY_AS_SECS;
49
+ var YEAR_AS_SECS = 365 * DAY_AS_SECS;
50
+ function durationObjToMs(durationObj) {
51
+ return (durationObj.hours ?? 0) * HOUR_AS_MS + (durationObj.minutes ?? 0) * MINUTE_AS_MS + (durationObj.seconds ?? 0) * 1e3 + (durationObj.ms ?? 0) + (durationObj.days ?? 0) * DAY_AS_MS;
52
+ }
53
+
37
54
  // src/cache.ts
38
55
  function cachedGetter(getter) {
39
56
  return {
@@ -50,6 +67,18 @@ var RejectValue = class {
50
67
  this.value = value;
51
68
  }
52
69
  };
70
+ var WithExpiration = class {
71
+ value;
72
+ expiration;
73
+ /**
74
+ * @param value - The value to store in the cache.
75
+ * @param expiration - The expiration time of the value in seconds or a duration object.
76
+ */
77
+ constructor(value, expiration) {
78
+ this.value = value;
79
+ this.expiration = durationObjToMs(expiration);
80
+ }
81
+ };
53
82
  function createCache({
54
83
  maxCacheSize = 1e3,
55
84
  maxItemAge,
@@ -57,13 +86,14 @@ function createCache({
57
86
  } = {}) {
58
87
  const cache = /* @__PURE__ */ new Map();
59
88
  let lastExpirationCheck = 0;
89
+ const defaultMaxItemAgeMs = maxItemAge && durationObjToMs(maxItemAge);
60
90
  function cleanExpiredItems() {
61
91
  const now = Date.now();
62
- if (!maxItemAge || now - lastExpirationCheck < expirationThrottle) return;
92
+ if (!defaultMaxItemAgeMs || now - lastExpirationCheck < expirationThrottle)
93
+ return;
63
94
  lastExpirationCheck = now;
64
- const maxAgeMs = maxItemAge * 1e3;
65
95
  for (const [key, item] of cache.entries()) {
66
- if (now - item.timestamp > maxAgeMs) {
96
+ if (isExpired(item, now)) {
67
97
  cache.delete(key);
68
98
  }
69
99
  }
@@ -81,25 +111,43 @@ function createCache({
81
111
  }
82
112
  }
83
113
  }
84
- function isExpired(timestamp, now) {
85
- return maxItemAge !== void 0 && now - timestamp > maxItemAge * 1e3;
114
+ function isExpired(entry, now) {
115
+ const maxItemAgeMs = entry.expiration ?? defaultMaxItemAgeMs;
116
+ return !!maxItemAgeMs && now - entry.timestamp > maxItemAgeMs;
117
+ }
118
+ function unwrapValue(value, now) {
119
+ if (value instanceof WithExpiration) {
120
+ return {
121
+ value: value.value,
122
+ timestamp: now,
123
+ expiration: value.expiration ? typeof value.expiration === "number" ? value.expiration : now + durationObjToMs(value.expiration) : void 0
124
+ };
125
+ }
126
+ return { value, timestamp: now, expiration: void 0 };
86
127
  }
87
128
  const utils = {
88
- reject: (value) => new RejectValue(value)
129
+ reject: (value) => new RejectValue(value),
130
+ withExpiration: (value, expiration) => {
131
+ return new WithExpiration(value, expiration);
132
+ }
89
133
  };
90
134
  return {
91
- getOrInsert(cacheKey, val) {
135
+ getOrInsert(cacheKey, val, options) {
92
136
  const now = Date.now();
93
137
  const entry = cache.get(cacheKey);
94
- if (!entry || isExpired(entry.timestamp, now)) {
138
+ if (!entry || isExpired(entry, now)) {
95
139
  const value = val(utils);
96
140
  if (value instanceof RejectValue) {
97
141
  return value.value;
98
142
  }
99
- cache.set(cacheKey, { value, timestamp: now });
143
+ if (options?.rejectWhen?.(value)) {
144
+ return value;
145
+ }
146
+ const unwrappedValue = unwrapValue(value, now);
147
+ cache.set(cacheKey, unwrappedValue);
100
148
  trimToSize();
101
149
  cleanExpiredItems();
102
- return value;
150
+ return unwrappedValue.value;
103
151
  }
104
152
  if (isPromise(entry.value)) {
105
153
  throw new Error(
@@ -108,13 +156,13 @@ function createCache({
108
156
  }
109
157
  return entry.value;
110
158
  },
111
- async getOrInsertAsync(cacheKey, val) {
159
+ async getOrInsertAsync(cacheKey, val, options) {
112
160
  const entry = cache.get(cacheKey);
113
161
  if (entry && isPromise(entry.value)) {
114
162
  return entry.value;
115
163
  }
116
164
  const now = Date.now();
117
- if (entry && !isExpired(entry.timestamp, now)) {
165
+ if (entry && !isExpired(entry, now)) {
118
166
  return entry.value;
119
167
  }
120
168
  const promise = val(utils).then((result) => {
@@ -125,13 +173,25 @@ function createCache({
125
173
  }
126
174
  return result.value;
127
175
  }
128
- cache.set(cacheKey, { value: result, timestamp: Date.now() });
129
- return result;
176
+ if (options?.rejectWhen?.(result)) {
177
+ const cacheValue = cache.get(cacheKey);
178
+ if (cacheValue?.value === promise) {
179
+ cache.delete(cacheKey);
180
+ }
181
+ return result;
182
+ }
183
+ const unwrappedValue = unwrapValue(result, Date.now());
184
+ cache.set(cacheKey, unwrappedValue);
185
+ return unwrappedValue.value;
130
186
  }).catch((error) => {
131
187
  cache.delete(cacheKey);
132
188
  throw error;
133
189
  });
134
- cache.set(cacheKey, { value: promise, timestamp: now });
190
+ cache.set(cacheKey, {
191
+ value: promise,
192
+ timestamp: now,
193
+ expiration: void 0
194
+ });
135
195
  trimToSize();
136
196
  cleanExpiredItems();
137
197
  return promise;
@@ -141,7 +201,7 @@ function createCache({
141
201
  },
142
202
  get(cacheKey) {
143
203
  const entry = cache.get(cacheKey);
144
- if (!entry || isExpired(entry.timestamp, Date.now())) {
204
+ if (!entry || isExpired(entry, Date.now())) {
145
205
  return void 0;
146
206
  }
147
207
  if (isPromise(entry.value)) {
@@ -150,28 +210,41 @@ function createCache({
150
210
  return entry.value;
151
211
  },
152
212
  set(cacheKey, value) {
153
- cache.set(cacheKey, { value, timestamp: Date.now() });
213
+ cache.set(cacheKey, unwrapValue(value, Date.now()));
154
214
  trimToSize();
155
215
  cleanExpiredItems();
156
216
  },
157
217
  async getAsync(cacheKey) {
158
218
  const entry = cache.get(cacheKey);
159
- if (!entry || isExpired(entry.timestamp, Date.now())) {
219
+ if (!entry || isExpired(entry, Date.now())) {
160
220
  return void 0;
161
221
  }
162
- return await entry.value;
222
+ return entry.value;
163
223
  },
164
- setAsync(cacheKey, value) {
165
- const promise = value().then((result) => {
166
- cache.set(cacheKey, { value: result, timestamp: Date.now() });
167
- return result;
224
+ async setAsync(cacheKey, value) {
225
+ const promise = value(utils).then((result) => {
226
+ if (result instanceof RejectValue) {
227
+ const cacheValue = cache.get(cacheKey);
228
+ if (cacheValue?.value === promise) {
229
+ cache.delete(cacheKey);
230
+ }
231
+ return result.value;
232
+ }
233
+ const unwrappedValue = unwrapValue(result, Date.now());
234
+ cache.set(cacheKey, unwrappedValue);
235
+ return unwrappedValue.value;
168
236
  }).catch((error) => {
169
237
  cache.delete(cacheKey);
170
238
  throw error;
171
239
  });
172
- cache.set(cacheKey, { value: promise, timestamp: Date.now() });
240
+ cache.set(cacheKey, {
241
+ value: promise,
242
+ timestamp: Date.now(),
243
+ expiration: void 0
244
+ });
173
245
  trimToSize();
174
246
  cleanExpiredItems();
247
+ return promise;
175
248
  },
176
249
  cleanExpiredItems,
177
250
  /** @internal */
@@ -181,6 +254,7 @@ function createCache({
181
254
  // Annotate the CommonJS export names for ESM import in node:
182
255
  0 && (module.exports = {
183
256
  RejectValue,
257
+ WithExpiration,
184
258
  cachedGetter,
185
259
  createCache
186
260
  });
package/dist/cache.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import { DurationObj } from './time.cjs';
2
+
1
3
  declare function cachedGetter<T>(getter: () => T): {
2
4
  value: T;
3
5
  };
@@ -8,9 +10,9 @@ type Options = {
8
10
  */
9
11
  maxCacheSize?: number;
10
12
  /**
11
- * The maximum age of items in the cache in seconds.
13
+ * The maximum age of items in the cache.
12
14
  */
13
- maxItemAge?: number;
15
+ maxItemAge?: DurationObj;
14
16
  /**
15
17
  * The throttle for checking expired items in milliseconds.
16
18
  * @default
@@ -22,19 +24,42 @@ declare class RejectValue<T> {
22
24
  value: T;
23
25
  constructor(value: T);
24
26
  }
27
+ declare class WithExpiration<T> {
28
+ value: T;
29
+ expiration: number;
30
+ /**
31
+ * @param value - The value to store in the cache.
32
+ * @param expiration - The expiration time of the value in seconds or a duration object.
33
+ */
34
+ constructor(value: T, expiration: DurationObj);
35
+ }
36
+ type Utils<T> = {
37
+ reject: (value: T) => RejectValue<T>;
38
+ /**
39
+ * Create a new WithExpiration object with the given value and expiration time.
40
+ * @param value - The value to store in the cache.
41
+ * @param expiration - The expiration time of the value in seconds or a duration object.
42
+ */
43
+ withExpiration: (value: T, expiration: DurationObj) => WithExpiration<T>;
44
+ };
45
+ type GetOptions<T> = {
46
+ /**
47
+ * A function that determines whether a value should be rejected from being cached.
48
+ * If the function returns true, the value will be returned but not cached.
49
+ * @param value The value to check
50
+ * @returns true if the value should be rejected, false otherwise
51
+ */
52
+ rejectWhen?: (value: T) => boolean;
53
+ };
25
54
  type Cache<T> = {
26
- getOrInsert: (cacheKey: string, val: (utils: {
27
- reject: (value: T) => RejectValue<T>;
28
- }) => T | RejectValue<T>) => T;
29
- getOrInsertAsync: (cacheKey: string, val: (utils: {
30
- reject: (value: T) => RejectValue<T>;
31
- }) => Promise<T | RejectValue<T>>) => Promise<T>;
55
+ getOrInsert: (cacheKey: string, val: (utils: Utils<T>) => T | RejectValue<T>, options?: GetOptions<T>) => T;
56
+ getOrInsertAsync: (cacheKey: string, val: (utils: Utils<T>) => Promise<T | RejectValue<T>>, options?: GetOptions<T>) => Promise<T>;
32
57
  clear: () => void;
33
58
  get: (cacheKey: string) => T | undefined;
34
- set: (cacheKey: string, value: T) => void;
59
+ set: (cacheKey: string, value: T | WithExpiration<T>) => void;
35
60
  cleanExpiredItems: () => void;
36
61
  getAsync: (cacheKey: string) => Promise<T | undefined>;
37
- setAsync: (cacheKey: string, value: () => Promise<T>) => void;
62
+ setAsync: (cacheKey: string, value: (utils: Utils<T>) => Promise<T | WithExpiration<T>>) => Promise<T>;
38
63
  [' cache']: {
39
64
  map: Map<string, {
40
65
  value: T | Promise<T>;
@@ -44,4 +69,4 @@ type Cache<T> = {
44
69
  };
45
70
  declare function createCache<T>({ maxCacheSize, maxItemAge, expirationThrottle, }?: Options): Cache<T>;
46
71
 
47
- export { type Cache, RejectValue, cachedGetter, createCache };
72
+ export { type Cache, RejectValue, WithExpiration, cachedGetter, createCache };
package/dist/cache.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { DurationObj } from './time.js';
2
+
1
3
  declare function cachedGetter<T>(getter: () => T): {
2
4
  value: T;
3
5
  };
@@ -8,9 +10,9 @@ type Options = {
8
10
  */
9
11
  maxCacheSize?: number;
10
12
  /**
11
- * The maximum age of items in the cache in seconds.
13
+ * The maximum age of items in the cache.
12
14
  */
13
- maxItemAge?: number;
15
+ maxItemAge?: DurationObj;
14
16
  /**
15
17
  * The throttle for checking expired items in milliseconds.
16
18
  * @default
@@ -22,19 +24,42 @@ declare class RejectValue<T> {
22
24
  value: T;
23
25
  constructor(value: T);
24
26
  }
27
+ declare class WithExpiration<T> {
28
+ value: T;
29
+ expiration: number;
30
+ /**
31
+ * @param value - The value to store in the cache.
32
+ * @param expiration - The expiration time of the value in seconds or a duration object.
33
+ */
34
+ constructor(value: T, expiration: DurationObj);
35
+ }
36
+ type Utils<T> = {
37
+ reject: (value: T) => RejectValue<T>;
38
+ /**
39
+ * Create a new WithExpiration object with the given value and expiration time.
40
+ * @param value - The value to store in the cache.
41
+ * @param expiration - The expiration time of the value in seconds or a duration object.
42
+ */
43
+ withExpiration: (value: T, expiration: DurationObj) => WithExpiration<T>;
44
+ };
45
+ type GetOptions<T> = {
46
+ /**
47
+ * A function that determines whether a value should be rejected from being cached.
48
+ * If the function returns true, the value will be returned but not cached.
49
+ * @param value The value to check
50
+ * @returns true if the value should be rejected, false otherwise
51
+ */
52
+ rejectWhen?: (value: T) => boolean;
53
+ };
25
54
  type Cache<T> = {
26
- getOrInsert: (cacheKey: string, val: (utils: {
27
- reject: (value: T) => RejectValue<T>;
28
- }) => T | RejectValue<T>) => T;
29
- getOrInsertAsync: (cacheKey: string, val: (utils: {
30
- reject: (value: T) => RejectValue<T>;
31
- }) => Promise<T | RejectValue<T>>) => Promise<T>;
55
+ getOrInsert: (cacheKey: string, val: (utils: Utils<T>) => T | RejectValue<T>, options?: GetOptions<T>) => T;
56
+ getOrInsertAsync: (cacheKey: string, val: (utils: Utils<T>) => Promise<T | RejectValue<T>>, options?: GetOptions<T>) => Promise<T>;
32
57
  clear: () => void;
33
58
  get: (cacheKey: string) => T | undefined;
34
- set: (cacheKey: string, value: T) => void;
59
+ set: (cacheKey: string, value: T | WithExpiration<T>) => void;
35
60
  cleanExpiredItems: () => void;
36
61
  getAsync: (cacheKey: string) => Promise<T | undefined>;
37
- setAsync: (cacheKey: string, value: () => Promise<T>) => void;
62
+ setAsync: (cacheKey: string, value: (utils: Utils<T>) => Promise<T | WithExpiration<T>>) => Promise<T>;
38
63
  [' cache']: {
39
64
  map: Map<string, {
40
65
  value: T | Promise<T>;
@@ -44,4 +69,4 @@ type Cache<T> = {
44
69
  };
45
70
  declare function createCache<T>({ maxCacheSize, maxItemAge, expirationThrottle, }?: Options): Cache<T>;
46
71
 
47
- export { type Cache, RejectValue, cachedGetter, createCache };
72
+ export { type Cache, RejectValue, WithExpiration, cachedGetter, createCache };
package/dist/cache.js CHANGED
@@ -1,6 +1,11 @@
1
+ import {
2
+ durationObjToMs
3
+ } from "./chunk-RK6PT7JY.js";
4
+ import "./chunk-HTCYUMDR.js";
1
5
  import {
2
6
  isPromise
3
7
  } from "./chunk-4UGSP3L3.js";
8
+ import "./chunk-GBFS2I67.js";
4
9
 
5
10
  // src/cache.ts
6
11
  function cachedGetter(getter) {
@@ -18,6 +23,18 @@ var RejectValue = class {
18
23
  this.value = value;
19
24
  }
20
25
  };
26
+ var WithExpiration = class {
27
+ value;
28
+ expiration;
29
+ /**
30
+ * @param value - The value to store in the cache.
31
+ * @param expiration - The expiration time of the value in seconds or a duration object.
32
+ */
33
+ constructor(value, expiration) {
34
+ this.value = value;
35
+ this.expiration = durationObjToMs(expiration);
36
+ }
37
+ };
21
38
  function createCache({
22
39
  maxCacheSize = 1e3,
23
40
  maxItemAge,
@@ -25,13 +42,14 @@ function createCache({
25
42
  } = {}) {
26
43
  const cache = /* @__PURE__ */ new Map();
27
44
  let lastExpirationCheck = 0;
45
+ const defaultMaxItemAgeMs = maxItemAge && durationObjToMs(maxItemAge);
28
46
  function cleanExpiredItems() {
29
47
  const now = Date.now();
30
- if (!maxItemAge || now - lastExpirationCheck < expirationThrottle) return;
48
+ if (!defaultMaxItemAgeMs || now - lastExpirationCheck < expirationThrottle)
49
+ return;
31
50
  lastExpirationCheck = now;
32
- const maxAgeMs = maxItemAge * 1e3;
33
51
  for (const [key, item] of cache.entries()) {
34
- if (now - item.timestamp > maxAgeMs) {
52
+ if (isExpired(item, now)) {
35
53
  cache.delete(key);
36
54
  }
37
55
  }
@@ -49,25 +67,43 @@ function createCache({
49
67
  }
50
68
  }
51
69
  }
52
- function isExpired(timestamp, now) {
53
- return maxItemAge !== void 0 && now - timestamp > maxItemAge * 1e3;
70
+ function isExpired(entry, now) {
71
+ const maxItemAgeMs = entry.expiration ?? defaultMaxItemAgeMs;
72
+ return !!maxItemAgeMs && now - entry.timestamp > maxItemAgeMs;
73
+ }
74
+ function unwrapValue(value, now) {
75
+ if (value instanceof WithExpiration) {
76
+ return {
77
+ value: value.value,
78
+ timestamp: now,
79
+ expiration: value.expiration ? typeof value.expiration === "number" ? value.expiration : now + durationObjToMs(value.expiration) : void 0
80
+ };
81
+ }
82
+ return { value, timestamp: now, expiration: void 0 };
54
83
  }
55
84
  const utils = {
56
- reject: (value) => new RejectValue(value)
85
+ reject: (value) => new RejectValue(value),
86
+ withExpiration: (value, expiration) => {
87
+ return new WithExpiration(value, expiration);
88
+ }
57
89
  };
58
90
  return {
59
- getOrInsert(cacheKey, val) {
91
+ getOrInsert(cacheKey, val, options) {
60
92
  const now = Date.now();
61
93
  const entry = cache.get(cacheKey);
62
- if (!entry || isExpired(entry.timestamp, now)) {
94
+ if (!entry || isExpired(entry, now)) {
63
95
  const value = val(utils);
64
96
  if (value instanceof RejectValue) {
65
97
  return value.value;
66
98
  }
67
- cache.set(cacheKey, { value, timestamp: now });
99
+ if (options?.rejectWhen?.(value)) {
100
+ return value;
101
+ }
102
+ const unwrappedValue = unwrapValue(value, now);
103
+ cache.set(cacheKey, unwrappedValue);
68
104
  trimToSize();
69
105
  cleanExpiredItems();
70
- return value;
106
+ return unwrappedValue.value;
71
107
  }
72
108
  if (isPromise(entry.value)) {
73
109
  throw new Error(
@@ -76,13 +112,13 @@ function createCache({
76
112
  }
77
113
  return entry.value;
78
114
  },
79
- async getOrInsertAsync(cacheKey, val) {
115
+ async getOrInsertAsync(cacheKey, val, options) {
80
116
  const entry = cache.get(cacheKey);
81
117
  if (entry && isPromise(entry.value)) {
82
118
  return entry.value;
83
119
  }
84
120
  const now = Date.now();
85
- if (entry && !isExpired(entry.timestamp, now)) {
121
+ if (entry && !isExpired(entry, now)) {
86
122
  return entry.value;
87
123
  }
88
124
  const promise = val(utils).then((result) => {
@@ -93,13 +129,25 @@ function createCache({
93
129
  }
94
130
  return result.value;
95
131
  }
96
- cache.set(cacheKey, { value: result, timestamp: Date.now() });
97
- return result;
132
+ if (options?.rejectWhen?.(result)) {
133
+ const cacheValue = cache.get(cacheKey);
134
+ if (cacheValue?.value === promise) {
135
+ cache.delete(cacheKey);
136
+ }
137
+ return result;
138
+ }
139
+ const unwrappedValue = unwrapValue(result, Date.now());
140
+ cache.set(cacheKey, unwrappedValue);
141
+ return unwrappedValue.value;
98
142
  }).catch((error) => {
99
143
  cache.delete(cacheKey);
100
144
  throw error;
101
145
  });
102
- cache.set(cacheKey, { value: promise, timestamp: now });
146
+ cache.set(cacheKey, {
147
+ value: promise,
148
+ timestamp: now,
149
+ expiration: void 0
150
+ });
103
151
  trimToSize();
104
152
  cleanExpiredItems();
105
153
  return promise;
@@ -109,7 +157,7 @@ function createCache({
109
157
  },
110
158
  get(cacheKey) {
111
159
  const entry = cache.get(cacheKey);
112
- if (!entry || isExpired(entry.timestamp, Date.now())) {
160
+ if (!entry || isExpired(entry, Date.now())) {
113
161
  return void 0;
114
162
  }
115
163
  if (isPromise(entry.value)) {
@@ -118,28 +166,41 @@ function createCache({
118
166
  return entry.value;
119
167
  },
120
168
  set(cacheKey, value) {
121
- cache.set(cacheKey, { value, timestamp: Date.now() });
169
+ cache.set(cacheKey, unwrapValue(value, Date.now()));
122
170
  trimToSize();
123
171
  cleanExpiredItems();
124
172
  },
125
173
  async getAsync(cacheKey) {
126
174
  const entry = cache.get(cacheKey);
127
- if (!entry || isExpired(entry.timestamp, Date.now())) {
175
+ if (!entry || isExpired(entry, Date.now())) {
128
176
  return void 0;
129
177
  }
130
- return await entry.value;
178
+ return entry.value;
131
179
  },
132
- setAsync(cacheKey, value) {
133
- const promise = value().then((result) => {
134
- cache.set(cacheKey, { value: result, timestamp: Date.now() });
135
- return result;
180
+ async setAsync(cacheKey, value) {
181
+ const promise = value(utils).then((result) => {
182
+ if (result instanceof RejectValue) {
183
+ const cacheValue = cache.get(cacheKey);
184
+ if (cacheValue?.value === promise) {
185
+ cache.delete(cacheKey);
186
+ }
187
+ return result.value;
188
+ }
189
+ const unwrappedValue = unwrapValue(result, Date.now());
190
+ cache.set(cacheKey, unwrappedValue);
191
+ return unwrappedValue.value;
136
192
  }).catch((error) => {
137
193
  cache.delete(cacheKey);
138
194
  throw error;
139
195
  });
140
- cache.set(cacheKey, { value: promise, timestamp: Date.now() });
196
+ cache.set(cacheKey, {
197
+ value: promise,
198
+ timestamp: Date.now(),
199
+ expiration: void 0
200
+ });
141
201
  trimToSize();
142
202
  cleanExpiredItems();
203
+ return promise;
143
204
  },
144
205
  cleanExpiredItems,
145
206
  /** @internal */
@@ -148,6 +209,7 @@ function createCache({
148
209
  }
149
210
  export {
150
211
  RejectValue,
212
+ WithExpiration,
151
213
  cachedGetter,
152
214
  createCache
153
215
  };
@@ -0,0 +1,96 @@
1
+ import {
2
+ clampMax
3
+ } from "./chunk-HTCYUMDR.js";
4
+ import {
5
+ castToNumber
6
+ } from "./chunk-GBFS2I67.js";
7
+
8
+ // src/time.ts
9
+ var MINUTE_AS_MS = 60 * 1e3;
10
+ var HOUR_AS_MS = 60 * MINUTE_AS_MS;
11
+ var DAY_AS_MS = 24 * HOUR_AS_MS;
12
+ var WEEK_AS_MS = 7 * DAY_AS_MS;
13
+ var MONTH_AS_MS = 30 * DAY_AS_MS;
14
+ var YEAR_AS_MS = 365 * DAY_AS_MS;
15
+ var HOUR_AS_SECS = 60 * 60;
16
+ var DAY_AS_SECS = 24 * HOUR_AS_SECS;
17
+ var WEEK_AS_SECS = 7 * DAY_AS_SECS;
18
+ var MONTH_AS_SECS = 30 * DAY_AS_SECS;
19
+ var YEAR_AS_SECS = 365 * DAY_AS_SECS;
20
+ function dateStringOrNullToUnixMs(isoString) {
21
+ if (!isoString) return null;
22
+ const unixMs = new Date(isoString).getTime();
23
+ if (isNaN(unixMs)) return null;
24
+ return unixMs;
25
+ }
26
+ function msToTimeString(ms, format, hoursMinLength = 2) {
27
+ const { hours, minutes, seconds, milliseconds } = msToDurationObj(ms);
28
+ const hoursString = padTimeVal(hours, hoursMinLength);
29
+ const minutesString = padTimeVal(minutes);
30
+ if (format === "minutes") {
31
+ return `${hoursString}:${minutesString}`;
32
+ }
33
+ const secondsString = padTimeVal(seconds);
34
+ if (format === "seconds") {
35
+ return `${hoursString}:${minutesString}:${secondsString}`;
36
+ }
37
+ return `${hoursString}:${minutesString}:${secondsString}:${padTimeVal(
38
+ milliseconds,
39
+ 3
40
+ )}`;
41
+ }
42
+ function padTimeVal(val, maxLength = 2) {
43
+ return val.toString().padStart(maxLength, "0");
44
+ }
45
+ function parseTimeStringToMs(timeString) {
46
+ if (!timeString.trim()) return 0;
47
+ const [hours, minutes, seconds, ms] = timeString.split(":");
48
+ return getTimeStringPartToInt(hours) * HOUR_AS_MS + clampMax(getTimeStringPartToInt(minutes), 59) * MINUTE_AS_MS + clampMax(getTimeStringPartToInt(seconds), 59) * 1e3 + getTimeStringPartToInt(ms, 3);
49
+ }
50
+ function getTimeStringPartToInt(timeStringPart, length) {
51
+ if (!timeStringPart?.trim()) return 0;
52
+ let string = timeStringPart.replaceAll("_", "0");
53
+ string = string.replaceAll("-", "");
54
+ if (length) {
55
+ string = string.padEnd(length, "0");
56
+ if (string.length > length) {
57
+ string = string.slice(0, length);
58
+ }
59
+ }
60
+ const num = castToNumber(string);
61
+ if (!num) return 0;
62
+ return Math.floor(num);
63
+ }
64
+ function msToDurationObj(ms) {
65
+ return {
66
+ milliseconds: ms % 1e3,
67
+ seconds: Math.floor(ms / 1e3) % 60,
68
+ minutes: Math.floor(ms / 1e3 / 60) % 60,
69
+ hours: Math.floor(ms / 1e3 / 60 / 60)
70
+ };
71
+ }
72
+ function getUnixSeconds() {
73
+ return Math.floor(Date.now() / 1e3);
74
+ }
75
+ function durationObjToMs(durationObj) {
76
+ return (durationObj.hours ?? 0) * HOUR_AS_MS + (durationObj.minutes ?? 0) * MINUTE_AS_MS + (durationObj.seconds ?? 0) * 1e3 + (durationObj.ms ?? 0) + (durationObj.days ?? 0) * DAY_AS_MS;
77
+ }
78
+
79
+ export {
80
+ MINUTE_AS_MS,
81
+ HOUR_AS_MS,
82
+ DAY_AS_MS,
83
+ WEEK_AS_MS,
84
+ MONTH_AS_MS,
85
+ YEAR_AS_MS,
86
+ HOUR_AS_SECS,
87
+ DAY_AS_SECS,
88
+ WEEK_AS_SECS,
89
+ MONTH_AS_SECS,
90
+ YEAR_AS_SECS,
91
+ dateStringOrNullToUnixMs,
92
+ msToTimeString,
93
+ parseTimeStringToMs,
94
+ getUnixSeconds,
95
+ durationObjToMs
96
+ };
@@ -121,22 +121,29 @@ var EnhancedMap = class _EnhancedMap extends Map {
121
121
  }
122
122
  };
123
123
 
124
+ // src/time.ts
125
+ var MINUTE_AS_MS = 60 * 1e3;
126
+ var HOUR_AS_MS = 60 * MINUTE_AS_MS;
127
+ var DAY_AS_MS = 24 * HOUR_AS_MS;
128
+ var WEEK_AS_MS = 7 * DAY_AS_MS;
129
+ var MONTH_AS_MS = 30 * DAY_AS_MS;
130
+ var YEAR_AS_MS = 365 * DAY_AS_MS;
131
+ var HOUR_AS_SECS = 60 * 60;
132
+ var DAY_AS_SECS = 24 * HOUR_AS_SECS;
133
+ var WEEK_AS_SECS = 7 * DAY_AS_SECS;
134
+ var MONTH_AS_SECS = 30 * DAY_AS_SECS;
135
+ var YEAR_AS_SECS = 365 * DAY_AS_SECS;
136
+ function durationObjToMs(durationObj) {
137
+ return (durationObj.hours ?? 0) * HOUR_AS_MS + (durationObj.minutes ?? 0) * MINUTE_AS_MS + (durationObj.seconds ?? 0) * 1e3 + (durationObj.ms ?? 0) + (durationObj.days ?? 0) * DAY_AS_MS;
138
+ }
139
+
124
140
  // src/createThrottleController.ts
125
141
  function createThrottleController({
126
142
  maxCalls,
127
143
  per,
128
144
  cleanupCheckSecsInterval = 60 * 30
129
145
  }) {
130
- let msInterval = 0;
131
- if (per.ms) {
132
- msInterval = per.ms;
133
- } else if (per.seconds) {
134
- msInterval = per.seconds * 1e3;
135
- } else if (per.minutes) {
136
- msInterval = per.minutes * 1e3 * 60;
137
- } else if (per.hours) {
138
- msInterval = per.hours * 1e3 * 60 * 60;
139
- }
146
+ const msInterval = durationObjToMs(per);
140
147
  if (msInterval === 0) {
141
148
  throw new Error("Invalid interval");
142
149
  }
@@ -1,11 +1,8 @@
1
+ import { DurationObj } from './time.cjs';
2
+
1
3
  type Options = {
2
4
  maxCalls: number;
3
- per: {
4
- ms?: number;
5
- seconds?: number;
6
- minutes?: number;
7
- hours?: number;
8
- };
5
+ per: DurationObj;
9
6
  cleanupCheckSecsInterval?: number;
10
7
  };
11
8
  type ThrottleController = {
@@ -1,11 +1,8 @@
1
+ import { DurationObj } from './time.js';
2
+
1
3
  type Options = {
2
4
  maxCalls: number;
3
- per: {
4
- ms?: number;
5
- seconds?: number;
6
- minutes?: number;
7
- hours?: number;
8
- };
5
+ per: DurationObj;
9
6
  cleanupCheckSecsInterval?: number;
10
7
  };
11
8
  type ThrottleController = {
@@ -1,7 +1,12 @@
1
1
  import {
2
2
  EnhancedMap
3
3
  } from "./chunk-T5WDDPFI.js";
4
+ import {
5
+ durationObjToMs
6
+ } from "./chunk-RK6PT7JY.js";
7
+ import "./chunk-HTCYUMDR.js";
4
8
  import "./chunk-4UGSP3L3.js";
9
+ import "./chunk-GBFS2I67.js";
5
10
 
6
11
  // src/createThrottleController.ts
7
12
  function createThrottleController({
@@ -9,16 +14,7 @@ function createThrottleController({
9
14
  per,
10
15
  cleanupCheckSecsInterval = 60 * 30
11
16
  }) {
12
- let msInterval = 0;
13
- if (per.ms) {
14
- msInterval = per.ms;
15
- } else if (per.seconds) {
16
- msInterval = per.seconds * 1e3;
17
- } else if (per.minutes) {
18
- msInterval = per.minutes * 1e3 * 60;
19
- } else if (per.hours) {
20
- msInterval = per.hours * 1e3 * 60 * 60;
21
- }
17
+ const msInterval = durationObjToMs(per);
22
18
  if (msInterval === 0) {
23
19
  throw new Error("Invalid interval");
24
20
  }
package/dist/testUtils.js CHANGED
@@ -5,13 +5,13 @@ import {
5
5
  import {
6
6
  deepEqual
7
7
  } from "./chunk-JQFUKJU5.js";
8
- import {
9
- clampMin
10
- } from "./chunk-HTCYUMDR.js";
11
8
  import {
12
9
  arrayWithPrevAndIndex,
13
10
  filterAndMap
14
11
  } from "./chunk-QMFZE2VO.js";
12
+ import {
13
+ clampMin
14
+ } from "./chunk-HTCYUMDR.js";
15
15
  import {
16
16
  isObject
17
17
  } from "./chunk-4UGSP3L3.js";
package/dist/time.cjs CHANGED
@@ -32,6 +32,7 @@ __export(time_exports, {
32
32
  YEAR_AS_MS: () => YEAR_AS_MS,
33
33
  YEAR_AS_SECS: () => YEAR_AS_SECS,
34
34
  dateStringOrNullToUnixMs: () => dateStringOrNullToUnixMs,
35
+ durationObjToMs: () => durationObjToMs,
35
36
  getUnixSeconds: () => getUnixSeconds,
36
37
  msToTimeString: () => msToTimeString,
37
38
  parseTimeStringToMs: () => parseTimeStringToMs
@@ -119,6 +120,9 @@ function msToDurationObj(ms) {
119
120
  function getUnixSeconds() {
120
121
  return Math.floor(Date.now() / 1e3);
121
122
  }
123
+ function durationObjToMs(durationObj) {
124
+ return (durationObj.hours ?? 0) * HOUR_AS_MS + (durationObj.minutes ?? 0) * MINUTE_AS_MS + (durationObj.seconds ?? 0) * 1e3 + (durationObj.ms ?? 0) + (durationObj.days ?? 0) * DAY_AS_MS;
125
+ }
122
126
  // Annotate the CommonJS export names for ESM import in node:
123
127
  0 && (module.exports = {
124
128
  DAY_AS_MS,
@@ -133,6 +137,7 @@ function getUnixSeconds() {
133
137
  YEAR_AS_MS,
134
138
  YEAR_AS_SECS,
135
139
  dateStringOrNullToUnixMs,
140
+ durationObjToMs,
136
141
  getUnixSeconds,
137
142
  msToTimeString,
138
143
  parseTimeStringToMs
package/dist/time.d.cts CHANGED
@@ -13,5 +13,13 @@ declare function dateStringOrNullToUnixMs(isoString: string | null | undefined):
13
13
  declare function msToTimeString(ms: number, format: 'minutes' | 'seconds' | 'milliseconds', hoursMinLength?: number): string;
14
14
  declare function parseTimeStringToMs(timeString: string): number;
15
15
  declare function getUnixSeconds(): number;
16
+ type DurationObj = {
17
+ ms?: number;
18
+ seconds?: number;
19
+ minutes?: number;
20
+ hours?: number;
21
+ days?: number;
22
+ };
23
+ declare function durationObjToMs(durationObj: DurationObj): number;
16
24
 
17
- export { DAY_AS_MS, DAY_AS_SECS, HOUR_AS_MS, HOUR_AS_SECS, MINUTE_AS_MS, MONTH_AS_MS, MONTH_AS_SECS, WEEK_AS_MS, WEEK_AS_SECS, YEAR_AS_MS, YEAR_AS_SECS, dateStringOrNullToUnixMs, getUnixSeconds, msToTimeString, parseTimeStringToMs };
25
+ export { DAY_AS_MS, DAY_AS_SECS, type DurationObj, HOUR_AS_MS, HOUR_AS_SECS, MINUTE_AS_MS, MONTH_AS_MS, MONTH_AS_SECS, WEEK_AS_MS, WEEK_AS_SECS, YEAR_AS_MS, YEAR_AS_SECS, dateStringOrNullToUnixMs, durationObjToMs, getUnixSeconds, msToTimeString, parseTimeStringToMs };
package/dist/time.d.ts CHANGED
@@ -13,5 +13,13 @@ declare function dateStringOrNullToUnixMs(isoString: string | null | undefined):
13
13
  declare function msToTimeString(ms: number, format: 'minutes' | 'seconds' | 'milliseconds', hoursMinLength?: number): string;
14
14
  declare function parseTimeStringToMs(timeString: string): number;
15
15
  declare function getUnixSeconds(): number;
16
+ type DurationObj = {
17
+ ms?: number;
18
+ seconds?: number;
19
+ minutes?: number;
20
+ hours?: number;
21
+ days?: number;
22
+ };
23
+ declare function durationObjToMs(durationObj: DurationObj): number;
16
24
 
17
- export { DAY_AS_MS, DAY_AS_SECS, HOUR_AS_MS, HOUR_AS_SECS, MINUTE_AS_MS, MONTH_AS_MS, MONTH_AS_SECS, WEEK_AS_MS, WEEK_AS_SECS, YEAR_AS_MS, YEAR_AS_SECS, dateStringOrNullToUnixMs, getUnixSeconds, msToTimeString, parseTimeStringToMs };
25
+ export { DAY_AS_MS, DAY_AS_SECS, type DurationObj, HOUR_AS_MS, HOUR_AS_SECS, MINUTE_AS_MS, MONTH_AS_MS, MONTH_AS_SECS, WEEK_AS_MS, WEEK_AS_SECS, YEAR_AS_MS, YEAR_AS_SECS, dateStringOrNullToUnixMs, durationObjToMs, getUnixSeconds, msToTimeString, parseTimeStringToMs };
package/dist/time.js CHANGED
@@ -1,77 +1,23 @@
1
1
  import {
2
- clampMax
3
- } from "./chunk-HTCYUMDR.js";
4
- import {
5
- castToNumber
6
- } from "./chunk-GBFS2I67.js";
7
-
8
- // src/time.ts
9
- var MINUTE_AS_MS = 60 * 1e3;
10
- var HOUR_AS_MS = 60 * MINUTE_AS_MS;
11
- var DAY_AS_MS = 24 * HOUR_AS_MS;
12
- var WEEK_AS_MS = 7 * DAY_AS_MS;
13
- var MONTH_AS_MS = 30 * DAY_AS_MS;
14
- var YEAR_AS_MS = 365 * DAY_AS_MS;
15
- var HOUR_AS_SECS = 60 * 60;
16
- var DAY_AS_SECS = 24 * HOUR_AS_SECS;
17
- var WEEK_AS_SECS = 7 * DAY_AS_SECS;
18
- var MONTH_AS_SECS = 30 * DAY_AS_SECS;
19
- var YEAR_AS_SECS = 365 * DAY_AS_SECS;
20
- function dateStringOrNullToUnixMs(isoString) {
21
- if (!isoString) return null;
22
- const unixMs = new Date(isoString).getTime();
23
- if (isNaN(unixMs)) return null;
24
- return unixMs;
25
- }
26
- function msToTimeString(ms, format, hoursMinLength = 2) {
27
- const { hours, minutes, seconds, milliseconds } = msToDurationObj(ms);
28
- const hoursString = padTimeVal(hours, hoursMinLength);
29
- const minutesString = padTimeVal(minutes);
30
- if (format === "minutes") {
31
- return `${hoursString}:${minutesString}`;
32
- }
33
- const secondsString = padTimeVal(seconds);
34
- if (format === "seconds") {
35
- return `${hoursString}:${minutesString}:${secondsString}`;
36
- }
37
- return `${hoursString}:${minutesString}:${secondsString}:${padTimeVal(
38
- milliseconds,
39
- 3
40
- )}`;
41
- }
42
- function padTimeVal(val, maxLength = 2) {
43
- return val.toString().padStart(maxLength, "0");
44
- }
45
- function parseTimeStringToMs(timeString) {
46
- if (!timeString.trim()) return 0;
47
- const [hours, minutes, seconds, ms] = timeString.split(":");
48
- return getTimeStringPartToInt(hours) * HOUR_AS_MS + clampMax(getTimeStringPartToInt(minutes), 59) * MINUTE_AS_MS + clampMax(getTimeStringPartToInt(seconds), 59) * 1e3 + getTimeStringPartToInt(ms, 3);
49
- }
50
- function getTimeStringPartToInt(timeStringPart, length) {
51
- if (!timeStringPart?.trim()) return 0;
52
- let string = timeStringPart.replaceAll("_", "0");
53
- string = string.replaceAll("-", "");
54
- if (length) {
55
- string = string.padEnd(length, "0");
56
- if (string.length > length) {
57
- string = string.slice(0, length);
58
- }
59
- }
60
- const num = castToNumber(string);
61
- if (!num) return 0;
62
- return Math.floor(num);
63
- }
64
- function msToDurationObj(ms) {
65
- return {
66
- milliseconds: ms % 1e3,
67
- seconds: Math.floor(ms / 1e3) % 60,
68
- minutes: Math.floor(ms / 1e3 / 60) % 60,
69
- hours: Math.floor(ms / 1e3 / 60 / 60)
70
- };
71
- }
72
- function getUnixSeconds() {
73
- return Math.floor(Date.now() / 1e3);
74
- }
2
+ DAY_AS_MS,
3
+ DAY_AS_SECS,
4
+ HOUR_AS_MS,
5
+ HOUR_AS_SECS,
6
+ MINUTE_AS_MS,
7
+ MONTH_AS_MS,
8
+ MONTH_AS_SECS,
9
+ WEEK_AS_MS,
10
+ WEEK_AS_SECS,
11
+ YEAR_AS_MS,
12
+ YEAR_AS_SECS,
13
+ dateStringOrNullToUnixMs,
14
+ durationObjToMs,
15
+ getUnixSeconds,
16
+ msToTimeString,
17
+ parseTimeStringToMs
18
+ } from "./chunk-RK6PT7JY.js";
19
+ import "./chunk-HTCYUMDR.js";
20
+ import "./chunk-GBFS2I67.js";
75
21
  export {
76
22
  DAY_AS_MS,
77
23
  DAY_AS_SECS,
@@ -85,6 +31,7 @@ export {
85
31
  YEAR_AS_MS,
86
32
  YEAR_AS_SECS,
87
33
  dateStringOrNullToUnixMs,
34
+ durationObjToMs,
88
35
  getUnixSeconds,
89
36
  msToTimeString,
90
37
  parseTimeStringToMs
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ls-stack/utils",
3
3
  "description": "Typescript utils",
4
- "version": "2.12.0",
4
+ "version": "2.14.0",
5
5
  "license": "MIT",
6
6
  "files": [
7
7
  "dist"
@@ -322,13 +322,13 @@
322
322
  }
323
323
  },
324
324
  "scripts": {
325
- "test": "vitest --ui",
326
- "test:run": "vitest run",
325
+ "test:ui": "vitest --ui",
326
+ "test": "vitest run",
327
327
  "lint": "pnpm tsc && pnpm eslint",
328
328
  "tsc": "tsc -p tsconfig.prod.json",
329
329
  "tsc:watch": "tsc -p tsconfig.prod.json --watch",
330
330
  "eslint": "CI=true eslint src/ scripts/ --color --max-warnings=0",
331
- "build": "pnpm test:run && pnpm lint && pnpm build:no-test && pnpm build:update-exports",
331
+ "build": "pnpm test && pnpm lint && pnpm build:no-test && pnpm build:update-exports",
332
332
  "build:no-test": "tsup",
333
333
  "build:update-exports": "tsm --no-warnings scripts/updatePackageExports.ts",
334
334
  "build-test": "tsup --config tsup.test.config.ts",