@askrjs/askr 0.3.1 → 0.4.1

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 (123) hide show
  1. package/CHANGELOG.md +898 -1
  2. package/README.md +61 -29
  3. package/capabilities.json +19 -9
  4. package/dist/actions/index.js +56 -12
  5. package/dist/benchmark.js +10 -15
  6. package/dist/boot/index.d.ts +3 -2
  7. package/dist/boot/index.js +1 -1
  8. package/dist/boot-C5HnQZio.js +4032 -0
  9. package/dist/browser-activity-2r5gA1Cb.js +222 -0
  10. package/dist/components/index.d.ts +8 -1
  11. package/dist/components/index.js +1 -43
  12. package/dist/{aria-hKjThHcp.js → compose-ref-ccRU59BM.js} +48 -5
  13. package/dist/control/index.d.ts +2 -0
  14. package/dist/control/index.js +1 -1
  15. package/dist/control-hr3B0QaD.js +211 -0
  16. package/dist/core.d.ts +5 -9
  17. package/dist/csp-nonce-D-XM_uuJ.js +35 -0
  18. package/dist/data/index.js +3 -3
  19. package/dist/{data-2edW0jhF.js → data-BsnOUpQ6.js} +294 -95
  20. package/dist/data-runtime-i-RD0Ffm.js +242 -0
  21. package/dist/{deferred-CbgNhf67.js → deferred-nGZglpj6.js} +42 -20
  22. package/dist/domains/actions.d.ts +8 -3
  23. package/dist/domains/component.d.ts +1 -107
  24. package/dist/domains/context.d.ts +0 -15
  25. package/dist/domains/control.d.ts +36 -249
  26. package/dist/domains/data.d.ts +31 -13
  27. package/dist/domains/diagnostics.d.ts +1 -2
  28. package/dist/domains/lifecycle.d.ts +2 -5
  29. package/dist/domains/refs.d.ts +0 -2
  30. package/dist/domains/routing.d.ts +43 -8
  31. package/dist/domains/scheduler.d.ts +1 -76
  32. package/dist/domains/server.d.ts +5 -2
  33. package/dist/domains/state.d.ts +2 -5
  34. package/dist/domains/telemetry.d.ts +0 -2
  35. package/dist/elements.d.ts +214 -51
  36. package/dist/error-boundary-ChXoIFVl.js +293 -0
  37. package/dist/foundations/icon/index.d.ts +0 -58
  38. package/dist/foundations/icon/index.js +2 -2
  39. package/dist/foundations/index.js +2 -1
  40. package/dist/foundations/interactions/index.js +1 -1
  41. package/dist/foundations/state/index.d.ts +3 -3
  42. package/dist/foundations/state/index.js +5 -3
  43. package/dist/foundations/structures/index.js +2 -1
  44. package/dist/foundations/utilities/index.d.ts +2 -0
  45. package/dist/foundations/utilities/index.js +1 -2
  46. package/dist/fx/index.d.ts +31 -58
  47. package/dist/fx/index.js +313 -195
  48. package/dist/hooks-kjLigwDJ.js +202 -0
  49. package/dist/index.d.ts +11 -74
  50. package/dist/index.js +8 -447
  51. package/dist/instance-DL-YKrj6.js +992 -0
  52. package/dist/{interactions-CTeACdT_.js → interactions-BAa2xuJ-.js} +3 -2
  53. package/dist/jsx-dev-runtime.d.ts +41 -18
  54. package/dist/jsx-dev-runtime.js +1 -6
  55. package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
  56. package/dist/jsx-runtime.js +1 -1
  57. package/dist/jsx.d.ts +61 -37
  58. package/dist/{manifest-D1P3UNWV.js → manifest-BNupb86f.js} +3 -3
  59. package/dist/{navigate-prC5V8XV.js → navigate-DsfO12hB.js} +468 -85
  60. package/dist/navigation.d.ts +12 -3
  61. package/dist/peer-types.d.ts +8 -0
  62. package/dist/portal-LYf4cbHd.js +349 -0
  63. package/dist/promise-Dz8iIHAm.js +16 -0
  64. package/dist/query-registry-tzSiVrV_.js +325 -0
  65. package/dist/readable-DFWOsTac.js +21 -0
  66. package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
  67. package/dist/render-sync-CUxvoVab.js +1256 -0
  68. package/dist/resolution-CF1BqHLm.js +1258 -0
  69. package/dist/resource-BhcaFqdB.js +377 -0
  70. package/dist/resources/index.d.ts +21 -11
  71. package/dist/resources/index.js +65 -266
  72. package/dist/router/index.d.ts +14 -5
  73. package/dist/router/index.js +22 -53
  74. package/dist/scope-ila_zaId.js +55 -0
  75. package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
  76. package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
  77. package/dist/ssg/index.d.ts +1 -2
  78. package/dist/ssg/index.js +43 -22
  79. package/dist/ssr/index.d.ts +26 -28
  80. package/dist/ssr/index.js +4 -4
  81. package/dist/{ssr-CiNm6Vzl.js → ssr-9LOx_bEu.js} +133 -122
  82. package/dist/ssr-DPfdcq0e.js +229 -0
  83. package/dist/state-i9D4EtY6.js +250 -0
  84. package/dist/structures-CkehlOT3.js +231 -0
  85. package/dist/testing/index.d.ts +8 -4
  86. package/dist/testing/index.js +29 -34
  87. package/dist/url-C9xMpMMv.js +185 -0
  88. package/dist/utilities.d.ts +48 -2
  89. package/dist/verify-hydration-D_cyn1OX.js +152 -0
  90. package/package.json +19 -9
  91. package/dist/access-CEA2pOry.js +0 -1046
  92. package/dist/activity-oy2YFTFF.js +0 -201
  93. package/dist/boot-DLplW9h4.js +0 -1104
  94. package/dist/capabilities-Bbf0mlp9.js +0 -42
  95. package/dist/compose-ref-v0qGlHoN.js +0 -26
  96. package/dist/control-BR_mrX__.js +0 -173
  97. package/dist/control-C-ApnFs1.js +0 -20
  98. package/dist/csp-nonce-BfFWcd0w.js +0 -173
  99. package/dist/data-runtime-CxoY98lX.js +0 -149
  100. package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
  101. package/dist/dom-renderer.d.ts +0 -77
  102. package/dist/domains/renderer.d.ts +0 -127
  103. package/dist/eager-control.d.ts +0 -8
  104. package/dist/effect-C3Zsc1k6.js +0 -292
  105. package/dist/for-state-BDykeOJL.js +0 -1753
  106. package/dist/instance-VAFYVJOa.js +0 -1027
  107. package/dist/notify-DxxuDPeY.js +0 -266
  108. package/dist/portal-w3oQ6oQU.js +0 -29
  109. package/dist/query-registry-LrYpQsDJ.js +0 -83
  110. package/dist/render-resolved-BC0W7_5b.js +0 -1123
  111. package/dist/renderer-CT0HeY58.js +0 -8623
  112. package/dist/resolution-3DskUkjG.js +0 -577
  113. package/dist/resource-18-sFRl9.js +0 -344
  114. package/dist/route-matching-CUzZ31gT.js +0 -551
  115. package/dist/router-internal-7nuNEHfG.js +0 -36
  116. package/dist/scope-Cq_iYbTR.js +0 -403
  117. package/dist/selector-BSPVkjKP.js +0 -311
  118. package/dist/ssr-EPjwJH5R.js +0 -29
  119. package/dist/state-BXJfudq1.js +0 -91
  120. package/dist/structures-CjEzfj4h.js +0 -654
  121. package/dist/timer-C7uqnJVt.js +0 -85
  122. package/dist/verify-hydration-ikaxotf7.js +0 -27
  123. package/dist/vnode-D24p6IW2.js +0 -7
@@ -0,0 +1,152 @@
1
+ import { r as validateCspNonce } from "./csp-nonce-D-XM_uuJ.js";
2
+ import { g as withHydrationVerificationRender, v as getHydrationRenderUrl } from "./render-context-DGHnEveC.js";
3
+ import { C as removeRouteBasePath, S as normalizeRouteBasePath, f as currentAuth, n as getRouteRenderContext, y as resolveRouteFromRoutes } from "./resolution-CF1BqHLm.js";
4
+ import { t as SSR_RENDER_DATA_ATTR } from "./ssr-DPfdcq0e.js";
5
+ import { i as StringSink, s as createRenderContext, t as renderSSRRouteAppToSink } from "./render-sync-CUxvoVab.js";
6
+ //#region src/ssr/render-resolved.ts
7
+ function sameRouteParams(left, right) {
8
+ if (!left || !right) return !left && !right;
9
+ const leftKeys = Object.keys(left);
10
+ const rightKeys = Object.keys(right);
11
+ if (leftKeys.length !== rightKeys.length) return false;
12
+ for (const key of leftKeys) if (left[key] !== right[key]) return false;
13
+ return true;
14
+ }
15
+ /** @internal Render a resolved route handler, with the request-local auth context used by hydration verification. */
16
+ function renderResolvedForHydrationSync(opts, authContext) {
17
+ const { url, registry, handler, params, options } = opts;
18
+ const routes = registry.routes;
19
+ const requestUrl = new URL(url, "http://localhost");
20
+ const logicalTarget = removeRouteBasePath(`${requestUrl.pathname}${requestUrl.search}${requestUrl.hash}`, normalizeRouteBasePath(registry.manifest.basePath));
21
+ const matchedIndex = routes.findIndex((route) => {
22
+ if (logicalTarget === void 0) return false;
23
+ const resolved = resolveRouteFromRoutes(new URL(logicalTarget, "http://localhost").pathname, [route]);
24
+ return resolved !== null && resolved.handler === route.handler && sameRouteParams(resolved.params, params ?? {});
25
+ });
26
+ if (matchedIndex < 0) throw new Error(`renderResolvedForHydrationSync: no route found for url: ${url}`);
27
+ const effectiveRoutes = routes.map((route, index) => index === matchedIndex ? {
28
+ ...route,
29
+ handler
30
+ } : route);
31
+ const matchedRoute = routes[matchedIndex];
32
+ const cspNonce = validateCspNonce(options?.cspNonce);
33
+ const ctx = createRenderContext(options?.seed, {
34
+ url,
35
+ basePath: registry.manifest.basePath,
36
+ data: options?.data,
37
+ params,
38
+ routes: effectiveRoutes,
39
+ routeAuth: registry.manifest.auth,
40
+ authContext,
41
+ dataRuntime: options?.dataRuntime,
42
+ envelope: options?.envelope,
43
+ cspNonce
44
+ });
45
+ const sink = new StringSink();
46
+ renderSSRRouteAppToSink({
47
+ route: {
48
+ ...matchedRoute,
49
+ handler
50
+ },
51
+ params: params ?? {},
52
+ data: options?.data,
53
+ ctx,
54
+ sink
55
+ });
56
+ sink.end();
57
+ return sink.toString();
58
+ }
59
+ //#endregion
60
+ //#region src/ssr/verify-hydration.ts
61
+ const SSR_STYLE_REGISTRY_SELECTOR = "style[data-askr-style-registry]";
62
+ const RENDERER_BOOKKEEPING_ATTRS = [
63
+ "data-skip-hydrate",
64
+ "data-key",
65
+ "data-askr-key-kind"
66
+ ];
67
+ /**
68
+ * Parsed declarations in a canonical order. Each parsed longhand is unique, so
69
+ * order carries no meaning here, but the DOM renderer may reorder properties
70
+ * it rewrites.
71
+ */
72
+ function normalizeStyleDeclarations(style) {
73
+ const declarations = [];
74
+ for (let index = 0; index < style.length; index += 1) {
75
+ const name = style.item(index);
76
+ const priority = style.getPropertyPriority(name);
77
+ declarations.push(`${name}: ${style.getPropertyValue(name)}${priority ? ` !${priority}` : ""};`);
78
+ }
79
+ return declarations.sort().join(" ");
80
+ }
81
+ /**
82
+ * Serialize markup in a form that is stable across the SSR serializer and the
83
+ * DOM renderer: transport carriers, comments (range anchors) and the
84
+ * key and `data-skip-hydrate` bookkeeping the renderers add are dropped, and style
85
+ * attributes are re-serialized through the CSSOM so `color:red;` and the
86
+ * DOM's `color: red;` compare equal.
87
+ */
88
+ function normalizeHydrationHtml(html) {
89
+ const template = document.createElement("template");
90
+ template.innerHTML = html;
91
+ for (const carrier of Array.from(template.content.querySelectorAll(`script[${SSR_RENDER_DATA_ATTR}],${SSR_STYLE_REGISTRY_SELECTOR}`))) carrier.remove();
92
+ for (const name of RENDERER_BOOKKEEPING_ATTRS) for (const element of Array.from(template.content.querySelectorAll(`[${name}]`))) element.removeAttribute(name);
93
+ for (const element of Array.from(template.content.querySelectorAll("[style]"))) {
94
+ const style = element.style;
95
+ if (!style) continue;
96
+ const cssText = normalizeStyleDeclarations(style);
97
+ if (cssText) element.setAttribute("style", cssText);
98
+ else element.removeAttribute("style");
99
+ }
100
+ const comments = document.createTreeWalker(template.content, NodeFilter.SHOW_COMMENT);
101
+ const found = [];
102
+ while (comments.nextNode()) found.push(comments.currentNode);
103
+ for (const comment of found) comment.parentNode?.removeChild(comment);
104
+ return template.innerHTML;
105
+ }
106
+ /**
107
+ * Whether the client renders the same URL the server markup was rendered
108
+ * for. A static page opened with a client-only query or hash is verified
109
+ * against its queryless render URL, then hydration applies the browser URL on
110
+ * purpose, so its client output legitimately differs.
111
+ */
112
+ function clientRendersServerUrl(url, envelope) {
113
+ const live = new URL(url, "http://localhost");
114
+ const renderUrl = getHydrationRenderUrl(envelope);
115
+ const rendered = new URL(renderUrl ?? live.pathname, "http://localhost");
116
+ return rendered.search === live.search && rendered.hash === live.hash;
117
+ }
118
+ /**
119
+ * Capture the server markup under `root` before the client renderer touches
120
+ * it, normalized for {@link verifyClientHydrationMarkup}. Returns `null` when
121
+ * the client output is not expected to reproduce it because the page is
122
+ * hydrated at a different URL than it was rendered for.
123
+ */
124
+ function captureServerHydrationMarkup(root, url, envelope) {
125
+ const html = root.innerHTML;
126
+ if (!clientRendersServerUrl(url, envelope)) return null;
127
+ return normalizeHydrationHtml(html);
128
+ }
129
+ /**
130
+ * Whether client markup left by hydration (`clientHtml`) matches the server
131
+ * markup captured before it ran. Hydration reconciles the server DOM in place,
132
+ * so an SSR/client renderer divergence shows up here even when a fresh server
133
+ * render reproduces the server HTML exactly.
134
+ */
135
+ function verifyClientHydrationMarkup(clientHtml, serverMarkup) {
136
+ return normalizeHydrationHtml(clientHtml) === serverMarkup;
137
+ }
138
+ function verifyHydrationSyncForUrl(opts) {
139
+ const { root, url, registry, resolved, options } = opts;
140
+ const verificationUrl = getHydrationRenderUrl(options?.envelope) ?? new URL(url, "http://localhost").pathname;
141
+ const authContext = getRouteRenderContext(resolved)?.auth ?? currentAuth();
142
+ const expected = withHydrationVerificationRender(() => renderResolvedForHydrationSync({
143
+ url: verificationUrl,
144
+ registry,
145
+ handler: resolved.handler,
146
+ params: resolved.params,
147
+ options
148
+ }, authContext));
149
+ return normalizeHydrationHtml(root.innerHTML) === normalizeHydrationHtml(expected);
150
+ }
151
+ //#endregion
152
+ export { captureServerHydrationMarkup, verifyClientHydrationMarkup, verifyHydrationSyncForUrl };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@askrjs/askr",
3
- "version": "0.3.1",
4
- "description": "Lane-scheduled deterministic UI framework",
3
+ "version": "0.4.1",
4
+ "description": "A TypeScript UI runtime with getter-based state, fine-grained bindings, transactional commits with rollback, and one route graph for SPA, SSR, and SSG.",
5
5
  "keywords": [
6
6
  "askr",
7
7
  "framework",
@@ -128,7 +128,7 @@
128
128
  "dev": "vp dev",
129
129
  "fmt": "vp fmt .",
130
130
  "lint": "vp lint src tests test-utils benches && npm run typecheck",
131
- "typecheck": "tsc --noEmit --pretty false",
131
+ "typecheck": "tsc --noEmit --pretty false && tsc --noEmit --pretty false -p test-utils && tsc --noEmit --pretty false -p benches && tsc --noEmit --pretty false -p tests",
132
132
  "test": "npm run test:unit && npm run test:checks && npm run test:jsdom && npm run test:browser",
133
133
  "test:browser": "vp test run -c vitest.test.browser.config.ts tests/browser",
134
134
  "test:checks": "vp test run -c vitest.test.checks.config.ts",
@@ -146,22 +146,32 @@
146
146
  "prepack": "npm run build",
147
147
  "prepublishOnly": "npm run check"
148
148
  },
149
- "dependencies": {
150
- "@askrjs/auth": ">=0.3.0 <0.4.0",
151
- "@askrjs/schema": ">=0.3.0 <0.4.0"
152
- },
153
149
  "devDependencies": {
154
- "@types/node": "^26.4.1",
150
+ "@askrjs/auth": ">=0.4.0 <0.5.0",
151
+ "@askrjs/schema": ">=0.4.0 <0.5.0",
152
+ "@types/node": "^26.6.2",
155
153
  "@typescript/typescript6": "^6.0.2",
156
154
  "@vitest/browser-playwright": "4.1.11",
157
155
  "cross-env": "^10.1.0",
158
- "jsdom": "^30.0.1",
156
+ "jsdom": "^30.1.1",
159
157
  "playwright": "^1.63.0",
160
158
  "publint": "^0.3.24",
161
159
  "tsd": "^0.33.0",
162
160
  "typescript": "^7.0.2",
163
161
  "vite-plus": "^0.3.1"
164
162
  },
163
+ "peerDependencies": {
164
+ "@askrjs/auth": ">=0.4.0 <0.5.0",
165
+ "@askrjs/schema": ">=0.4.0 <0.5.0"
166
+ },
167
+ "peerDependenciesMeta": {
168
+ "@askrjs/auth": {
169
+ "optional": true
170
+ },
171
+ "@askrjs/schema": {
172
+ "optional": true
173
+ }
174
+ },
165
175
  "tsd": {
166
176
  "compilerOptions": {
167
177
  "composite": false,