@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/CHANGELOG.md +17 -1
- package/README.md +355 -9
- package/alertsStore/index.d.ts +201 -0
- package/alertsStore/index.js +317 -0
- package/alertsStore/react.d.ts +36 -0
- package/alertsStore/react.js +96 -0
- package/async.d.ts +51 -0
- package/async.js +59 -1
- package/errorhandling.d.ts +1 -1
- package/esm/alertsStore/index.d.ts +201 -0
- package/esm/alertsStore/index.js +280 -0
- package/esm/alertsStore/react.d.ts +36 -0
- package/esm/alertsStore/react.js +58 -0
- package/esm/async.d.ts +51 -0
- package/esm/async.js +57 -0
- package/esm/errorhandling.d.ts +1 -1
- package/esm/index.d.ts +2 -0
- package/index.d.ts +2 -0
- package/package.json +11 -2
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
|
+
};
|
package/esm/errorhandling.d.ts
CHANGED
|
@@ -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-
|
|
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.
|
|
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.
|
|
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"
|