@reykjavik/webtools 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm/async.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { toSec as _toSec } from './http.js';
1
2
  /**
2
3
  * Simple sleep function. Returns a promise that resolves after `length`
3
4
  * milliseconds.
@@ -174,3 +175,59 @@ skipFirst) => {
174
175
  throttle.d = (delay, skipFirst) => throttle(function (fn, ...args) {
175
176
  fn.apply(this, args);
176
177
  }, delay, skipFirst);
178
+ // ---------------------------------------------------------------------------
179
+ // Wrap toSec to use a 90% shorter TTL in development mode
180
+ const toSec = process.env.NODE_ENV === 'production' ? _toSec : (val) => _toSec(val) / 10;
181
+ const DEFAULT_THROTTLING_MS = '30s';
182
+ /**
183
+ * Wraps an async function with a simple, but fairly robust caching layer.
184
+ *
185
+ * Successful results are cached for `ttlMs`, while error results are
186
+ * throttled to avoid hammering the underlying function.
187
+ *
188
+ * Has no max size or eviction strategy; intended for caching a small,
189
+ * clearly bounded number of different cache "keys" (e.g. per language).
190
+ *
191
+ * @see https://github.com/reykjavikcity/webtools/blob/v0.3/README.md#cachifyasync
192
+ */
193
+ /*#__NO_SIDE_EFFECTS__*/
194
+ export const cachifyAsync = (opts) => {
195
+ const { fn, getKey = (...args) => JSON.stringify(args), customTtl, returnStale } = opts;
196
+ // Set up the cache object
197
+ const TTL_SEC = toSec(opts.ttl);
198
+ const THROTTLING_SEC = toSec(opts.throttle || 0) || Math.min(toSec(DEFAULT_THROTTLING_MS), TTL_SEC);
199
+ const _cache = new Map();
200
+ return (async (...args) => {
201
+ const now = Date.now();
202
+ const key = getKey(...args);
203
+ const cached = _cache.get(key);
204
+ if (cached && now < cached.freshUntil) {
205
+ return cached.data;
206
+ }
207
+ const lastData = returnStale !== false && (cached === null || cached === void 0 ? void 0 : cached.data);
208
+ const entry = {
209
+ // Set an initial "fresh until" that's longer than TTL_SEC to cover
210
+ // (somewhat) safely the time it takes for the promise to resolve,
211
+ // so that we don't trigger multiple calls to `fn` in parallel
212
+ // TODO: Build in a proper AbortSignal timeout, etc. to handle this more robustly
213
+ freshUntil: now + (TTL_SEC + 60) * 1000,
214
+ data: fn(...args).then((result) => {
215
+ const customTtlSec = toSec((customTtl === null || customTtl === void 0 ? void 0 : customTtl(args, result)) || 0);
216
+ entry.freshUntil = now + (customTtlSec || TTL_SEC) * 1000;
217
+ if (result.error) {
218
+ if (!customTtlSec) {
219
+ // Set shorter TTL on errors to allow quicker retries
220
+ entry.freshUntil = now + THROTTLING_SEC * 1000;
221
+ }
222
+ if (lastData) {
223
+ // Return last known good data if available, even if it's a bit stale
224
+ return lastData;
225
+ }
226
+ }
227
+ return result;
228
+ }),
229
+ };
230
+ _cache.set(key, entry);
231
+ return entry.data;
232
+ });
233
+ };
@@ -119,7 +119,7 @@ export declare namespace Result {
119
119
  * Extracts the error type `E` from a `Result.Tuple<T, E>`-like
120
120
  * type, a `Promise` of such type, or a function returning either of those.
121
121
  *
122
- * @see https://github.com/reykjavikcity/webtools/blob/v0.3/README.md#type-resultpayloadof
122
+ * @see https://github.com/reykjavikcity/webtools/blob/v0.3/README.md#type-resulterrorof
123
123
  */
124
124
  type ErrorOf<T extends ResultTuple<unknown> | Promise<ResultTuple<unknown>> | ((...args: Array<any>) => ResultTuple<unknown> | Promise<ResultTuple<unknown>>)> = T extends [infer E, undefined?] ? E : T extends Promise<infer P> ? P extends [infer E, undefined?] ? E : never : T extends (...args: Array<any>) => infer R ? R extends [infer E, undefined?] ? E : R extends Promise<infer P> ? P extends [infer E, undefined?] ? E : never : never : never;
125
125
  }
package/esm/index.d.ts CHANGED
@@ -5,9 +5,11 @@
5
5
  /// <reference path="./fixIcelandicLocale.d.ts" />
6
6
  /// <reference path="./errorhandling.d.ts" />
7
7
  /// <reference path="./react-router/http.d.ts" />
8
+ /// <reference path="./alertsStore/index.d.ts" />
8
9
  /// <reference path="./SiteImprove.d.tsx" />
9
10
  /// <reference path="./CookieHubConsent.d.tsx" />
10
11
  /// <reference path="./react-router/Wait.d.tsx" />
12
+ /// <reference path="./alertsStore/react.d.tsx" />
11
13
  /// <reference path="./next/http.d.tsx" />
12
14
 
13
15
  export {};
package/index.d.ts CHANGED
@@ -5,9 +5,11 @@
5
5
  /// <reference path="./fixIcelandicLocale.d.ts" />
6
6
  /// <reference path="./errorhandling.d.ts" />
7
7
  /// <reference path="./react-router/http.d.ts" />
8
+ /// <reference path="./alertsStore/index.d.ts" />
8
9
  /// <reference path="./SiteImprove.d.tsx" />
9
10
  /// <reference path="./CookieHubConsent.d.tsx" />
10
11
  /// <reference path="./react-router/Wait.d.tsx" />
12
+ /// <reference path="./alertsStore/react.d.tsx" />
11
13
  /// <reference path="./next/http.d.tsx" />
12
14
 
13
15
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reykjavik/webtools",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Misc. JS/TS helpers used by Reykjavík City's web dev teams.",
5
5
  "main": "index.js",
6
6
  "repository": "ssh://git@github.com:reykjavikcity/webtools.git",
@@ -11,7 +11,8 @@
11
11
  ],
12
12
  "license": "MIT",
13
13
  "dependencies": {
14
- "@reykjavik/hanna-utils": "^0.2.20"
14
+ "@reykjavik/hanna-utils": "^0.2.22",
15
+ "valibot": "^1.2.0"
15
16
  },
16
17
  "peerDependencies": {
17
18
  "@vanilla-extract/css": "^1.14.1",
@@ -76,6 +77,10 @@
76
77
  "import": "./esm/react-router/http.js",
77
78
  "require": "./react-router/http.js"
78
79
  },
80
+ "./alertsStore": {
81
+ "import": "./esm/alertsStore/index.js",
82
+ "require": "./alertsStore/index.js"
83
+ },
79
84
  "./SiteImprove": {
80
85
  "import": "./esm/SiteImprove.js",
81
86
  "require": "./SiteImprove.js"
@@ -88,6 +93,10 @@
88
93
  "import": "./esm/react-router/Wait.js",
89
94
  "require": "./react-router/Wait.js"
90
95
  },
96
+ "./alertsStore/react": {
97
+ "import": "./esm/alertsStore/react.js",
98
+ "require": "./alertsStore/react.js"
99
+ },
91
100
  "./next/http": {
92
101
  "import": "./esm/next/http.js",
93
102
  "require": "./next/http.js"