@owlmeans/client 0.1.18-rc.50 → 0.1.18-rc.51
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/README.md +4 -4
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/client/SKILL.md +13 -13
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/lazy-retry/types.d.ts +50 -0
- package/build/lazy-retry/types.d.ts.map +1 -0
- package/build/lazy-retry/types.js +2 -0
- package/build/lazy-retry/types.js.map +1 -0
- package/build/lazy-retry.d.ts +4 -45
- package/build/lazy-retry.d.ts.map +1 -1
- package/build/lazy-retry.js +76 -109
- package/build/lazy-retry.js.map +1 -1
- package/build/lazy.js +5 -5
- package/build/lazy.js.map +1 -1
- package/build/router.d.ts.map +1 -1
- package/build/router.js +5 -4
- package/build/router.js.map +1 -1
- package/build/types.d.ts +5 -2
- package/build/types.d.ts.map +1 -1
- package/build/types.local.d.ts +2 -2
- package/build/types.local.d.ts.map +1 -1
- package/build/utils/index.d.ts +1 -0
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js.map +1 -1
- package/build/utils/route.js +2 -2
- package/build/utils/route.js.map +1 -1
- package/build/utils/router/types.d.ts +15 -0
- package/build/utils/router/types.d.ts.map +1 -0
- package/build/utils/router/types.js +2 -0
- package/build/utils/router/types.js.map +1 -0
- package/build/utils/router.d.ts +4 -5
- package/build/utils/router.d.ts.map +1 -1
- package/build/utils/router.js +36 -32
- package/build/utils/router.js.map +1 -1
- package/package.json +13 -13
- package/src/index.ts +1 -0
- package/src/lazy-retry/types.ts +50 -0
- package/src/lazy-retry.ts +78 -107
- package/src/lazy.tsx +5 -5
- package/src/router.ts +5 -4
- package/src/types.local.ts +2 -1
- package/src/types.ts +3 -2
- package/src/utils/index.ts +1 -0
- package/src/utils/route.tsx +2 -2
- package/src/utils/router/types.ts +15 -0
- package/src/utils/router.ts +50 -44
- package/tests/lazy-retry.spec.ts +40 -42
- package/tests/lazy.spec.ts +2 -2
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ imports everything from here. Server code never uses this package; its equivalen
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
bun add @owlmeans/client@^0.1.18-rc.
|
|
17
|
+
bun add @owlmeans/client@^0.1.18-rc.51
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
`react` and `@remix-run/router` are peer dependencies.
|
|
@@ -227,8 +227,8 @@ The surface is mounted once. It calls `useSetupModalNavigator()`, links a `useTo
|
|
|
227
227
|
|
|
228
228
|
| Symbol | Kind | Purpose |
|
|
229
229
|
|---|---|---|
|
|
230
|
-
| `buildEntrypointTree`,
|
|
231
|
-
| `
|
|
230
|
+
| `clientRouterOf(context).buildEntrypointTree()`, `.visitEntrypointTree(tree, visitor)`, `EntrypointTreeVisitor` | helper member / type | Build and walk the frontend entrypoint tree |
|
|
231
|
+
| `clientRouterOf(context).initializeRouter()` | helper member | Initialize the router for a context |
|
|
232
232
|
| `createRouteRenderer`, `HandledRenderer` | function / type | Render one route with guards applied |
|
|
233
233
|
| `EntrypointContext` | React context | What `useEntrypoint` reads |
|
|
234
234
|
|
|
@@ -273,7 +273,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
273
273
|
your project's skill store (`.agents/skills/`):
|
|
274
274
|
|
|
275
275
|
```sh
|
|
276
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
276
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.49
|
|
277
277
|
```
|
|
278
278
|
|
|
279
279
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/client",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.51",
|
|
5
|
+
"generatedAt": "2026-10-05T21:03:06.392Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: client
|
|
3
|
-
description: How to use @owlmeans/client — the platform-agnostic React client framework (web and native) — makeClientContext, App/Router, useNavigate/Navigator, useEntrypoint/RoutedComponent, useStoreModel/useStoreList, useValue, lazyComponent/lazyHandler code-splitting and chunk-failure recovery (
|
|
3
|
+
description: How to use @owlmeans/client — the platform-agnostic React client framework (web and native) — makeClientContext, App/Router, useNavigate/Navigator, useEntrypoint/RoutedComponent, useStoreModel/useStoreList, useValue, lazyComponent/lazyHandler code-splitting and chunk-failure recovery (lazyRetryHelper), the modal and debug services. Auto-invoked when importing client framework primitives, navigating between screens, or reading client state from React.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/client
|
|
9
9
|
|
|
10
10
|
**Layer:** Client
|
|
11
|
-
**Install:** `"@owlmeans/client": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/client": "^0.1.18-rc.51"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
The React substrate `@owlmeans/web-client` (browser) and the native equivalent are built on. A
|
|
14
14
|
cross-platform package imports from here; an application normally imports from the platform
|
|
@@ -37,8 +37,8 @@ package, which re-exports what it needs — **except the hooks below, which are
|
|
|
37
37
|
| `RoutedComponent<Extra>` | Type of a component bound to a frontend protocol |
|
|
38
38
|
| `handler(Component, preprender?)` | Wrap a React component as an entrypoint handler |
|
|
39
39
|
| `lazyComponent(load, exportName, opts?)` / `lazyHandler(load, exportName, opts?)` | A code-split component with a static `.preload()`; and `handler(lazyComponent(...))` with `.preload` carried through. Types `LazyComponent`, `LazyHandler`, `LazyComponentOptions`, `LazyErrorRenderer` — see Code-splitting |
|
|
40
|
-
| `retryImport(load, opts?)` / `isChunkLoadError(error)` | Run a dynamic `import()` again while it fails to FETCH; tell a fetch failure from a module that loaded and broke. `RetryImportOptions` — see Chunk failures |
|
|
41
|
-
| `reloadOnce(key, windowMs)` / `recoverFromChunkError()` | The guarded page reload, and the one every chunk-failure path in a tab shares — see Chunk failures |
|
|
40
|
+
| `lazyRetryHelper.retryImport(load, opts?)` / `lazyRetryHelper.isChunkLoadError(error)` | Run a dynamic `import()` again while it fails to FETCH; tell a fetch failure from a module that loaded and broke. `RetryImportOptions` — see Chunk failures |
|
|
41
|
+
| `lazyRetryHelper.reloadOnce(key, windowMs)` / `lazyRetryHelper.recoverFromChunkError()` | The guarded page reload, and the one every chunk-failure path in a tab shares — see Chunk failures |
|
|
42
42
|
| `useStoreModel` / `useStoreList` | React hooks over a `@owlmeans/state` resource — one record by id, or a live query |
|
|
43
43
|
| `useValue(loader, deps?, forceDefault?)` / `UseValueParams<T>` | Render an async result. The second argument is the **dependency list**, not a default — see Async values |
|
|
44
44
|
| `useToggle(opened?)` / `Toggleable` | An open/close/toggle handle, which is what a modal surface binds to |
|
|
@@ -50,7 +50,7 @@ package, which re-exports what it needs — **except the hooks below, which are
|
|
|
50
50
|
|
|
51
51
|
## Subpath Exports
|
|
52
52
|
|
|
53
|
-
- `./utils` — `buildEntrypointTree`, `visitEntrypointTree`, `initializeRouter
|
|
53
|
+
- `./utils` — `clientRouterOf(ctx)` (`buildEntrypointTree`, `visitEntrypointTree`, `initializeRouter`), `createRouteRenderer`,
|
|
54
54
|
`EntrypointContext`. What the router is assembled from; a package building its own routing surface
|
|
55
55
|
uses these, an application does not.
|
|
56
56
|
|
|
@@ -132,7 +132,7 @@ const Chart = lazyComponent(() => import('./chart.js'), 'Chart', {
|
|
|
132
132
|
- **`fallback`** is a node or `fallback(props)`. **`error`** is a node or a `LazyErrorRenderer`
|
|
133
133
|
`(props, error, retry) => ReactNode`; `retry()` resets the piece's boundary and renders the
|
|
134
134
|
recreated lazy, which loads the chunk again.
|
|
135
|
-
- **`retry`** — the load runs through `retryImport` by default; pass `RetryImportOptions` to tune
|
|
135
|
+
- **`retry`** — the load runs through `lazyRetryHelper.retryImport` by default; pass `RetryImportOptions` to tune
|
|
136
136
|
it or `false` to load once.
|
|
137
137
|
- **An `exportName` the module does not export** rejects with a `SyntaxError` — never retried.
|
|
138
138
|
|
|
@@ -143,7 +143,7 @@ it:
|
|
|
143
143
|
|
|
144
144
|
| The piece fails with | `error` given | `error` omitted |
|
|
145
145
|
|---|---|---|
|
|
146
|
-
| a chunk-load failure (`isChunkLoadError`), after `retryImport` gave up | with `reload` (default for `lazyHandler`): the guarded reload starts, `fallback` stays, and `error` renders once the guard refuses; without it: `error` renders in place | `recoverFromChunkError()` starts the guarded reload; `fallback` stays in place |
|
|
146
|
+
| a chunk-load failure (`lazyRetryHelper.isChunkLoadError`), after `retryImport` gave up | with `reload` (default for `lazyHandler`): the guarded reload starts, `fallback` stays, and `error` renders once the guard refuses; without it: `error` renders in place | `lazyRetryHelper.recoverFromChunkError()` starts the guarded reload; `fallback` stays in place |
|
|
147
147
|
| anything else (a module that loaded and broke, its own render) | `error` renders in place | propagates to the nearest boundary above, as if the piece had none |
|
|
148
148
|
|
|
149
149
|
Give every piece a deliberate `error`: a leaf that has a plain rendering of the same content (a
|
|
@@ -151,10 +151,10 @@ formatter, a highlighter) degrades to it; anything else shows a notice with a re
|
|
|
151
151
|
(`lazyHandler`) reloads once before its notice (`reload: true` by default) — it has nothing to
|
|
152
152
|
degrade to.
|
|
153
153
|
|
|
154
|
-
- **Retry scope.** `retryImport` covers a TRANSIENT fetch failure — a blip, an edge answering 404
|
|
154
|
+
- **Retry scope.** `lazyRetryHelper.retryImport` covers a TRANSIENT fetch failure — a blip, an edge answering 404
|
|
155
155
|
or 5xx for a moment. Chromium keeps a failed module fetch for the document's lifetime and rejects
|
|
156
156
|
every later `import()` of that URL at once, so a retry imports the URL the error names with a
|
|
157
|
-
fresh `t` parameter (`chunkUrlOf` +
|
|
157
|
+
fresh `t` parameter (`lazyRetryHelper.chunkUrlOf` + `.cacheBustedUrl`, `bustCache` on by default; same-origin
|
|
158
158
|
http(s) URLs only): a new URL, fetched again. That recovers a built chunk. It cannot recover a
|
|
159
159
|
DEV-served module: React Fast Refresh makes every module import itself by its own URL, so the
|
|
160
160
|
busted copy depends on the remembered failure — only a new document loads it, which is what
|
|
@@ -163,20 +163,20 @@ degrade to.
|
|
|
163
163
|
that instance while recovering from the error, and a fresh load there would suspend again
|
|
164
164
|
forever. A NEW mount — a navigation back, another place in the tree — takes the recreated lazy and
|
|
165
165
|
loads again; so does `preload()`.
|
|
166
|
-
- **`isChunkLoadError(error)`** is true for a browser's failed dynamic import (Chromium "Failed to
|
|
166
|
+
- **`lazyRetryHelper.isChunkLoadError(error)`** is true for a browser's failed dynamic import (Chromium "Failed to
|
|
167
167
|
fetch dynamically imported module", Safari "Importing a module script failed", Firefox "error
|
|
168
168
|
loading dynamically imported module"), Vite's "Unable to preload CSS", webpack's `ChunkLoadError`,
|
|
169
169
|
a `vite:preloadError` event, and an element's `error` event. It is false for a `SyntaxError`
|
|
170
170
|
about a missing export and for a throw while the module evaluated — loading those again changes
|
|
171
171
|
nothing.
|
|
172
|
-
- **`retryImport(load, opts?)`** runs `load` again while `shouldRetry(error)` (default
|
|
172
|
+
- **`lazyRetryHelper.retryImport(load, opts?)`** runs `load` again while `shouldRetry(error)` (default
|
|
173
173
|
`isChunkLoadError`) holds, `attempts` (2) more times at most, pausing `delaysMs[i]` before retry
|
|
174
174
|
`i` (500 ms, 1500 ms; the last entry repeats), and rethrows the last failure.
|
|
175
|
-
- **`reloadOnce(key, windowMs)`** reloads the page at most once per `windowMs` per tab, keeping the
|
|
175
|
+
- **`lazyRetryHelper.reloadOnce(key, windowMs)`** reloads the page at most once per `windowMs` per tab, keeping the
|
|
176
176
|
time in `sessionStorage` under `key`; never while offline and never without storage (with no
|
|
177
177
|
guard kept, a failure that survives the reload would reload forever); a platform with no page to
|
|
178
178
|
reload does nothing. It answers whether a reload started.
|
|
179
|
-
- **`recoverFromChunkError()`** is `reloadOnce(CHUNK_RELOAD_KEY, CHUNK_RELOAD_WINDOW_MS)` — the ONE
|
|
179
|
+
- **`lazyRetryHelper.recoverFromChunkError()`** is `reloadOnce(CHUNK_RELOAD_KEY, CHUNK_RELOAD_WINDOW_MS)` — the ONE
|
|
180
180
|
guard a tab shares. An application that also reloads on `vite:preloadError` calls it rather than
|
|
181
181
|
keeping a guard of its own, so one failure never reloads twice.
|
|
182
182
|
|
package/build/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './services/index.js';
|
|
|
4
4
|
export * from './helper.js';
|
|
5
5
|
export * from './lazy.js';
|
|
6
6
|
export * from './lazy-retry.js';
|
|
7
|
+
export type * from './lazy-retry/types.js';
|
|
7
8
|
export * from './navigate.js';
|
|
8
9
|
export * from './entrypoint.js';
|
|
9
10
|
export * from './router.js';
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,mBAAmB,uBAAuB,CAAA;AAC1C,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA"}
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAE/B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { RetryImportOptions } from '../types.js';
|
|
2
|
+
/** Recovers a lazily-loaded chunk that failed to fetch: retry in place, then a guarded reload. */
|
|
3
|
+
export interface LazyRetryHelper {
|
|
4
|
+
/**
|
|
5
|
+
* Whether `error` is a chunk that could not be FETCHED: a browser's failed dynamic import, Vite's
|
|
6
|
+
* stylesheet preload failure, webpack's `ChunkLoadError`, Vite's `vite:preloadError` event, or
|
|
7
|
+
* the `error` event of the element a loader fetched through. A module that was fetched and then
|
|
8
|
+
* failed — a missing export, a throw while it evaluated — is not one: loading it again changes
|
|
9
|
+
* nothing.
|
|
10
|
+
*/
|
|
11
|
+
isChunkLoadError: (error: unknown) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The URL of the chunk a failed dynamic import tried to fetch, when the browser's error names it
|
|
14
|
+
* and it is an http(s) URL of this page's origin — never an arbitrary URL out of a message. `null`
|
|
15
|
+
* otherwise (Safari, a non-browser platform, another origin).
|
|
16
|
+
*/
|
|
17
|
+
chunkUrlOf: (error: unknown) => string | null;
|
|
18
|
+
/**
|
|
19
|
+
* `href` with a fresh `t` parameter: a URL the browser has not seen, so it fetches the module
|
|
20
|
+
* again. `t` is the parameter Vite's dev server already gives module URLs; a static host ignores it.
|
|
21
|
+
*/
|
|
22
|
+
cacheBustedUrl: (href: string, now?: number) => string;
|
|
23
|
+
/**
|
|
24
|
+
* Run `load` — a dynamic `import()` — and, while it rejects with a chunk-load failure, run it again
|
|
25
|
+
* after a pause, `attempts` more times at most. Any other rejection is rethrown at once.
|
|
26
|
+
*
|
|
27
|
+
* This covers a TRANSIENT failure — a network blip, an edge answering 404 or 5xx for a moment.
|
|
28
|
+
* A browser remembers a failed module fetch for the document's lifetime (Chromium does) and
|
|
29
|
+
* rejects every later `import()` of that URL at once, so a retry imports the URL the error names
|
|
30
|
+
* with a cache-busting parameter instead (`bustCache`, default on): a new URL, fetched again. Where
|
|
31
|
+
* the error names no URL (Safari), `load` runs again as is; what always recovers is a new
|
|
32
|
+
* document, which `recoverFromChunkError` starts, once and guarded.
|
|
33
|
+
*/
|
|
34
|
+
retryImport: <M>(load: () => Promise<M>, opts?: RetryImportOptions) => Promise<M>;
|
|
35
|
+
/**
|
|
36
|
+
* Reload the page, at most once per `windowMs` in this tab — the time of the last reload is kept
|
|
37
|
+
* in `sessionStorage` under `key`. Never while offline (the reload would land on the browser's own
|
|
38
|
+
* error page), and never without storage: with nowhere to keep the guard, a failure that survives
|
|
39
|
+
* the reload would reload forever. A platform with no page to reload does nothing. Answers whether
|
|
40
|
+
* a reload was started.
|
|
41
|
+
*/
|
|
42
|
+
reloadOnce: (key: string, windowMs: number) => boolean;
|
|
43
|
+
/**
|
|
44
|
+
* The guarded reload a chunk that failed for good ends in: `reloadOnce` under one key every caller
|
|
45
|
+
* in the tab shares, so a lazy boundary and an application's own `vite:preloadError` listener
|
|
46
|
+
* never reload twice for one failure.
|
|
47
|
+
*/
|
|
48
|
+
recoverFromChunkError: () => boolean;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lazy-retry/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,kGAAkG;AAClG,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,gBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;IAC7C;;;;OAIG;IACH,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAA;IAC7C;;;OAGG;IACH,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IACtD;;;;;;;;;;OAUG;IACH,WAAW,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IACjF;;;;;;OAMG;IACH,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAA;IACtD;;;;OAIG;IACH,qBAAqB,EAAE,MAAM,OAAO,CAAA;CACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lazy-retry/types.ts"],"names":[],"mappings":""}
|
package/build/lazy-retry.d.ts
CHANGED
|
@@ -1,47 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* the `error` event of the element a loader fetched through. A module that was fetched and then
|
|
6
|
-
* failed — a missing export, a throw while it evaluated — is not one: loading it again changes
|
|
7
|
-
* nothing.
|
|
8
|
-
*/
|
|
9
|
-
export declare const isChunkLoadError: (error: unknown) => boolean;
|
|
10
|
-
/**
|
|
11
|
-
* The URL of the chunk a failed dynamic import tried to fetch, when the browser's error names it
|
|
12
|
-
* and it is an http(s) URL of this page's origin — never an arbitrary URL out of a message. `null`
|
|
13
|
-
* otherwise (Safari, a non-browser platform, another origin).
|
|
14
|
-
*/
|
|
15
|
-
export declare const chunkUrlOf: (error: unknown) => string | null;
|
|
16
|
-
/**
|
|
17
|
-
* `href` with a fresh `t` parameter: a URL the browser has not seen, so it fetches the module
|
|
18
|
-
* again. `t` is the parameter Vite's dev server already gives module URLs; a static host ignores it.
|
|
19
|
-
*/
|
|
20
|
-
export declare const cacheBustedUrl: (href: string, now?: number) => string;
|
|
21
|
-
/**
|
|
22
|
-
* Run `load` — a dynamic `import()` — and, while it rejects with a chunk-load failure, run it again
|
|
23
|
-
* after a pause, `attempts` more times at most. Any other rejection is rethrown at once.
|
|
24
|
-
*
|
|
25
|
-
* This covers a TRANSIENT failure — a network blip, an edge answering 404 or 5xx for a moment.
|
|
26
|
-
* A browser remembers a failed module fetch for the document's lifetime (Chromium does) and
|
|
27
|
-
* rejects every later `import()` of that URL at once, so a retry imports the URL the error names
|
|
28
|
-
* with a cache-busting parameter instead (`bustCache`, default on): a new URL, fetched again. Where
|
|
29
|
-
* the error names no URL (Safari), `load` runs again as is; what always recovers is a new
|
|
30
|
-
* document, which `recoverFromChunkError` starts, once and guarded.
|
|
31
|
-
*/
|
|
32
|
-
export declare const retryImport: <M>(load: () => Promise<M>, opts?: RetryImportOptions) => Promise<M>;
|
|
33
|
-
/**
|
|
34
|
-
* Reload the page, at most once per `windowMs` in this tab — the time of the last reload is kept
|
|
35
|
-
* in `sessionStorage` under `key`. Never while offline (the reload would land on the browser's own
|
|
36
|
-
* error page), and never without storage: with nowhere to keep the guard, a failure that survives
|
|
37
|
-
* the reload would reload forever. A platform with no page to reload does nothing. Answers whether
|
|
38
|
-
* a reload was started.
|
|
39
|
-
*/
|
|
40
|
-
export declare const reloadOnce: (key: string, windowMs: number) => boolean;
|
|
41
|
-
/**
|
|
42
|
-
* The guarded reload a chunk that failed for good ends in: `reloadOnce` under one key every caller
|
|
43
|
-
* in the tab shares, so a lazy boundary and an application's own `vite:preloadError` listener
|
|
44
|
-
* never reload twice for one failure.
|
|
45
|
-
*/
|
|
1
|
+
import type { LazyRetryHelper } from './lazy-retry/types.js';
|
|
2
|
+
export declare const createLazyRetryHelper: () => LazyRetryHelper;
|
|
3
|
+
export declare const lazyRetryHelper: LazyRetryHelper;
|
|
4
|
+
/** @deprecated compat:factory-refactor — use `lazyRetryHelper.recoverFromChunkError()` */
|
|
46
5
|
export declare const recoverFromChunkError: () => boolean;
|
|
47
6
|
//# sourceMappingURL=lazy-retry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-retry.d.ts","sourceRoot":"","sources":["../src/lazy-retry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lazy-retry.d.ts","sourceRoot":"","sources":["../src/lazy-retry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAE5D,eAAO,MAAM,qBAAqB,QAAO,eA2FxC,CAAA;AAED,eAAO,MAAM,eAAe,iBAA0B,CAAA;AAEtD,0FAA0F;AAC1F,eAAO,MAAM,qBAAqB,QAAO,OAAkD,CAAA"}
|
package/build/lazy-retry.js
CHANGED
|
@@ -1,122 +1,89 @@
|
|
|
1
1
|
import { CHUNK_RELOAD_KEY, CHUNK_RELOAD_WINDOW_MS, DEF_IMPORT_RETRY_ATTEMPTS, DEF_IMPORT_RETRY_DELAYS_MS } from './consts.js';
|
|
2
2
|
import { CHUNK_FAILURE, FAILED_URL } from './consts.local.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
20
|
-
const pause = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
21
|
-
/**
|
|
22
|
-
* The URL of the chunk a failed dynamic import tried to fetch, when the browser's error names it
|
|
23
|
-
* and it is an http(s) URL of this page's origin — never an arbitrary URL out of a message. `null`
|
|
24
|
-
* otherwise (Safari, a non-browser platform, another origin).
|
|
25
|
-
*/
|
|
26
|
-
export const chunkUrlOf = (error) => {
|
|
27
|
-
const message = error?.message;
|
|
28
|
-
const found = typeof message === 'string' ? FAILED_URL.exec(message)?.[1] : undefined;
|
|
29
|
-
if (found == null) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
const url = new URL(found);
|
|
34
|
-
const origin = typeof location !== 'undefined' ? location.origin : undefined;
|
|
35
|
-
if ((url.protocol !== 'https:' && url.protocol !== 'http:') || (origin != null && url.origin !== origin)) {
|
|
3
|
+
export const createLazyRetryHelper = () => {
|
|
4
|
+
const isChunkLoadError = (error) => {
|
|
5
|
+
if (error == null || typeof error !== 'object') {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (typeof Event !== 'undefined' && error instanceof Event) {
|
|
9
|
+
return error.type === 'vite:preloadError' || error.type === 'error';
|
|
10
|
+
}
|
|
11
|
+
const { name, message } = error;
|
|
12
|
+
return name === 'ChunkLoadError' || (typeof message === 'string' && CHUNK_FAILURE.test(message));
|
|
13
|
+
};
|
|
14
|
+
const pause = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
15
|
+
const chunkUrlOf = (error) => {
|
|
16
|
+
const message = error?.message;
|
|
17
|
+
const found = typeof message === 'string' ? FAILED_URL.exec(message)?.[1] : undefined;
|
|
18
|
+
if (found == null) {
|
|
36
19
|
return null;
|
|
37
20
|
}
|
|
38
|
-
return url.href;
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* `href` with a fresh `t` parameter: a URL the browser has not seen, so it fetches the module
|
|
46
|
-
* again. `t` is the parameter Vite's dev server already gives module URLs; a static host ignores it.
|
|
47
|
-
*/
|
|
48
|
-
export const cacheBustedUrl = (href, now = Date.now()) => {
|
|
49
|
-
const url = new URL(href);
|
|
50
|
-
url.searchParams.set('t', String(now));
|
|
51
|
-
return url.href;
|
|
52
|
-
};
|
|
53
|
-
const importUrl = (url) => import(/* @vite-ignore */ /* webpackIgnore: true */ url);
|
|
54
|
-
/**
|
|
55
|
-
* Run `load` — a dynamic `import()` — and, while it rejects with a chunk-load failure, run it again
|
|
56
|
-
* after a pause, `attempts` more times at most. Any other rejection is rethrown at once.
|
|
57
|
-
*
|
|
58
|
-
* This covers a TRANSIENT failure — a network blip, an edge answering 404 or 5xx for a moment.
|
|
59
|
-
* A browser remembers a failed module fetch for the document's lifetime (Chromium does) and
|
|
60
|
-
* rejects every later `import()` of that URL at once, so a retry imports the URL the error names
|
|
61
|
-
* with a cache-busting parameter instead (`bustCache`, default on): a new URL, fetched again. Where
|
|
62
|
-
* the error names no URL (Safari), `load` runs again as is; what always recovers is a new
|
|
63
|
-
* document, which `recoverFromChunkError` starts, once and guarded.
|
|
64
|
-
*/
|
|
65
|
-
export const retryImport = async (load, opts) => {
|
|
66
|
-
const attempts = Math.max(0, opts?.attempts ?? DEF_IMPORT_RETRY_ATTEMPTS);
|
|
67
|
-
const delays = opts?.delaysMs ?? DEF_IMPORT_RETRY_DELAYS_MS;
|
|
68
|
-
const shouldRetry = opts?.shouldRetry ?? isChunkLoadError;
|
|
69
|
-
const bust = opts?.bustCache !== false;
|
|
70
|
-
const importBusted = opts?.importUrl ?? importUrl;
|
|
71
|
-
let next = load;
|
|
72
|
-
for (let attempt = 0;; attempt++) {
|
|
73
21
|
try {
|
|
74
|
-
|
|
22
|
+
const url = new URL(found);
|
|
23
|
+
const origin = typeof location !== 'undefined' ? location.origin : undefined;
|
|
24
|
+
if ((url.protocol !== 'https:' && url.protocol !== 'http:') || (origin != null && url.origin !== origin)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return url.href;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
75
31
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
32
|
+
};
|
|
33
|
+
const cacheBustedUrl = (href, now = Date.now()) => {
|
|
34
|
+
const url = new URL(href);
|
|
35
|
+
url.searchParams.set('t', String(now));
|
|
36
|
+
return url.href;
|
|
37
|
+
};
|
|
38
|
+
const importUrl = (url) => import(/* @vite-ignore */ /* webpackIgnore: true */ url);
|
|
39
|
+
const retryImport = async (load, opts) => {
|
|
40
|
+
const attempts = Math.max(0, opts?.attempts ?? DEF_IMPORT_RETRY_ATTEMPTS);
|
|
41
|
+
const delays = opts?.delaysMs ?? DEF_IMPORT_RETRY_DELAYS_MS;
|
|
42
|
+
const shouldRetry = opts?.shouldRetry ?? isChunkLoadError;
|
|
43
|
+
const bust = opts?.bustCache !== false;
|
|
44
|
+
const importBusted = opts?.importUrl ?? importUrl;
|
|
45
|
+
let next = load;
|
|
46
|
+
for (let attempt = 0;; attempt++) {
|
|
47
|
+
try {
|
|
48
|
+
return await next();
|
|
79
49
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (attempt >= attempts || !shouldRetry(error)) {
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
const url = bust ? chunkUrlOf(error) : null;
|
|
55
|
+
if (url != null) {
|
|
56
|
+
next = async () => await importBusted(cacheBustedUrl(url));
|
|
57
|
+
}
|
|
58
|
+
await pause(delays[Math.min(attempt, delays.length - 1)] ?? 0);
|
|
83
59
|
}
|
|
84
|
-
await pause(delays[Math.min(attempt, delays.length - 1)] ?? 0);
|
|
85
60
|
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
const now = Date.now();
|
|
105
|
-
if (now - Number(window.sessionStorage.getItem(key) ?? 0) < windowMs) {
|
|
61
|
+
};
|
|
62
|
+
const reloadOnce = (key, windowMs) => {
|
|
63
|
+
const location = typeof window !== 'undefined' ? window.location : undefined;
|
|
64
|
+
if (typeof location?.reload !== 'function') {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (typeof navigator !== 'undefined' && navigator.onLine === false) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const now = Date.now();
|
|
72
|
+
if (now - Number(window.sessionStorage.getItem(key) ?? 0) < windowMs) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
window.sessionStorage.setItem(key, String(now));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
106
78
|
return false;
|
|
107
79
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
location.reload();
|
|
114
|
-
return true;
|
|
80
|
+
location.reload();
|
|
81
|
+
return true;
|
|
82
|
+
};
|
|
83
|
+
const recoverFromChunkError = () => reloadOnce(CHUNK_RELOAD_KEY, CHUNK_RELOAD_WINDOW_MS);
|
|
84
|
+
return { isChunkLoadError, chunkUrlOf, cacheBustedUrl, retryImport, reloadOnce, recoverFromChunkError };
|
|
115
85
|
};
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
* never reload twice for one failure.
|
|
120
|
-
*/
|
|
121
|
-
export const recoverFromChunkError = () => reloadOnce(CHUNK_RELOAD_KEY, CHUNK_RELOAD_WINDOW_MS);
|
|
86
|
+
export const lazyRetryHelper = createLazyRetryHelper();
|
|
87
|
+
/** @deprecated compat:factory-refactor — use `lazyRetryHelper.recoverFromChunkError()` */
|
|
88
|
+
export const recoverFromChunkError = () => lazyRetryHelper.recoverFromChunkError();
|
|
122
89
|
//# sourceMappingURL=lazy-retry.js.map
|
package/build/lazy-retry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-retry.js","sourceRoot":"","sources":["../src/lazy-retry.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,0BAA0B,EAChG,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"lazy-retry.js","sourceRoot":"","sources":["../src/lazy-retry.ts"],"names":[],"mappings":"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"}
|
package/build/lazy.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { lazy, Suspense, Component, useState } from 'react';
|
|
3
3
|
import { handler } from './helper.js';
|
|
4
|
-
import {
|
|
4
|
+
import { lazyRetryHelper } from './lazy-retry.js';
|
|
5
5
|
/**
|
|
6
6
|
* Wrap an async module import as a stable lazily-loaded component with a `.preload()`.
|
|
7
7
|
*
|
|
@@ -26,7 +26,7 @@ import { isChunkLoadError, recoverFromChunkError, retryImport } from './lazy-ret
|
|
|
26
26
|
export const lazyComponent = (load, exportName, opts) => {
|
|
27
27
|
let loaded;
|
|
28
28
|
let loading;
|
|
29
|
-
const fetchModule = () => opts?.retry === false ? load() : retryImport(load, opts?.retry);
|
|
29
|
+
const fetchModule = () => opts?.retry === false ? load() : lazyRetryHelper.retryImport(load, opts?.retry);
|
|
30
30
|
const runLoad = () => loading ??= fetchModule().then(module => {
|
|
31
31
|
const Comp = module[exportName];
|
|
32
32
|
if (Comp == null) {
|
|
@@ -70,8 +70,8 @@ class LazyErrorBoundary extends Component {
|
|
|
70
70
|
// A chunk that failed for good is recovered by a new document: always without a surface of its
|
|
71
71
|
// own, and with one when asked (`reload`) — a whole screen rather than a piece that degrades.
|
|
72
72
|
// The reload is guarded (once a minute per tab); when the guard refuses, the surface stays.
|
|
73
|
-
if (isChunkLoadError(error) && (this.props.error === undefined || this.props.reload)) {
|
|
74
|
-
if (recoverFromChunkError()) {
|
|
73
|
+
if (lazyRetryHelper.isChunkLoadError(error) && (this.props.error === undefined || this.props.reload)) {
|
|
74
|
+
if (lazyRetryHelper.recoverFromChunkError()) {
|
|
75
75
|
this.setState({ reloading: true });
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -92,7 +92,7 @@ class LazyErrorBoundary extends Component {
|
|
|
92
92
|
if (error !== undefined) {
|
|
93
93
|
return typeof error === 'function' ? error(props, this.state.error, this.retry) : error;
|
|
94
94
|
}
|
|
95
|
-
if (isChunkLoadError(this.state.error)) {
|
|
95
|
+
if (lazyRetryHelper.isChunkLoadError(this.state.error)) {
|
|
96
96
|
return fallback;
|
|
97
97
|
}
|
|
98
98
|
// Not a chunk failure and no surface for it: the application's own boundary decides.
|
package/build/lazy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy.js","sourceRoot":"","sources":["../src/lazy.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"lazy.js","sourceRoot":"","sources":["../src/lazy.tsx"],"names":[],"mappings":"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"}
|
package/build/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAA8C,MAAM,OAAO,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAA;AAiB1E,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAkClC,CAAA;AAED,eAAO,MAAM,eAAe,QAAO,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAA8C,MAAM,OAAO,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAA;AAiB1E,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAkClC,CAAA;AAED,eAAO,MAAM,eAAe,QAAO,WA8BlC,CAAA"}
|
package/build/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { clientRouterOf } from './utils/router.js';
|
|
3
3
|
import { createRouteRenderer } from './utils/route.js';
|
|
4
4
|
import { useContext } from './context.js';
|
|
5
5
|
import { assertContext } from '@owlmeans/context';
|
|
@@ -26,7 +26,7 @@ export const Router = ({ provide }) => {
|
|
|
26
26
|
if (!progress.current && !context.cfg.ready) {
|
|
27
27
|
progress.current = true;
|
|
28
28
|
if (provideFn != null) {
|
|
29
|
-
|
|
29
|
+
clientRouterOf(context).initializeRouter().then(routes => provideFn(routes))
|
|
30
30
|
.then(router => setRouter(router));
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -43,8 +43,9 @@ export const makeRouterModel = () => {
|
|
|
43
43
|
routes: [],
|
|
44
44
|
resolve: async (ctx) => {
|
|
45
45
|
const context = assertContext(ctx, location);
|
|
46
|
-
const
|
|
47
|
-
const
|
|
46
|
+
const routing = clientRouterOf(context);
|
|
47
|
+
const entrypointTree = routing.buildEntrypointTree();
|
|
48
|
+
const reactRoutes = await routing.visitEntrypointTree(entrypointTree, async (module, children) => {
|
|
48
49
|
const renderer = module.handle != null
|
|
49
50
|
? { Component: createRouteRenderer({ context, module, hasChildren: children.length > 0 }) }
|
|
50
51
|
: undefined;
|
package/build/router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE3E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|