@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.
- package/CHANGELOG.md +898 -1
- package/README.md +61 -29
- package/capabilities.json +19 -9
- package/dist/actions/index.js +56 -12
- package/dist/benchmark.js +10 -15
- package/dist/boot/index.d.ts +3 -2
- package/dist/boot/index.js +1 -1
- package/dist/boot-C5HnQZio.js +4032 -0
- package/dist/browser-activity-2r5gA1Cb.js +222 -0
- package/dist/components/index.d.ts +8 -1
- package/dist/components/index.js +1 -43
- package/dist/{aria-hKjThHcp.js → compose-ref-ccRU59BM.js} +48 -5
- package/dist/control/index.d.ts +2 -0
- package/dist/control/index.js +1 -1
- package/dist/control-hr3B0QaD.js +211 -0
- package/dist/core.d.ts +5 -9
- package/dist/csp-nonce-D-XM_uuJ.js +35 -0
- package/dist/data/index.js +3 -3
- package/dist/{data-2edW0jhF.js → data-BsnOUpQ6.js} +294 -95
- package/dist/data-runtime-i-RD0Ffm.js +242 -0
- package/dist/{deferred-CbgNhf67.js → deferred-nGZglpj6.js} +42 -20
- package/dist/domains/actions.d.ts +8 -3
- package/dist/domains/component.d.ts +1 -107
- package/dist/domains/context.d.ts +0 -15
- package/dist/domains/control.d.ts +36 -249
- package/dist/domains/data.d.ts +31 -13
- package/dist/domains/diagnostics.d.ts +1 -2
- package/dist/domains/lifecycle.d.ts +2 -5
- package/dist/domains/refs.d.ts +0 -2
- package/dist/domains/routing.d.ts +43 -8
- package/dist/domains/scheduler.d.ts +1 -76
- package/dist/domains/server.d.ts +5 -2
- package/dist/domains/state.d.ts +2 -5
- package/dist/domains/telemetry.d.ts +0 -2
- package/dist/elements.d.ts +214 -51
- package/dist/error-boundary-ChXoIFVl.js +293 -0
- package/dist/foundations/icon/index.d.ts +0 -58
- package/dist/foundations/icon/index.js +2 -2
- package/dist/foundations/index.js +2 -1
- package/dist/foundations/interactions/index.js +1 -1
- package/dist/foundations/state/index.d.ts +3 -3
- package/dist/foundations/state/index.js +5 -3
- package/dist/foundations/structures/index.js +2 -1
- package/dist/foundations/utilities/index.d.ts +2 -0
- package/dist/foundations/utilities/index.js +1 -2
- package/dist/fx/index.d.ts +31 -58
- package/dist/fx/index.js +313 -195
- package/dist/hooks-kjLigwDJ.js +202 -0
- package/dist/index.d.ts +11 -74
- package/dist/index.js +8 -447
- package/dist/instance-DL-YKrj6.js +992 -0
- package/dist/{interactions-CTeACdT_.js → interactions-BAa2xuJ-.js} +3 -2
- package/dist/jsx-dev-runtime.d.ts +41 -18
- package/dist/jsx-dev-runtime.js +1 -6
- package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
- package/dist/jsx-runtime.js +1 -1
- package/dist/jsx.d.ts +61 -37
- package/dist/{manifest-D1P3UNWV.js → manifest-BNupb86f.js} +3 -3
- package/dist/{navigate-prC5V8XV.js → navigate-DsfO12hB.js} +468 -85
- package/dist/navigation.d.ts +12 -3
- package/dist/peer-types.d.ts +8 -0
- package/dist/portal-LYf4cbHd.js +349 -0
- package/dist/promise-Dz8iIHAm.js +16 -0
- package/dist/query-registry-tzSiVrV_.js +325 -0
- package/dist/readable-DFWOsTac.js +21 -0
- package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
- package/dist/render-sync-CUxvoVab.js +1256 -0
- package/dist/resolution-CF1BqHLm.js +1258 -0
- package/dist/resource-BhcaFqdB.js +377 -0
- package/dist/resources/index.d.ts +21 -11
- package/dist/resources/index.js +65 -266
- package/dist/router/index.d.ts +14 -5
- package/dist/router/index.js +22 -53
- package/dist/scope-ila_zaId.js +55 -0
- package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
- package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
- package/dist/ssg/index.d.ts +1 -2
- package/dist/ssg/index.js +43 -22
- package/dist/ssr/index.d.ts +26 -28
- package/dist/ssr/index.js +4 -4
- package/dist/{ssr-CiNm6Vzl.js → ssr-9LOx_bEu.js} +133 -122
- package/dist/ssr-DPfdcq0e.js +229 -0
- package/dist/state-i9D4EtY6.js +250 -0
- package/dist/structures-CkehlOT3.js +231 -0
- package/dist/testing/index.d.ts +8 -4
- package/dist/testing/index.js +29 -34
- package/dist/url-C9xMpMMv.js +185 -0
- package/dist/utilities.d.ts +48 -2
- package/dist/verify-hydration-D_cyn1OX.js +152 -0
- package/package.json +19 -9
- package/dist/access-CEA2pOry.js +0 -1046
- package/dist/activity-oy2YFTFF.js +0 -201
- package/dist/boot-DLplW9h4.js +0 -1104
- package/dist/capabilities-Bbf0mlp9.js +0 -42
- package/dist/compose-ref-v0qGlHoN.js +0 -26
- package/dist/control-BR_mrX__.js +0 -173
- package/dist/control-C-ApnFs1.js +0 -20
- package/dist/csp-nonce-BfFWcd0w.js +0 -173
- package/dist/data-runtime-CxoY98lX.js +0 -149
- package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
- package/dist/dom-renderer.d.ts +0 -77
- package/dist/domains/renderer.d.ts +0 -127
- package/dist/eager-control.d.ts +0 -8
- package/dist/effect-C3Zsc1k6.js +0 -292
- package/dist/for-state-BDykeOJL.js +0 -1753
- package/dist/instance-VAFYVJOa.js +0 -1027
- package/dist/notify-DxxuDPeY.js +0 -266
- package/dist/portal-w3oQ6oQU.js +0 -29
- package/dist/query-registry-LrYpQsDJ.js +0 -83
- package/dist/render-resolved-BC0W7_5b.js +0 -1123
- package/dist/renderer-CT0HeY58.js +0 -8623
- package/dist/resolution-3DskUkjG.js +0 -577
- package/dist/resource-18-sFRl9.js +0 -344
- package/dist/route-matching-CUzZ31gT.js +0 -551
- package/dist/router-internal-7nuNEHfG.js +0 -36
- package/dist/scope-Cq_iYbTR.js +0 -403
- package/dist/selector-BSPVkjKP.js +0 -311
- package/dist/ssr-EPjwJH5R.js +0 -29
- package/dist/state-BXJfudq1.js +0 -91
- package/dist/structures-CjEzfj4h.js +0 -654
- package/dist/timer-C7uqnJVt.js +0 -85
- package/dist/verify-hydration-ikaxotf7.js +0 -27
- 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.
|
|
4
|
-
"description": "
|
|
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
|
-
"@
|
|
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.
|
|
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,
|