@owlmeans/client 0.1.18-rc.4 → 0.1.18-rc.41

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 (88) hide show
  1. package/README.md +231 -54
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/client/SKILL.md +282 -19
  4. package/build/consts.d.ts +8 -0
  5. package/build/consts.d.ts.map +1 -1
  6. package/build/consts.js +8 -0
  7. package/build/consts.js.map +1 -1
  8. package/build/context.d.ts.map +1 -1
  9. package/build/context.js +1 -3
  10. package/build/context.js.map +1 -1
  11. package/build/entrypoint.d.ts +3 -0
  12. package/build/entrypoint.d.ts.map +1 -0
  13. package/build/entrypoint.js +4 -0
  14. package/build/entrypoint.js.map +1 -0
  15. package/build/helper.js +3 -3
  16. package/build/helper.js.map +1 -1
  17. package/build/index.d.ts +3 -1
  18. package/build/index.d.ts.map +1 -1
  19. package/build/index.js +3 -1
  20. package/build/index.js.map +1 -1
  21. package/build/lazy-retry.d.ts +47 -0
  22. package/build/lazy-retry.d.ts.map +1 -0
  23. package/build/lazy-retry.js +128 -0
  24. package/build/lazy-retry.js.map +1 -0
  25. package/build/lazy.d.ts +32 -0
  26. package/build/lazy.d.ts.map +1 -0
  27. package/build/lazy.js +114 -0
  28. package/build/lazy.js.map +1 -0
  29. package/build/navigate.d.ts.map +1 -1
  30. package/build/navigate.js +15 -18
  31. package/build/navigate.js.map +1 -1
  32. package/build/router.d.ts.map +1 -1
  33. package/build/router.js +12 -6
  34. package/build/router.js.map +1 -1
  35. package/build/services/debug.js.map +1 -1
  36. package/build/store.d.ts +19 -3
  37. package/build/store.d.ts.map +1 -1
  38. package/build/store.js +57 -50
  39. package/build/store.js.map +1 -1
  40. package/build/types.d.ts +85 -7
  41. package/build/types.d.ts.map +1 -1
  42. package/build/utils/entrypoint.d.ts +3 -0
  43. package/build/utils/entrypoint.d.ts.map +1 -0
  44. package/build/utils/{module.js → entrypoint.js} +2 -2
  45. package/build/utils/entrypoint.js.map +1 -0
  46. package/build/utils/index.d.ts +1 -1
  47. package/build/utils/index.d.ts.map +1 -1
  48. package/build/utils/index.js +1 -1
  49. package/build/utils/index.js.map +1 -1
  50. package/build/utils/route.d.ts.map +1 -1
  51. package/build/utils/route.js +12 -6
  52. package/build/utils/route.js.map +1 -1
  53. package/build/utils/router.d.ts +4 -4
  54. package/build/utils/router.d.ts.map +1 -1
  55. package/build/utils/router.js +8 -8
  56. package/build/utils/router.js.map +1 -1
  57. package/package.json +21 -14
  58. package/src/consts.ts +10 -0
  59. package/src/context.ts +1 -4
  60. package/src/entrypoint.ts +6 -0
  61. package/src/helper.tsx +6 -6
  62. package/src/index.ts +3 -1
  63. package/src/lazy-retry.ts +141 -0
  64. package/src/lazy.tsx +161 -0
  65. package/src/navigate.ts +16 -19
  66. package/src/router.ts +14 -10
  67. package/src/services/debug.ts +2 -2
  68. package/src/store.ts +71 -54
  69. package/src/types.ts +95 -7
  70. package/src/utils/{module.ts → entrypoint.ts} +2 -2
  71. package/src/utils/index.ts +1 -1
  72. package/src/utils/route.tsx +15 -8
  73. package/src/utils/router.ts +11 -11
  74. package/tests/context.ts +33 -0
  75. package/tests/harness/index.html +11 -0
  76. package/tests/harness/mount.tsx +86 -0
  77. package/tests/harness/piece.tsx +4 -0
  78. package/tests/lazy-retry.spec.ts +199 -0
  79. package/tests/lazy.spec.ts +145 -0
  80. package/tsconfig.json +1 -1
  81. package/build/module.d.ts +0 -3
  82. package/build/module.d.ts.map +0 -1
  83. package/build/module.js +0 -4
  84. package/build/module.js.map +0 -1
  85. package/build/utils/module.d.ts +0 -3
  86. package/build/utils/module.d.ts.map +0 -1
  87. package/build/utils/module.js.map +0 -1
  88. package/src/module.ts +0 -6
@@ -0,0 +1,128 @@
1
+ import { CHUNK_RELOAD_KEY, CHUNK_RELOAD_WINDOW_MS, DEF_IMPORT_RETRY_ATTEMPTS, DEF_IMPORT_RETRY_DELAYS_MS } from './consts.js';
2
+ /**
3
+ * What a browser says when a dynamic `import()` could not fetch its module — Chromium, Safari and
4
+ * Firefox, in that order — and what Vite's preload helper says when a chunk's stylesheet could not.
5
+ */
6
+ const CHUNK_FAILURE = /failed to fetch dynamically imported module|importing a module script failed|error loading dynamically imported module|unable to preload css/i;
7
+ /**
8
+ * Whether `error` is a chunk that could not be FETCHED: a browser's failed dynamic import, Vite's
9
+ * stylesheet preload failure, webpack's `ChunkLoadError`, Vite's `vite:preloadError` event, or
10
+ * the `error` event of the element a loader fetched through. A module that was fetched and then
11
+ * failed — a missing export, a throw while it evaluated — is not one: loading it again changes
12
+ * nothing.
13
+ */
14
+ export const isChunkLoadError = (error) => {
15
+ if (error == null || typeof error !== 'object') {
16
+ return false;
17
+ }
18
+ if (typeof Event !== 'undefined' && error instanceof Event) {
19
+ return error.type === 'vite:preloadError' || error.type === 'error';
20
+ }
21
+ const { name, message } = error;
22
+ return name === 'ChunkLoadError' || (typeof message === 'string' && CHUNK_FAILURE.test(message));
23
+ };
24
+ const pause = (ms) => new Promise(resolve => setTimeout(resolve, ms));
25
+ /** The module URL a Chromium or Firefox import failure names; Safari's message names none. */
26
+ const FAILED_URL = /dynamically imported module:?\s+(\S+)/i;
27
+ /**
28
+ * The URL of the chunk a failed dynamic import tried to fetch, when the browser's error names it
29
+ * and it is an http(s) URL of this page's origin — never an arbitrary URL out of a message. `null`
30
+ * otherwise (Safari, a non-browser platform, another origin).
31
+ */
32
+ export const chunkUrlOf = (error) => {
33
+ const message = error?.message;
34
+ const found = typeof message === 'string' ? FAILED_URL.exec(message)?.[1] : undefined;
35
+ if (found == null) {
36
+ return null;
37
+ }
38
+ try {
39
+ const url = new URL(found);
40
+ const origin = typeof location !== 'undefined' ? location.origin : undefined;
41
+ if ((url.protocol !== 'https:' && url.protocol !== 'http:') || (origin != null && url.origin !== origin)) {
42
+ return null;
43
+ }
44
+ return url.href;
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ };
50
+ /**
51
+ * `href` with a fresh `t` parameter: a URL the browser has not seen, so it fetches the module
52
+ * again. `t` is the parameter Vite's dev server already gives module URLs; a static host ignores it.
53
+ */
54
+ export const cacheBustedUrl = (href, now = Date.now()) => {
55
+ const url = new URL(href);
56
+ url.searchParams.set('t', String(now));
57
+ return url.href;
58
+ };
59
+ const importUrl = (url) => import(/* @vite-ignore */ /* webpackIgnore: true */ url);
60
+ /**
61
+ * Run `load` — a dynamic `import()` — and, while it rejects with a chunk-load failure, run it again
62
+ * after a pause, `attempts` more times at most. Any other rejection is rethrown at once.
63
+ *
64
+ * This covers a TRANSIENT failure — a network blip, an edge answering 404 or 5xx for a moment.
65
+ * A browser remembers a failed module fetch for the document's lifetime (Chromium does) and
66
+ * rejects every later `import()` of that URL at once, so a retry imports the URL the error names
67
+ * with a cache-busting parameter instead (`bustCache`, default on): a new URL, fetched again. Where
68
+ * the error names no URL (Safari), `load` runs again as is; what always recovers is a new
69
+ * document, which `recoverFromChunkError` starts, once and guarded.
70
+ */
71
+ export const retryImport = async (load, opts) => {
72
+ const attempts = Math.max(0, opts?.attempts ?? DEF_IMPORT_RETRY_ATTEMPTS);
73
+ const delays = opts?.delaysMs ?? DEF_IMPORT_RETRY_DELAYS_MS;
74
+ const shouldRetry = opts?.shouldRetry ?? isChunkLoadError;
75
+ const bust = opts?.bustCache !== false;
76
+ const importBusted = opts?.importUrl ?? importUrl;
77
+ let next = load;
78
+ for (let attempt = 0;; attempt++) {
79
+ try {
80
+ return await next();
81
+ }
82
+ catch (error) {
83
+ if (attempt >= attempts || !shouldRetry(error)) {
84
+ throw error;
85
+ }
86
+ const url = bust ? chunkUrlOf(error) : null;
87
+ if (url != null) {
88
+ next = async () => await importBusted(cacheBustedUrl(url));
89
+ }
90
+ await pause(delays[Math.min(attempt, delays.length - 1)] ?? 0);
91
+ }
92
+ }
93
+ };
94
+ /**
95
+ * Reload the page, at most once per `windowMs` in this tab — the time of the last reload is kept
96
+ * in `sessionStorage` under `key`. Never while offline (the reload would land on the browser's own
97
+ * error page), and never without storage: with nowhere to keep the guard, a failure that survives
98
+ * the reload would reload forever. A platform with no page to reload does nothing. Answers whether
99
+ * a reload was started.
100
+ */
101
+ export const reloadOnce = (key, windowMs) => {
102
+ const location = typeof window !== 'undefined' ? window.location : undefined;
103
+ if (typeof location?.reload !== 'function') {
104
+ return false;
105
+ }
106
+ if (typeof navigator !== 'undefined' && navigator.onLine === false) {
107
+ return false;
108
+ }
109
+ try {
110
+ const now = Date.now();
111
+ if (now - Number(window.sessionStorage.getItem(key) ?? 0) < windowMs) {
112
+ return false;
113
+ }
114
+ window.sessionStorage.setItem(key, String(now));
115
+ }
116
+ catch {
117
+ return false;
118
+ }
119
+ location.reload();
120
+ return true;
121
+ };
122
+ /**
123
+ * The guarded reload a chunk that failed for good ends in: `reloadOnce` under one key every caller
124
+ * in the tab shares, so a lazy boundary and an application's own `vite:preloadError` listener
125
+ * never reload twice for one failure.
126
+ */
127
+ export const recoverFromChunkError = () => reloadOnce(CHUNK_RELOAD_KEY, CHUNK_RELOAD_WINDOW_MS);
128
+ //# sourceMappingURL=lazy-retry.js.map
@@ -0,0 +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;AAGpB;;;GAGG;AACH,MAAM,aAAa,GAAG,+IAA+I,CAAA;AAErK;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAW,EAAE;IAC1D,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,WAAW,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAC,IAAI,KAAK,mBAAmB,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAA;IACrE,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAA8C,CAAA;IAExE,OAAO,IAAI,KAAK,gBAAgB,IAAI,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;AAClG,CAAC,CAAA;AAED,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AAE5F,8FAA8F;AAC9F,MAAM,UAAU,GAAG,wCAAwC,CAAA;AAE3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAc,EAAiB,EAAE;IAC1D,MAAM,OAAO,GAAI,KAAsC,EAAE,OAAO,CAAA;IAChE,MAAM,KAAK,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACrF,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,MAAM,MAAM,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;QAC5E,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;YACzG,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,GAAG,CAAC,IAAI,CAAA;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAE,GAAG,GAAW,IAAI,CAAC,GAAG,EAAE,EAAU,EAAE;IAC/E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAA;IACzB,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IACtC,OAAO,GAAG,CAAC,IAAI,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,GAAW,EAAoB,EAAE,CAClD,MAAM,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,GAAG,CAAC,CAAA;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAK,IAAsB,EAAE,IAAyB,EAAc,EAAE;IACpG,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,IAAI,yBAAyB,CAAC,CAAA;IACzE,MAAM,MAAM,GAAG,IAAI,EAAE,QAAQ,IAAI,0BAA0B,CAAA;IAC3D,MAAM,WAAW,GAAG,IAAI,EAAE,WAAW,IAAI,gBAAgB,CAAA;IACzD,MAAM,IAAI,GAAG,IAAI,EAAE,SAAS,KAAK,KAAK,CAAA;IACtC,MAAM,YAAY,GAAG,IAAI,EAAE,SAAS,IAAI,SAAS,CAAA;IAEjD,IAAI,IAAI,GAAqB,IAAI,CAAA;IACjC,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,EAAE,CAAA;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,IAAI,QAAQ,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/C,MAAM,KAAK,CAAA;YACb,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;YAC3C,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;gBAChB,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC,MAAM,YAAY,CAAC,cAAc,CAAC,GAAG,CAAC,CAAM,CAAA;YACjE,CAAC;YACD,MAAM,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAChE,CAAC;IACH,CAAC;AACH,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,QAAgB,EAAW,EAAE;IACnE,MAAM,QAAQ,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAC5E,IAAI,OAAO,QAAQ,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,SAAS,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACnE,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC;YACrE,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IACD,QAAQ,CAAC,MAAM,EAAE,CAAA;IAEjB,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAY,EAAE,CAAC,UAAU,CAAC,gBAAgB,EAAE,sBAAsB,CAAC,CAAA"}
@@ -0,0 +1,32 @@
1
+ import type { ComponentExport, ExportProps, LazyComponent, LazyComponentOptions, LazyHandler } from './types.js';
2
+ /**
3
+ * Wrap an async module import as a stable lazily-loaded component with a `.preload()`.
4
+ *
5
+ * MUST be called at module scope, never inside a render, a hook body or an entrypoint handler
6
+ * factory — the OwlMeans route renderer (`utils/route.tsx`) remounts the whole route subtree on
7
+ * every navigation (a fresh component identity per render), so a lazy object created during
8
+ * render would re-suspend on every navigation instead of rendering instantly once loaded.
9
+ *
10
+ * The `Suspense` boundary sits inside the returned component, so the fallback replaces only this
11
+ * component — the layout around it stays mounted while the chunk loads.
12
+ *
13
+ * Once loaded, later renders resolve synchronously (no re-suspend), so a component whose chunk
14
+ * was already preloaded never shows its fallback. A load that fails to fetch is retried in place
15
+ * (`retryImport`, tuned or turned off by `opts.retry`); one that still fails is never cached: the
16
+ * internal `React.lazy` is recreated, so the next mount, `retry()` or `preload()` loads for real.
17
+ *
18
+ * The component always carries its own error boundary, so a chunk that failed for good never
19
+ * unmounts what is around it: `opts.error` renders in its place, or — without one — the guarded
20
+ * reload (`recoverFromChunkError`) starts and the fallback stays. Any other error without
21
+ * `opts.error` goes on to the nearest boundary above, as if there were none.
22
+ */
23
+ export declare const lazyComponent: <M, K extends ComponentExport<M>>(load: () => Promise<M>, exportName: K, opts?: LazyComponentOptions) => LazyComponent<ExportProps<M, K>>;
24
+ /**
25
+ * `handler(lazyComponent(...))`, carrying `.preload()` through — bind it to a screen exactly like
26
+ * `handler(Component)`. The same module-scope rule applies: call it where the entrypoints are
27
+ * declared, never inside a render. A screen whose chunk still fails after its retries starts the
28
+ * guarded reload before showing its `error` (`reload` defaults to `true` here): a whole screen has
29
+ * nothing to degrade to, and in a dev-served app only a new document can load it again.
30
+ */
31
+ export declare const lazyHandler: <M, K extends ComponentExport<M>>(load: () => Promise<M>, exportName: K, opts?: LazyComponentOptions) => LazyHandler<ExportProps<M, K>>;
32
+ //# sourceMappingURL=lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../src/lazy.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,oBAAoB,EAAE,WAAW,EAC/E,MAAM,YAAY,CAAA;AAKnB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,QACrD,MAAM,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,SAAS,oBAAoB,KACjE,aAAa,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAgDjC,CAAA;AA+DD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,EAAE,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,QACnD,MAAM,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,SAAS,oBAAoB,KACjE,WAAW,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAK/B,CAAA"}
package/build/lazy.js ADDED
@@ -0,0 +1,114 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { lazy, Suspense, Component, useState } from 'react';
3
+ import { handler } from './helper.js';
4
+ import { isChunkLoadError, recoverFromChunkError, retryImport } from './lazy-retry.js';
5
+ /**
6
+ * Wrap an async module import as a stable lazily-loaded component with a `.preload()`.
7
+ *
8
+ * MUST be called at module scope, never inside a render, a hook body or an entrypoint handler
9
+ * factory — the OwlMeans route renderer (`utils/route.tsx`) remounts the whole route subtree on
10
+ * every navigation (a fresh component identity per render), so a lazy object created during
11
+ * render would re-suspend on every navigation instead of rendering instantly once loaded.
12
+ *
13
+ * The `Suspense` boundary sits inside the returned component, so the fallback replaces only this
14
+ * component — the layout around it stays mounted while the chunk loads.
15
+ *
16
+ * Once loaded, later renders resolve synchronously (no re-suspend), so a component whose chunk
17
+ * was already preloaded never shows its fallback. A load that fails to fetch is retried in place
18
+ * (`retryImport`, tuned or turned off by `opts.retry`); one that still fails is never cached: the
19
+ * internal `React.lazy` is recreated, so the next mount, `retry()` or `preload()` loads for real.
20
+ *
21
+ * The component always carries its own error boundary, so a chunk that failed for good never
22
+ * unmounts what is around it: `opts.error` renders in its place, or — without one — the guarded
23
+ * reload (`recoverFromChunkError`) starts and the fallback stays. Any other error without
24
+ * `opts.error` goes on to the nearest boundary above, as if there were none.
25
+ */
26
+ export const lazyComponent = (load, exportName, opts) => {
27
+ let loaded;
28
+ let loading;
29
+ const fetchModule = () => opts?.retry === false ? load() : retryImport(load, opts?.retry);
30
+ const runLoad = () => loading ??= fetchModule().then(module => {
31
+ const Comp = module[exportName];
32
+ if (Comp == null) {
33
+ throw new SyntaxError(`Lazy module has no component export "${exportName}"`);
34
+ }
35
+ return loaded = Comp;
36
+ }).catch((error) => {
37
+ loading = undefined;
38
+ current = createLazy();
39
+ throw error;
40
+ });
41
+ const preload = () => loaded != null ? Promise.resolve(loaded) : runLoad();
42
+ const createLazy = () => lazy(() => {
43
+ const ready = loaded;
44
+ if (ready != null) {
45
+ // Already resolved: hand React a thenable that settles synchronously, so its lazy
46
+ // initializer reads the module in the same tick and never suspends.
47
+ const settled = { then: (resolve) => resolve({ default: ready }) };
48
+ return settled;
49
+ }
50
+ return runLoad().then(Comp => ({ default: Comp }));
51
+ });
52
+ let current = createLazy();
53
+ const Lazy = (props) => {
54
+ // The lazy THIS instance renders, taken when it mounts: a failed load stays failed for it
55
+ // while React re-renders it to recover from the error, until `retry` swaps in the recreated
56
+ // lazy. A new mount — a navigation back, another place — takes the recreated one at once.
57
+ const [Current, setCurrent] = useState(() => current);
58
+ const fallback = (typeof opts?.fallback === 'function' ? opts.fallback(props) : opts?.fallback) ?? null;
59
+ return _jsx(LazyErrorBoundary, { error: opts?.error, reload: opts?.reload === true, fallback: fallback, props: props, onRetry: () => setCurrent(() => current), children: _jsx(Suspense, { fallback: fallback, children: _jsx(Current, { ...props }) }) });
60
+ };
61
+ Lazy.displayName = `Lazy(${exportName})`;
62
+ return Object.assign(Lazy, { preload });
63
+ };
64
+ class LazyErrorBoundary extends Component {
65
+ state = { failed: false, error: undefined };
66
+ static getDerivedStateFromError(error) {
67
+ return { failed: true, error };
68
+ }
69
+ componentDidCatch(error) {
70
+ // A chunk that failed for good is recovered by a new document: always without a surface of its
71
+ // own, and with one when asked (`reload`) — a whole screen rather than a piece that degrades.
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()) {
75
+ this.setState({ reloading: true });
76
+ }
77
+ }
78
+ }
79
+ /** Render the children again, over the recreated lazy, which loads anew. */
80
+ retry = () => {
81
+ this.setState({ failed: false, error: undefined, reloading: false });
82
+ this.props.onRetry();
83
+ };
84
+ render() {
85
+ if (!this.state.failed) {
86
+ return this.props.children;
87
+ }
88
+ const { error, fallback, props } = this.props;
89
+ if (this.state.reloading === true) {
90
+ return fallback;
91
+ }
92
+ if (error !== undefined) {
93
+ return typeof error === 'function' ? error(props, this.state.error, this.retry) : error;
94
+ }
95
+ if (isChunkLoadError(this.state.error)) {
96
+ return fallback;
97
+ }
98
+ // Not a chunk failure and no surface for it: the application's own boundary decides.
99
+ throw this.state.error;
100
+ }
101
+ }
102
+ /**
103
+ * `handler(lazyComponent(...))`, carrying `.preload()` through — bind it to a screen exactly like
104
+ * `handler(Component)`. The same module-scope rule applies: call it where the entrypoints are
105
+ * declared, never inside a render. A screen whose chunk still fails after its retries starts the
106
+ * guarded reload before showing its `error` (`reload` defaults to `true` here): a whole screen has
107
+ * nothing to degrade to, and in a dev-served app only a new document can load it again.
108
+ */
109
+ export const lazyHandler = (load, exportName, opts) => {
110
+ const LazyComp = lazyComponent(load, exportName, { ...opts, reload: opts?.reload ?? true });
111
+ const refed = handler(LazyComp);
112
+ return Object.assign(refed, { preload: LazyComp.preload });
113
+ };
114
+ //# sourceMappingURL=lazy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy.js","sourceRoot":"","sources":["../src/lazy.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"navigate.d.ts","sourceRoot":"","sources":["../src/navigate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAK3C,eAAO,MAAM,WAAW,QAAO,SA+C9B,CAAA"}
1
+ {"version":3,"file":"navigate.d.ts","sourceRoot":"","sources":["../src/navigate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAI3C,eAAO,MAAM,WAAW,QAAO,SA6C9B,CAAA"}
package/build/navigate.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { useMemo } from 'react';
2
- import { EntrypointOutcome } from '@owlmeans/entrypoint';
3
2
  import { useContext } from './context.js';
4
3
  export const useNavigate = () => {
5
4
  const context = useContext();
@@ -8,25 +7,23 @@ export const useNavigate = () => {
8
7
  const navigator = useMemo(() => {
9
8
  const navigator = {
10
9
  _navigate: navigate,
11
- navigate: async (module, request) => {
12
- const [url, ok] = await module.call(request);
13
- if (ok === EntrypointOutcome.Ok) {
14
- if (url.startsWith('http')) {
15
- globalThis.location.href = url;
16
- }
17
- else {
18
- navigate(url, {
19
- state: {
20
- ...module.route.route, silent: request?.silent
21
- },
22
- replace: request?.replace ?? false
23
- });
24
- }
10
+ navigate: async (entrypoint, request) => {
11
+ const url = await entrypoint.url(request);
12
+ if (url.startsWith('http')) {
13
+ globalThis.location.href = url;
14
+ }
15
+ else {
16
+ navigate(url, {
17
+ state: {
18
+ ...entrypoint.route.route, silent: request?.silent
19
+ },
20
+ replace: request?.replace ?? false
21
+ });
25
22
  }
26
23
  },
27
- go: async (alias, request) => navigator.navigate(context.entrypoint(alias), request),
28
- press: (alias, request) => () => {
29
- void navigator.go(alias, request);
24
+ go: async (target, request) => navigator.navigate(context.entrypoint(target), request),
25
+ press: (target, request) => () => {
26
+ void navigator.go(target, request);
30
27
  },
31
28
  back: async () => {
32
29
  navigate(-1);
@@ -1 +1 @@
1
- {"version":3,"file":"navigate.js","sourceRoot":"","sources":["../src/navigate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,MAAM,CAAC,MAAM,WAAW,GAAG,GAAc,EAAE;IACzC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAA;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAA;IAC/C,MAAM,SAAS,GAAc,OAAO,CAAC,GAAG,EAAE;QACxC,MAAM,SAAS,GAAc;YAC3B,SAAS,EAAE,QAAQ;YAEnB,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;gBAClC,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBAE5C,IAAI,EAAE,KAAK,iBAAiB,CAAC,EAAE,EAAE,CAAC;oBAChC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC3B,UAAU,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAA;oBAChC,CAAC;yBAAM,CAAC;wBACN,QAAQ,CAAC,GAAG,EAAE;4BACZ,KAAK,EAAE;gCACL,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;6BAC/C;4BACD,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK;yBACnC,CAAC,CAAA;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;YAED,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAC3B,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAA2B,KAAK,CAAC,EAAE,OAAO,CAAC;YAElF,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,EAAE;gBAC9B,KAAK,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;YACnC,CAAC;YAED,IAAI,EAAE,KAAK,IAAI,EAAE;gBACf,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YACd,CAAC;YAED,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE;gBACpB,KAAK,SAAS,CAAC,IAAI,EAAE,CAAA;YACvB,CAAC;YAED,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ;SACzB,CAAA;QAED,OAAO,SAAS,CAAA;IAClB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA"}
1
+ {"version":3,"file":"navigate.js","sourceRoot":"","sources":["../src/navigate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,MAAM,CAAC,MAAM,WAAW,GAAG,GAAc,EAAE;IACzC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAA;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAA;IAC/C,MAAM,SAAS,GAAc,OAAO,CAAC,GAAG,EAAE;QACxC,MAAM,SAAS,GAAc;YAC3B,SAAS,EAAE,QAAQ;YAEnB,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE;gBACtC,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBAEzC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,UAAU,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAA;gBAChC,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,GAAG,EAAE;wBACZ,KAAK,EAAE;4BACL,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;yBACnD;wBACD,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK;qBACnC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;YAED,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAC5B,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAA2B,MAAM,CAAC,EAAE,OAAO,CAAC;YAEnF,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,EAAE;gBAC/B,KAAK,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;YACpC,CAAC;YAED,IAAI,EAAE,KAAK,IAAI,EAAE;gBACf,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YACd,CAAC;YAED,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE;gBACpB,KAAK,SAAS,CAAC,IAAI,EAAE,CAAA;YACvB,CAAC;YAED,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ;SACzB,CAAA;QAED,OAAO,SAAS,CAAA;IAClB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAA;AAc1E,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAkClC,CAAA;AAED,eAAO,MAAM,eAAe,QAAO,WAgClC,CAAA"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAA;AAqB1E,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAkClC,CAAA;AAED,eAAO,MAAM,eAAe,QAAO,WA6BlC,CAAA"}
package/build/router.js CHANGED
@@ -1,8 +1,14 @@
1
1
  import { createElement, useEffect, useRef, useState } from 'react';
2
- import { buildModuleTree, initializeRouter, visitModuleTree } from './utils/router.js';
2
+ import { buildEntrypointTree, initializeRouter, visitEntrypointTree } 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';
6
+ /** A child path that keeps its leading separator reads as absolute, and the router rejects it. */
7
+ const relative = (segment) => {
8
+ segment = segment.trim();
9
+ segment = segment.endsWith('/') ? segment.slice(0, -1) : segment;
10
+ return segment.startsWith('/') ? segment.substring(1) : segment;
11
+ };
6
12
  export const Router = ({ provide }) => {
7
13
  const progress = useRef(false);
8
14
  const context = useContext();
@@ -37,16 +43,16 @@ export const makeRouterModel = () => {
37
43
  routes: [],
38
44
  resolve: async (ctx) => {
39
45
  const context = assertContext(ctx, location);
40
- const moduleTree = buildModuleTree(context);
41
- const reactRoutes = await visitModuleTree(moduleTree, async (module, children) => {
42
- const ctx = assertContext((module.ctx ?? context), location);
43
- await module.route.resolve(ctx);
46
+ const entrypointTree = buildEntrypointTree(context);
47
+ const reactRoutes = await visitEntrypointTree(entrypointTree, async (module, children) => {
44
48
  const renderer = module.handle != null
45
49
  ? { Component: createRouteRenderer({ context, module, hasChildren: children.length > 0 }) }
46
50
  : undefined;
51
+ // The React tree nests, so each node contributes only its OWN segment — its ancestors are
52
+ // the branches it hangs under and already carry theirs.
47
53
  const route = {
48
54
  ...(module.route.route.default ? { index: true } : undefined),
49
- ...(!module.route.route.default ? { path: module.getPath(true), children } : undefined),
55
+ ...(!module.route.route.default ? { path: relative(module.segment()), children } : undefined),
50
56
  ...renderer
51
57
  };
52
58
  return route;
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"debug.js","sourceRoot":"","sources":["../../src/services/debug.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../../src/services/debug.ts"],"names":[],"mappings":"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"}
package/build/store.d.ts CHANGED
@@ -1,4 +1,20 @@
1
- import type { UseStoreHelper, UseStoreListHelper } from '@owlmeans/state';
2
- export declare const useStoreModel: UseStoreHelper;
3
- export declare const useStoreList: UseStoreListHelper;
1
+ import type { ResourceRecord } from '@owlmeans/resource';
2
+ import type { StateModel } from '@owlmeans/state';
3
+ import type { UseStoreListOptions } from './types.js';
4
+ /**
5
+ * One record from a state resource, live.
6
+ *
7
+ * It never throws for missing data: an id the store knows nothing about yields a model whose
8
+ * `empty` is true — reading `record` gives the resource's configured default, and nothing is
9
+ * written into the store on the way. An ABSENT id is the same answer rather than an error, since
10
+ * a screen renders before the record that supplies the id has arrived; on a `single` resource an
11
+ * absent id addresses its sole record. Writing through an empty model with no id is refused.
12
+ */
13
+ export declare const useStoreModel: <T extends ResourceRecord = ResourceRecord>(id?: string, alias?: string) => StateModel<T>;
14
+ /**
15
+ * A live LIST from a state resource: every record the query accepts, re-evaluated on every write
16
+ * that changes the answer, so a screen never recomputes ids and never re-subscribes to keep up.
17
+ * Omitting `query` matches everything.
18
+ */
19
+ export declare const useStoreList: <T extends ResourceRecord = ResourceRecord>(opts?: UseStoreListOptions<T>) => StateModel<T>[];
4
20
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,cAAc,EAAyB,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAI5G,eAAO,MAAM,aAAa,EAAE,cAQ3B,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,kBAoD1B,CAAA"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAiCrD;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,cAAc,GAAG,cAAc,OAChE,MAAM,UAAU,MAAM,KAC1B,UAAU,CAAC,CAAC,CASd,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,cAAc,GAAG,cAAc,SAC7D,mBAAmB,CAAC,CAAC,CAAC,KAC5B,UAAU,CAAC,CAAC,CAAC,EAkBf,CAAA"}
package/build/store.js CHANGED
@@ -1,55 +1,62 @@
1
- import { useEffect, useId, useMemo, useState } from 'react';
1
+ import { useMemo, useSyncExternalStore } from 'react';
2
2
  import { useContext } from './context.js';
3
- export const useStoreModel = (id, opts) => {
4
- const list = useStoreList(id, opts);
5
- if (list.length < 1) {
6
- throw new SyntaxError('Store always return model and create it if not exists');
7
- }
8
- return list[0];
3
+ /**
4
+ * Turn one state subscription into the pair `useSyncExternalStore` wants.
5
+ *
6
+ * The value is cached rather than rebuilt per render: the hook is asked for a snapshot on every
7
+ * render and must answer with the same reference until something actually changed, or React
8
+ * re-renders forever. A state subscription hands its value over synchronously, so the first
9
+ * snapshot is taken by subscribing and unsubscribing again — no render ever runs without one,
10
+ * and no subscription outlives the call.
11
+ */
12
+ const bind = (subscribe) => {
13
+ let current;
14
+ let seeded = false;
15
+ const capture = (notify) => (value) => {
16
+ current = value;
17
+ seeded = true;
18
+ notify?.();
19
+ };
20
+ return {
21
+ subscribe: (notify) => subscribe(capture(notify)),
22
+ snapshot: () => {
23
+ if (!seeded) {
24
+ subscribe(capture())();
25
+ }
26
+ return current;
27
+ }
28
+ };
9
29
  };
10
- export const useStoreList = (ids, opts) => {
11
- if (typeof ids === 'object' && !Array.isArray(ids)) {
12
- opts = ids;
13
- }
14
- const params = typeof opts === 'object' ? opts : {};
15
- if (typeof ids === 'string' || Array.isArray(ids)) {
16
- params.id = ids;
17
- }
18
- if (typeof opts === 'string') {
19
- params.resource = opts;
20
- }
21
- else if (typeof opts === 'boolean') {
22
- params.listen = opts;
23
- }
24
- params.listen = params.listen ?? true;
30
+ /**
31
+ * One record from a state resource, live.
32
+ *
33
+ * It never throws for missing data: an id the store knows nothing about yields a model whose
34
+ * `empty` is true — reading `record` gives the resource's configured default, and nothing is
35
+ * written into the store on the way. An ABSENT id is the same answer rather than an error, since
36
+ * a screen renders before the record that supplies the id has arrived; on a `single` resource an
37
+ * absent id addresses its sole record. Writing through an empty model with no id is refused.
38
+ */
39
+ export const useStoreModel = (id, alias) => {
25
40
  const context = useContext();
26
- const resource = useMemo(() => context.getStateResource(params.resource), [params.resource]);
27
- const deps = [
28
- Array.isArray(params.id) ? params.id.join(',') : params.id,
29
- params.query == null,
30
- JSON.stringify(params.default),
31
- params.listen
32
- ];
33
- const id = useId();
34
- const [models, setModels] = useState([]);
35
- let _return = [...models];
36
- const unsubscribe = useMemo(() => {
37
- const [unsubscribe, _initialModels] = resource.subscribe({
38
- _systemId: id,
39
- id: params.id,
40
- listener: models => {
41
- params.listen && setModels(models);
42
- },
43
- default: params.default,
44
- query: params.query,
45
- });
46
- setModels(_initialModels);
47
- if (_return.length < 1) {
48
- _return.push(..._initialModels);
49
- }
50
- return unsubscribe;
51
- }, deps);
52
- useEffect(() => unsubscribe, deps);
53
- return _return;
41
+ const resource = useMemo(() => context.getStateResource(alias), [context, alias]);
42
+ const store = useMemo(() => bind(listener => resource.watch(id, listener)), [resource, id]);
43
+ return useSyncExternalStore(store.subscribe, store.snapshot, store.snapshot);
44
+ };
45
+ /**
46
+ * A live LIST from a state resource: every record the query accepts, re-evaluated on every write
47
+ * that changes the answer, so a screen never recomputes ids and never re-subscribes to keep up.
48
+ * Omitting `query` matches everything.
49
+ */
50
+ export const useStoreList = (opts) => {
51
+ const context = useContext();
52
+ const resource = useMemo(() => context.getStateResource(opts?.resource), [context, opts?.resource]);
53
+ /**
54
+ * The subscription is keyed on the query's CONTENT, not on whether one was given: a screen
55
+ * that narrows its filter has to re-subscribe, and keyed on identity it kept answering the
56
+ * first filter it ever saw with nothing to say the list had gone stale.
57
+ */
58
+ const key = JSON.stringify([opts?.query ?? null, opts?.sort ?? null]);
59
+ const store = useMemo(() => bind(listener => resource.query(opts?.query, listener, { sort: opts?.sort })), [resource, key]);
60
+ return useSyncExternalStore(store.subscribe, store.snapshot, store.snapshot);
54
61
  };
55
62
  //# sourceMappingURL=store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAGrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC;;;;;;;;GAQG;AACH,MAAM,IAAI,GAAG,CAAI,SAAuD,EAAE,EAAE;IAC1E,IAAI,OAAsB,CAAA;IAC1B,IAAI,MAAM,GAAG,KAAK,CAAA;IAElB,MAAM,OAAO,GAAG,CAAC,MAAmB,EAAE,EAAE,CAAC,CAAC,KAAQ,EAAE,EAAE;QACpD,OAAO,GAAG,KAAK,CAAA;QACf,MAAM,GAAG,IAAI,CAAA;QACb,MAAM,EAAE,EAAE,CAAA;IACZ,CAAC,CAAA;IAED,OAAO;QACL,SAAS,EAAE,CAAC,MAAkB,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7D,QAAQ,EAAE,GAAM,EAAE;YAChB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,CAAA;YACxB,CAAC;YAED,OAAO,OAAY,CAAA;QACrB,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,EAAW,EAAE,KAAc,EACZ,EAAE;IACjB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAI,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAA;IACpF,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,IAAI,CAAgB,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,EACnE,CAAC,QAAQ,EAAE,EAAE,CAAC,CACf,CAAA;IAED,OAAO,oBAAoB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;AAC9E,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,IAA6B,EACZ,EAAE;IACnB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAI,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEtG;;;;OAIG;IACH,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,CAAA;IACrE,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,IAAI,CACR,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CACxE,EACD,CAAC,QAAQ,EAAE,GAAG,CAAC,CAChB,CAAA;IAED,OAAO,oBAAoB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;AAC9E,CAAC,CAAA"}