@bquery/bquery 1.7.0 → 1.8.2
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 +760 -716
- package/dist/{a11y-C5QOVvRn.js → a11y-DVBCy09c.js} +3 -3
- package/dist/a11y-DVBCy09c.js.map +1 -0
- package/dist/a11y.es.mjs +1 -1
- package/dist/component/library.d.ts.map +1 -1
- package/dist/{component-CuuTijA6.js → component-L3-JfOFz.js} +5 -5
- package/dist/component-L3-JfOFz.js.map +1 -0
- package/dist/component.es.mjs +1 -1
- package/dist/{config-BW35FKuA.js → config-DhT9auRm.js} +1 -1
- package/dist/{config-BW35FKuA.js.map → config-DhT9auRm.js.map} +1 -1
- package/dist/{constraints-3lV9yyBw.js → constraints-D5RHQLmP.js} +1 -1
- package/dist/constraints-D5RHQLmP.js.map +1 -0
- package/dist/core/collection.d.ts +86 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/element.d.ts +28 -0
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/shared.d.ts +6 -0
- package/dist/core/shared.d.ts.map +1 -1
- package/dist/core-DdtZHzsS.js +168 -0
- package/dist/core-DdtZHzsS.js.map +1 -0
- package/dist/{core-Cjl7GUu8.js → core-EMYSLzaT.js} +289 -259
- package/dist/core-EMYSLzaT.js.map +1 -0
- package/dist/core.es.mjs +48 -47
- package/dist/{custom-directives-7wAShnnd.js → custom-directives-Dr4C5lVV.js} +1 -1
- package/dist/custom-directives-Dr4C5lVV.js.map +1 -0
- package/dist/{devtools-D2fQLhDN.js → devtools-BhB2iDPT.js} +2 -2
- package/dist/devtools-BhB2iDPT.js.map +1 -0
- package/dist/devtools.es.mjs +1 -1
- package/dist/{dnd-B8EgyzaI.js → dnd-NwZBYh4l.js} +1 -1
- package/dist/dnd-NwZBYh4l.js.map +1 -0
- package/dist/dnd.es.mjs +1 -1
- package/dist/{env-NeVmr4Gf.js → env-CTdvLaH2.js} +1 -1
- package/dist/env-CTdvLaH2.js.map +1 -0
- package/dist/forms/create-form.d.ts.map +1 -1
- package/dist/forms/index.d.ts +3 -2
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/types.d.ts +46 -0
- package/dist/forms/types.d.ts.map +1 -1
- package/dist/forms/use-field.d.ts +34 -0
- package/dist/forms/use-field.d.ts.map +1 -0
- package/dist/forms/validators.d.ts +25 -0
- package/dist/forms/validators.d.ts.map +1 -1
- package/dist/forms-UcRHsYxC.js +227 -0
- package/dist/forms-UcRHsYxC.js.map +1 -0
- package/dist/forms.es.mjs +14 -12
- package/dist/full.d.ts +17 -26
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +206 -181
- package/dist/full.iife.js +33 -33
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +33 -33
- package/dist/full.umd.js.map +1 -1
- package/dist/function-Cybd57JV.js +33 -0
- package/dist/function-Cybd57JV.js.map +1 -0
- package/dist/{i18n-BnnhTFOS.js → i18n-kuF6Ekj6.js} +3 -3
- package/dist/i18n-kuF6Ekj6.js.map +1 -0
- package/dist/i18n.es.mjs +1 -1
- package/dist/index.es.mjs +251 -228
- package/dist/media/breakpoints.d.ts.map +1 -1
- package/dist/media/types.d.ts +2 -2
- package/dist/media/types.d.ts.map +1 -1
- package/dist/{media-Di2Ta22s.js → media-i-fB5WxI.js} +3 -3
- package/dist/media-i-fB5WxI.js.map +1 -0
- package/dist/media.es.mjs +1 -1
- package/dist/{motion-qPj_TYGv.js → motion-BJsAuULb.js} +2 -2
- package/dist/motion-BJsAuULb.js.map +1 -0
- package/dist/motion.es.mjs +1 -1
- package/dist/{mount-SM07RUa6.js → mount-B4Y8bk8Z.js} +5 -5
- package/dist/mount-B4Y8bk8Z.js.map +1 -0
- package/dist/{platform-CPbCprb6.js → platform-Dw2gE3zI.js} +3 -3
- package/dist/{platform-CPbCprb6.js.map → platform-Dw2gE3zI.js.map} +1 -1
- package/dist/platform.es.mjs +2 -2
- package/dist/plugin/registry.d.ts.map +1 -1
- package/dist/{plugin-cPoOHFLY.js → plugin-C2WuC8SF.js} +20 -18
- package/dist/plugin-C2WuC8SF.js.map +1 -0
- package/dist/plugin.es.mjs +1 -1
- package/dist/reactive/async-data.d.ts +28 -3
- package/dist/reactive/async-data.d.ts.map +1 -1
- package/dist/reactive/computed.d.ts +3 -0
- package/dist/reactive/computed.d.ts.map +1 -1
- package/dist/reactive/effect.d.ts +3 -0
- package/dist/reactive/effect.d.ts.map +1 -1
- package/dist/reactive/http.d.ts +194 -0
- package/dist/reactive/http.d.ts.map +1 -0
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.d.ts.map +1 -1
- package/dist/reactive/pagination.d.ts +126 -0
- package/dist/reactive/pagination.d.ts.map +1 -0
- package/dist/reactive/polling.d.ts +55 -0
- package/dist/reactive/polling.d.ts.map +1 -0
- package/dist/reactive/readonly.d.ts +20 -1
- package/dist/reactive/readonly.d.ts.map +1 -1
- package/dist/reactive/rest.d.ts +293 -0
- package/dist/reactive/rest.d.ts.map +1 -0
- package/dist/reactive/scope.d.ts +140 -0
- package/dist/reactive/scope.d.ts.map +1 -0
- package/dist/reactive/signal.d.ts +16 -2
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive/to-value.d.ts +57 -0
- package/dist/reactive/to-value.d.ts.map +1 -0
- package/dist/reactive/websocket.d.ts +285 -0
- package/dist/reactive/websocket.d.ts.map +1 -0
- package/dist/reactive-DwkhUJfP.js +1148 -0
- package/dist/reactive-DwkhUJfP.js.map +1 -0
- package/dist/reactive.es.mjs +38 -19
- package/dist/{registry-CWf368tT.js → registry-B08iilIh.js} +1 -1
- package/dist/{registry-CWf368tT.js.map → registry-B08iilIh.js.map} +1 -1
- package/dist/router/constraints.d.ts.map +1 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/state.d.ts +25 -2
- package/dist/router/state.d.ts.map +1 -1
- package/dist/router-CQikC9Ed.js +492 -0
- package/dist/router-CQikC9Ed.js.map +1 -0
- package/dist/router.es.mjs +9 -8
- package/dist/ssr/hydrate.d.ts.map +1 -1
- package/dist/{ssr-B2qd_WBB.js → ssr-_dAcGdzu.js} +4 -4
- package/dist/ssr-_dAcGdzu.js.map +1 -0
- package/dist/ssr.es.mjs +1 -1
- package/dist/store/persisted.d.ts.map +1 -1
- package/dist/{store-DWpyH6p5.js → store-Cb3gPRve.js} +7 -7
- package/dist/store-Cb3gPRve.js.map +1 -0
- package/dist/store.es.mjs +2 -2
- package/dist/storybook.es.mjs.map +1 -1
- package/dist/{testing-CsqjNUyy.js → testing-C5Sjfsna.js} +8 -8
- package/dist/testing-C5Sjfsna.js.map +1 -0
- package/dist/testing.es.mjs +1 -1
- package/dist/{type-guards-Do9DWgNp.js → type-guards-BMX2c0LP.js} +1 -1
- package/dist/{type-guards-Do9DWgNp.js.map → type-guards-BMX2c0LP.js.map} +1 -1
- package/dist/untrack-D0fnO5k2.js +36 -0
- package/dist/untrack-D0fnO5k2.js.map +1 -0
- package/dist/view/custom-directives.d.ts.map +1 -1
- package/dist/view.es.mjs +4 -4
- package/package.json +178 -177
- package/src/a11y/announce.ts +131 -131
- package/src/a11y/audit.ts +314 -314
- package/src/a11y/index.ts +68 -68
- package/src/a11y/media-preferences.ts +255 -255
- package/src/a11y/roving-tab-index.ts +164 -164
- package/src/a11y/skip-link.ts +255 -255
- package/src/a11y/trap-focus.ts +184 -184
- package/src/a11y/types.ts +183 -183
- package/src/component/component.ts +599 -599
- package/src/component/html.ts +153 -153
- package/src/component/index.ts +52 -52
- package/src/component/library.ts +540 -542
- package/src/component/scope.ts +212 -212
- package/src/component/types.ts +310 -310
- package/src/core/collection.ts +876 -707
- package/src/core/element.ts +1015 -981
- package/src/core/env.ts +60 -60
- package/src/core/index.ts +49 -49
- package/src/core/shared.ts +77 -62
- package/src/core/utils/index.ts +148 -148
- package/src/devtools/devtools.ts +410 -410
- package/src/devtools/index.ts +48 -48
- package/src/devtools/types.ts +104 -104
- package/src/dnd/draggable.ts +296 -296
- package/src/dnd/droppable.ts +228 -228
- package/src/dnd/index.ts +62 -62
- package/src/dnd/sortable.ts +307 -307
- package/src/dnd/types.ts +293 -293
- package/src/forms/create-form.ts +320 -278
- package/src/forms/index.ts +70 -65
- package/src/forms/types.ts +203 -154
- package/src/forms/use-field.ts +231 -0
- package/src/forms/validators.ts +294 -265
- package/src/full.ts +554 -480
- package/src/i18n/formatting.ts +67 -67
- package/src/i18n/i18n.ts +200 -200
- package/src/i18n/index.ts +67 -67
- package/src/i18n/translate.ts +182 -182
- package/src/i18n/types.ts +171 -171
- package/src/index.ts +108 -108
- package/src/media/battery.ts +116 -116
- package/src/media/breakpoints.ts +129 -131
- package/src/media/clipboard.ts +80 -80
- package/src/media/device-sensors.ts +158 -158
- package/src/media/geolocation.ts +119 -119
- package/src/media/index.ts +76 -76
- package/src/media/media-query.ts +92 -92
- package/src/media/network.ts +115 -115
- package/src/media/types.ts +177 -177
- package/src/media/viewport.ts +84 -84
- package/src/motion/index.ts +57 -57
- package/src/motion/morph.ts +151 -151
- package/src/motion/parallax.ts +120 -120
- package/src/motion/reduced-motion.ts +66 -66
- package/src/motion/types.ts +271 -271
- package/src/motion/typewriter.ts +164 -164
- package/src/plugin/index.ts +37 -37
- package/src/plugin/registry.ts +284 -269
- package/src/plugin/types.ts +137 -137
- package/src/reactive/async-data.ts +250 -29
- package/src/reactive/computed.ts +144 -130
- package/src/reactive/effect.ts +29 -6
- package/src/reactive/http.ts +790 -0
- package/src/reactive/index.ts +60 -0
- package/src/reactive/pagination.ts +317 -0
- package/src/reactive/polling.ts +179 -0
- package/src/reactive/readonly.ts +52 -8
- package/src/reactive/rest.ts +859 -0
- package/src/reactive/scope.ts +276 -0
- package/src/reactive/signal.ts +61 -1
- package/src/reactive/to-value.ts +71 -0
- package/src/reactive/websocket.ts +849 -0
- package/src/router/bq-link.ts +279 -279
- package/src/router/constraints.ts +204 -201
- package/src/router/index.ts +49 -49
- package/src/router/match.ts +312 -312
- package/src/router/path-pattern.ts +52 -52
- package/src/router/query.ts +38 -38
- package/src/router/router.ts +421 -402
- package/src/router/state.ts +51 -3
- package/src/router/types.ts +139 -139
- package/src/router/use-route.ts +68 -68
- package/src/router/utils.ts +157 -157
- package/src/security/index.ts +12 -12
- package/src/ssr/hydrate.ts +84 -82
- package/src/ssr/index.ts +70 -70
- package/src/ssr/render.ts +508 -508
- package/src/ssr/serialize.ts +296 -296
- package/src/ssr/types.ts +81 -81
- package/src/store/create-store.ts +467 -467
- package/src/store/index.ts +27 -27
- package/src/store/persisted.ts +245 -249
- package/src/store/types.ts +247 -247
- package/src/store/utils.ts +135 -135
- package/src/storybook/index.ts +480 -480
- package/src/testing/index.ts +42 -42
- package/src/testing/testing.ts +593 -593
- package/src/testing/types.ts +170 -170
- package/src/view/custom-directives.ts +28 -30
- package/src/view/evaluate.ts +292 -292
- package/src/view/process.ts +108 -108
- package/dist/a11y-C5QOVvRn.js.map +0 -1
- package/dist/component-CuuTijA6.js.map +0 -1
- package/dist/constraints-3lV9yyBw.js.map +0 -1
- package/dist/core-Cjl7GUu8.js.map +0 -1
- package/dist/core-DnlyjbF2.js +0 -112
- package/dist/core-DnlyjbF2.js.map +0 -1
- package/dist/custom-directives-7wAShnnd.js.map +0 -1
- package/dist/devtools-D2fQLhDN.js.map +0 -1
- package/dist/dnd-B8EgyzaI.js.map +0 -1
- package/dist/env-NeVmr4Gf.js.map +0 -1
- package/dist/forms-C3yovgH9.js +0 -141
- package/dist/forms-C3yovgH9.js.map +0 -1
- package/dist/i18n-BnnhTFOS.js.map +0 -1
- package/dist/media-Di2Ta22s.js.map +0 -1
- package/dist/motion-qPj_TYGv.js.map +0 -1
- package/dist/mount-SM07RUa6.js.map +0 -1
- package/dist/plugin-cPoOHFLY.js.map +0 -1
- package/dist/reactive-Cfv0RK6x.js +0 -233
- package/dist/reactive-Cfv0RK6x.js.map +0 -1
- package/dist/router-BrthaP_z.js +0 -473
- package/dist/router-BrthaP_z.js.map +0 -1
- package/dist/ssr-B2qd_WBB.js.map +0 -1
- package/dist/store-DWpyH6p5.js.map +0 -1
- package/dist/testing-CsqjNUyy.js.map +0 -1
- package/dist/untrack-DJVQQ2WM.js +0 -33
- package/dist/untrack-DJVQQ2WM.js.map +0 -1
package/src/router/utils.ts
CHANGED
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Router utilities.
|
|
3
|
-
* @module bquery/router
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { computed, type ReadonlySignal } from '../reactive/index';
|
|
7
|
-
import { getRouteConstraintRegex } from './constraints';
|
|
8
|
-
import { isParamChar, isParamStart, readConstraint } from './path-pattern';
|
|
9
|
-
import { getActiveRouter, routeSignal } from './state';
|
|
10
|
-
import type { RouteDefinition } from './types';
|
|
11
|
-
|
|
12
|
-
// ============================================================================
|
|
13
|
-
// Utilities
|
|
14
|
-
// ============================================================================
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Flattens nested routes into a single array with full paths.
|
|
18
|
-
* Does NOT include the router base - base is only for browser history.
|
|
19
|
-
* @internal
|
|
20
|
-
*/
|
|
21
|
-
export const flattenRoutes = (routes: RouteDefinition[], parentPath = ''): RouteDefinition[] => {
|
|
22
|
-
const result: RouteDefinition[] = [];
|
|
23
|
-
|
|
24
|
-
for (const route of routes) {
|
|
25
|
-
const fullPath = route.path === '*' ? '*' : `${parentPath}${route.path}`.replace(/\/+/g, '/');
|
|
26
|
-
|
|
27
|
-
result.push({
|
|
28
|
-
...route,
|
|
29
|
-
path: fullPath,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
if (route.children) {
|
|
33
|
-
result.push(...flattenRoutes(route.children, fullPath));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return result;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Resolves a route by name and params.
|
|
42
|
-
*
|
|
43
|
-
* @param name - The route name
|
|
44
|
-
* @param params - Route params to interpolate
|
|
45
|
-
* @returns The resolved path
|
|
46
|
-
* @throws {Error} If no router is initialized, the route name is unknown,
|
|
47
|
-
* a required path param is missing from `params`, a param value does not satisfy
|
|
48
|
-
* its route regex constraint, or a route param constraint has invalid syntax
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```ts
|
|
52
|
-
* import { resolve } from 'bquery/router';
|
|
53
|
-
*
|
|
54
|
-
* const path = resolve('user', { id: '42' });
|
|
55
|
-
* // Returns '/user/42' if route is defined as { name: 'user', path: '/user/:id' }
|
|
56
|
-
* ```
|
|
57
|
-
*/
|
|
58
|
-
export const resolve = (name: string, params: Record<string, string> = {}): string => {
|
|
59
|
-
const activeRouter = getActiveRouter();
|
|
60
|
-
if (!activeRouter) {
|
|
61
|
-
throw new Error('bQuery router: No router initialized.');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const route = activeRouter.routes.find((r) => r.name === name);
|
|
65
|
-
if (!route) {
|
|
66
|
-
throw new Error(`bQuery router: Route "${name}" not found.`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let path = '';
|
|
70
|
-
for (let i = 0; i < route.path.length; ) {
|
|
71
|
-
if (route.path[i] === ':' && isParamStart(route.path[i + 1])) {
|
|
72
|
-
let nameEnd = i + 2;
|
|
73
|
-
while (nameEnd < route.path.length && isParamChar(route.path[nameEnd])) {
|
|
74
|
-
nameEnd++;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
let nextIndex = nameEnd;
|
|
78
|
-
let constraint: string | null = null;
|
|
79
|
-
if (route.path[nameEnd] === '(') {
|
|
80
|
-
const parsedConstraint = readConstraint(route.path, nameEnd);
|
|
81
|
-
if (!parsedConstraint) {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`bQuery router: Invalid constraint syntax in path "${route.path}" for route "${name}".`
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
constraint = parsedConstraint.constraint;
|
|
87
|
-
nextIndex = parsedConstraint.endIndex;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const key = route.path.slice(i + 1, nameEnd);
|
|
91
|
-
const value = params[key];
|
|
92
|
-
if (value === undefined) {
|
|
93
|
-
throw new Error(`bQuery router: Missing required param "${key}" for route "${name}".`);
|
|
94
|
-
}
|
|
95
|
-
if (constraint && !getRouteConstraintRegex(constraint).test(value)) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`bQuery router: Param "${key}" with value "${value}" does not satisfy the route constraint "${constraint}" for route "${name}".`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
path += encodeURIComponent(value);
|
|
102
|
-
i = nextIndex;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
path += route.path[i];
|
|
107
|
-
i++;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return path;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Checks if a path matches the current route.
|
|
115
|
-
*
|
|
116
|
-
* @param path - Path to check
|
|
117
|
-
* @param exact - Whether to match exactly (default: false)
|
|
118
|
-
* @returns True if the path matches
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* ```ts
|
|
122
|
-
* import { isActive } from 'bquery/router';
|
|
123
|
-
*
|
|
124
|
-
* if (isActive('/dashboard')) {
|
|
125
|
-
* // Highlight nav item
|
|
126
|
-
* }
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
|
-
export const isActive = (path: string, exact = false): boolean => {
|
|
130
|
-
const current = routeSignal.value.path;
|
|
131
|
-
return exact ? current === path : current.startsWith(path);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Creates a computed signal that checks if a path is active.
|
|
136
|
-
*
|
|
137
|
-
* @param path - Path to check
|
|
138
|
-
* @param exact - Whether to match exactly
|
|
139
|
-
* @returns A reactive signal
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
|
-
* ```ts
|
|
143
|
-
* import { isActiveSignal } from 'bquery/router';
|
|
144
|
-
* import { effect } from 'bquery/reactive';
|
|
145
|
-
*
|
|
146
|
-
* const dashboardActive = isActiveSignal('/dashboard');
|
|
147
|
-
* effect(() => {
|
|
148
|
-
* navItem.classList.toggle('active', dashboardActive.value);
|
|
149
|
-
* });
|
|
150
|
-
* ```
|
|
151
|
-
*/
|
|
152
|
-
export const isActiveSignal = (path: string, exact = false): ReadonlySignal<boolean> => {
|
|
153
|
-
return computed(() => {
|
|
154
|
-
const current = routeSignal.value.path;
|
|
155
|
-
return exact ? current === path : current.startsWith(path);
|
|
156
|
-
});
|
|
157
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Router utilities.
|
|
3
|
+
* @module bquery/router
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { computed, type ReadonlySignal } from '../reactive/index';
|
|
7
|
+
import { getRouteConstraintRegex } from './constraints';
|
|
8
|
+
import { isParamChar, isParamStart, readConstraint } from './path-pattern';
|
|
9
|
+
import { getActiveRouter, routeSignal } from './state';
|
|
10
|
+
import type { RouteDefinition } from './types';
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Utilities
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Flattens nested routes into a single array with full paths.
|
|
18
|
+
* Does NOT include the router base - base is only for browser history.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export const flattenRoutes = (routes: RouteDefinition[], parentPath = ''): RouteDefinition[] => {
|
|
22
|
+
const result: RouteDefinition[] = [];
|
|
23
|
+
|
|
24
|
+
for (const route of routes) {
|
|
25
|
+
const fullPath = route.path === '*' ? '*' : `${parentPath}${route.path}`.replace(/\/+/g, '/');
|
|
26
|
+
|
|
27
|
+
result.push({
|
|
28
|
+
...route,
|
|
29
|
+
path: fullPath,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (route.children) {
|
|
33
|
+
result.push(...flattenRoutes(route.children, fullPath));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolves a route by name and params.
|
|
42
|
+
*
|
|
43
|
+
* @param name - The route name
|
|
44
|
+
* @param params - Route params to interpolate
|
|
45
|
+
* @returns The resolved path
|
|
46
|
+
* @throws {Error} If no router is initialized, the route name is unknown,
|
|
47
|
+
* a required path param is missing from `params`, a param value does not satisfy
|
|
48
|
+
* its route regex constraint, or a route param constraint has invalid syntax
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { resolve } from 'bquery/router';
|
|
53
|
+
*
|
|
54
|
+
* const path = resolve('user', { id: '42' });
|
|
55
|
+
* // Returns '/user/42' if route is defined as { name: 'user', path: '/user/:id' }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const resolve = (name: string, params: Record<string, string> = {}): string => {
|
|
59
|
+
const activeRouter = getActiveRouter();
|
|
60
|
+
if (!activeRouter) {
|
|
61
|
+
throw new Error('bQuery router: No router initialized.');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const route = activeRouter.routes.find((r) => r.name === name);
|
|
65
|
+
if (!route) {
|
|
66
|
+
throw new Error(`bQuery router: Route "${name}" not found.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let path = '';
|
|
70
|
+
for (let i = 0; i < route.path.length; ) {
|
|
71
|
+
if (route.path[i] === ':' && isParamStart(route.path[i + 1])) {
|
|
72
|
+
let nameEnd = i + 2;
|
|
73
|
+
while (nameEnd < route.path.length && isParamChar(route.path[nameEnd])) {
|
|
74
|
+
nameEnd++;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let nextIndex = nameEnd;
|
|
78
|
+
let constraint: string | null = null;
|
|
79
|
+
if (route.path[nameEnd] === '(') {
|
|
80
|
+
const parsedConstraint = readConstraint(route.path, nameEnd);
|
|
81
|
+
if (!parsedConstraint) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`bQuery router: Invalid constraint syntax in path "${route.path}" for route "${name}".`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
constraint = parsedConstraint.constraint;
|
|
87
|
+
nextIndex = parsedConstraint.endIndex;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const key = route.path.slice(i + 1, nameEnd);
|
|
91
|
+
const value = params[key];
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
throw new Error(`bQuery router: Missing required param "${key}" for route "${name}".`);
|
|
94
|
+
}
|
|
95
|
+
if (constraint && !getRouteConstraintRegex(constraint).test(value)) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`bQuery router: Param "${key}" with value "${value}" does not satisfy the route constraint "${constraint}" for route "${name}".`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
path += encodeURIComponent(value);
|
|
102
|
+
i = nextIndex;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
path += route.path[i];
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return path;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Checks if a path matches the current route.
|
|
115
|
+
*
|
|
116
|
+
* @param path - Path to check
|
|
117
|
+
* @param exact - Whether to match exactly (default: false)
|
|
118
|
+
* @returns True if the path matches
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* import { isActive } from 'bquery/router';
|
|
123
|
+
*
|
|
124
|
+
* if (isActive('/dashboard')) {
|
|
125
|
+
* // Highlight nav item
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export const isActive = (path: string, exact = false): boolean => {
|
|
130
|
+
const current = routeSignal.value.path;
|
|
131
|
+
return exact ? current === path : current.startsWith(path);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Creates a computed signal that checks if a path is active.
|
|
136
|
+
*
|
|
137
|
+
* @param path - Path to check
|
|
138
|
+
* @param exact - Whether to match exactly
|
|
139
|
+
* @returns A reactive signal
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import { isActiveSignal } from 'bquery/router';
|
|
144
|
+
* import { effect } from 'bquery/reactive';
|
|
145
|
+
*
|
|
146
|
+
* const dashboardActive = isActiveSignal('/dashboard');
|
|
147
|
+
* effect(() => {
|
|
148
|
+
* navItem.classList.toggle('active', dashboardActive.value);
|
|
149
|
+
* });
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export const isActiveSignal = (path: string, exact = false): ReadonlySignal<boolean> => {
|
|
153
|
+
return computed(() => {
|
|
154
|
+
const current = routeSignal.value.path;
|
|
155
|
+
return exact ? current === path : current.startsWith(path);
|
|
156
|
+
});
|
|
157
|
+
};
|
package/src/security/index.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Security module providing sanitization, CSP compatibility, and Trusted Types.
|
|
3
|
-
*
|
|
4
|
-
* @module bquery/security
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export { generateNonce, hasCSPDirective } from './csp';
|
|
8
|
-
export { escapeHtml, sanitizeHtml as sanitize, sanitizeHtml, stripTags } from './sanitize';
|
|
9
|
-
export { trusted } from './trusted-html';
|
|
10
|
-
export { createTrustedHtml, getTrustedTypesPolicy, isTrustedTypesSupported } from './trusted-types';
|
|
11
|
-
export type { SanitizedHtml, TrustedHtml } from './trusted-html';
|
|
12
|
-
export type { SanitizeOptions } from './types';
|
|
1
|
+
/**
|
|
2
|
+
* Security module providing sanitization, CSP compatibility, and Trusted Types.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/security
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { generateNonce, hasCSPDirective } from './csp';
|
|
8
|
+
export { escapeHtml, sanitizeHtml as sanitize, sanitizeHtml, stripTags } from './sanitize';
|
|
9
|
+
export { trusted } from './trusted-html';
|
|
10
|
+
export { createTrustedHtml, getTrustedTypesPolicy, isTrustedTypesSupported } from './trusted-types';
|
|
11
|
+
export type { SanitizedHtml, TrustedHtml } from './trusted-html';
|
|
12
|
+
export type { SanitizeOptions } from './types';
|
package/src/ssr/hydrate.ts
CHANGED
|
@@ -1,82 +1,84 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hydration support for server-rendered DOM.
|
|
3
|
-
*
|
|
4
|
-
* Enables the client-side view system to reuse existing server-rendered DOM
|
|
5
|
-
* elements instead of re-rendering them, by attaching reactive bindings
|
|
6
|
-
* to the pre-existing DOM structure.
|
|
7
|
-
*
|
|
8
|
-
* @module bquery/ssr
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type { BindingContext, MountOptions, View } from '../view/types';
|
|
12
|
-
import { mount } from '../view/mount';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Extended mount options that include hydration mode.
|
|
16
|
-
*/
|
|
17
|
-
export type HydrateMountOptions = MountOptions & {
|
|
18
|
-
/**
|
|
19
|
-
* When present, must be `true` so the mount operation reuses existing DOM elements
|
|
20
|
-
* instead of re-rendering them. Reactive bindings (effects) are
|
|
21
|
-
* still attached so the DOM updates reactively from that point on.
|
|
22
|
-
*
|
|
23
|
-
* @default true
|
|
24
|
-
*/
|
|
25
|
-
hydrate?: true;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Mounts a reactive view with optional hydration support.
|
|
30
|
-
*
|
|
31
|
-
* When `hydrate: true` is set, the existing server-rendered DOM is preserved
|
|
32
|
-
* and reactive bindings are attached on top. The DOM is NOT re-rendered;
|
|
33
|
-
* instead, effects begin tracking signals so future changes update the DOM.
|
|
34
|
-
*
|
|
35
|
-
* This is the client-side counterpart to `renderToString()`. The typical flow:
|
|
36
|
-
* 1. Server: `renderToString(template, data)` → send HTML to client
|
|
37
|
-
* 2. Client: `hydrateMount('#app', reactiveContext, { hydrate: true })`
|
|
38
|
-
*
|
|
39
|
-
* Under the hood, `hydrateMount` simply delegates to the standard `mount()`
|
|
40
|
-
* function. The `mount()` function already processes existing DOM elements
|
|
41
|
-
* and attaches reactive effects to them — it does not clear/replace content.
|
|
42
|
-
* The `hydrate` flag is a semantic marker indicating developer intent and
|
|
43
|
-
* ensures the existing DOM structure is preserved.
|
|
44
|
-
*
|
|
45
|
-
* @param selector - CSS selector or Element to hydrate
|
|
46
|
-
* @param context - Binding context with signals, computed values, and functions
|
|
47
|
-
* @param options - Mount options with `hydrate: true`
|
|
48
|
-
* @returns The mounted View instance
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```ts
|
|
52
|
-
* import { hydrateMount } from '@bquery/bquery/ssr';
|
|
53
|
-
* import { signal, computed } from '@bquery/bquery/reactive';
|
|
54
|
-
*
|
|
55
|
-
* // Server rendered:
|
|
56
|
-
* // <div id="app"><h1>Welcome</h1><p>Hello, World!</p></div>
|
|
57
|
-
*
|
|
58
|
-
* // Client hydration — attaches reactivity to existing DOM:
|
|
59
|
-
* const name = signal('World');
|
|
60
|
-
* const greeting = computed(() => `Hello, ${name.value}!`);
|
|
61
|
-
*
|
|
62
|
-
* const view = hydrateMount('#app', { name, greeting }, { hydrate: true });
|
|
63
|
-
*
|
|
64
|
-
* // Now updating `name.value` will reactively update the DOM
|
|
65
|
-
* name.value = 'Alice'; // <p> updates to "Hello, Alice!"
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
export const hydrateMount = (
|
|
69
|
-
selector: string | Element,
|
|
70
|
-
context: BindingContext,
|
|
71
|
-
options: HydrateMountOptions = {}
|
|
72
|
-
): View => {
|
|
73
|
-
const { hydrate = true, ...mountOptions } = options;
|
|
74
|
-
|
|
75
|
-
if (!hydrate) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Hydration support for server-rendered DOM.
|
|
3
|
+
*
|
|
4
|
+
* Enables the client-side view system to reuse existing server-rendered DOM
|
|
5
|
+
* elements instead of re-rendering them, by attaching reactive bindings
|
|
6
|
+
* to the pre-existing DOM structure.
|
|
7
|
+
*
|
|
8
|
+
* @module bquery/ssr
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { BindingContext, MountOptions, View } from '../view/types';
|
|
12
|
+
import { mount } from '../view/mount';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extended mount options that include hydration mode.
|
|
16
|
+
*/
|
|
17
|
+
export type HydrateMountOptions = MountOptions & {
|
|
18
|
+
/**
|
|
19
|
+
* When present, must be `true` so the mount operation reuses existing DOM elements
|
|
20
|
+
* instead of re-rendering them. Reactive bindings (effects) are
|
|
21
|
+
* still attached so the DOM updates reactively from that point on.
|
|
22
|
+
*
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
hydrate?: true;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Mounts a reactive view with optional hydration support.
|
|
30
|
+
*
|
|
31
|
+
* When `hydrate: true` is set, the existing server-rendered DOM is preserved
|
|
32
|
+
* and reactive bindings are attached on top. The DOM is NOT re-rendered;
|
|
33
|
+
* instead, effects begin tracking signals so future changes update the DOM.
|
|
34
|
+
*
|
|
35
|
+
* This is the client-side counterpart to `renderToString()`. The typical flow:
|
|
36
|
+
* 1. Server: `renderToString(template, data)` → send HTML to client
|
|
37
|
+
* 2. Client: `hydrateMount('#app', reactiveContext, { hydrate: true })`
|
|
38
|
+
*
|
|
39
|
+
* Under the hood, `hydrateMount` simply delegates to the standard `mount()`
|
|
40
|
+
* function. The `mount()` function already processes existing DOM elements
|
|
41
|
+
* and attaches reactive effects to them — it does not clear/replace content.
|
|
42
|
+
* The `hydrate` flag is a semantic marker indicating developer intent and
|
|
43
|
+
* ensures the existing DOM structure is preserved.
|
|
44
|
+
*
|
|
45
|
+
* @param selector - CSS selector or Element to hydrate
|
|
46
|
+
* @param context - Binding context with signals, computed values, and functions
|
|
47
|
+
* @param options - Mount options with `hydrate: true`
|
|
48
|
+
* @returns The mounted View instance
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { hydrateMount } from '@bquery/bquery/ssr';
|
|
53
|
+
* import { signal, computed } from '@bquery/bquery/reactive';
|
|
54
|
+
*
|
|
55
|
+
* // Server rendered:
|
|
56
|
+
* // <div id="app"><h1>Welcome</h1><p>Hello, World!</p></div>
|
|
57
|
+
*
|
|
58
|
+
* // Client hydration — attaches reactivity to existing DOM:
|
|
59
|
+
* const name = signal('World');
|
|
60
|
+
* const greeting = computed(() => `Hello, ${name.value}!`);
|
|
61
|
+
*
|
|
62
|
+
* const view = hydrateMount('#app', { name, greeting }, { hydrate: true });
|
|
63
|
+
*
|
|
64
|
+
* // Now updating `name.value` will reactively update the DOM
|
|
65
|
+
* name.value = 'Alice'; // <p> updates to "Hello, Alice!"
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export const hydrateMount = (
|
|
69
|
+
selector: string | Element,
|
|
70
|
+
context: BindingContext,
|
|
71
|
+
options: HydrateMountOptions = {}
|
|
72
|
+
): View => {
|
|
73
|
+
const { hydrate = true, ...mountOptions } = options;
|
|
74
|
+
|
|
75
|
+
if (!hydrate) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
'bQuery ssr: hydrateMount() requires { hydrate: true } when options are provided.'
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Hydration uses the standard mount which processes existing DOM
|
|
82
|
+
// and attaches reactive effects without clearing content.
|
|
83
|
+
return mount(selector, context, mountOptions);
|
|
84
|
+
};
|
package/src/ssr/index.ts
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SSR / Pre-rendering module for bQuery.js.
|
|
3
|
-
*
|
|
4
|
-
* Provides server-side rendering, hydration, and store state serialization
|
|
5
|
-
* utilities for bQuery applications. Enables rendering bQuery templates
|
|
6
|
-
* to HTML strings on the server, serializing store state for client pickup,
|
|
7
|
-
* and hydrating the pre-rendered DOM on the client.
|
|
8
|
-
*
|
|
9
|
-
* ## Features
|
|
10
|
-
*
|
|
11
|
-
* - **`renderToString(template, data)`** — Server-side render a bQuery
|
|
12
|
-
* template to an `SSRResult` containing an `html` string with directive evaluation.
|
|
13
|
-
* - **`hydrateMount(selector, context, { hydrate: true })`** — Reuse
|
|
14
|
-
* existing server-rendered DOM and attach reactive bindings.
|
|
15
|
-
* - **`serializeStoreState(options?)`** — Serialize store state into a
|
|
16
|
-
* `<script>` tag for client-side pickup.
|
|
17
|
-
* - **`deserializeStoreState()`** — Read serialized state on the client.
|
|
18
|
-
* - **`hydrateStore(id, state)` / `hydrateStores(stateMap)`** — Apply
|
|
19
|
-
* server state to client stores.
|
|
20
|
-
*
|
|
21
|
-
* ## Usage
|
|
22
|
-
*
|
|
23
|
-
* ### Server
|
|
24
|
-
* ```ts
|
|
25
|
-
* import { renderToString, serializeStoreState } from '@bquery/bquery/ssr';
|
|
26
|
-
*
|
|
27
|
-
* const { html } = renderToString(
|
|
28
|
-
* '<div id="app"><h1 bq-text="title"></h1></div>',
|
|
29
|
-
* { title: 'Welcome' }
|
|
30
|
-
* );
|
|
31
|
-
*
|
|
32
|
-
* const { scriptTag } = serializeStoreState();
|
|
33
|
-
*
|
|
34
|
-
* // Send to client: html + scriptTag
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* ### Client
|
|
38
|
-
* ```ts
|
|
39
|
-
* import { hydrateMount, deserializeStoreState, hydrateStores } from '@bquery/bquery/ssr';
|
|
40
|
-
* import { signal } from '@bquery/bquery/reactive';
|
|
41
|
-
*
|
|
42
|
-
* // Restore store state from SSR
|
|
43
|
-
* const ssrState = deserializeStoreState();
|
|
44
|
-
* hydrateStores(ssrState);
|
|
45
|
-
*
|
|
46
|
-
* // Hydrate the DOM with reactive bindings
|
|
47
|
-
* const title = signal('Welcome');
|
|
48
|
-
* hydrateMount('#app', { title }, { hydrate: true });
|
|
49
|
-
* ```
|
|
50
|
-
*
|
|
51
|
-
* @module bquery/ssr
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
export { hydrateMount } from './hydrate';
|
|
55
|
-
export type { HydrateMountOptions } from './hydrate';
|
|
56
|
-
export { renderToString } from './render';
|
|
57
|
-
export {
|
|
58
|
-
deserializeStoreState,
|
|
59
|
-
hydrateStore,
|
|
60
|
-
hydrateStores,
|
|
61
|
-
serializeStoreState,
|
|
62
|
-
} from './serialize';
|
|
63
|
-
export type { SerializeResult } from './serialize';
|
|
64
|
-
export type {
|
|
65
|
-
DeserializedStoreState,
|
|
66
|
-
HydrationOptions,
|
|
67
|
-
RenderOptions,
|
|
68
|
-
SSRResult,
|
|
69
|
-
SerializeOptions,
|
|
70
|
-
} from './types';
|
|
1
|
+
/**
|
|
2
|
+
* SSR / Pre-rendering module for bQuery.js.
|
|
3
|
+
*
|
|
4
|
+
* Provides server-side rendering, hydration, and store state serialization
|
|
5
|
+
* utilities for bQuery applications. Enables rendering bQuery templates
|
|
6
|
+
* to HTML strings on the server, serializing store state for client pickup,
|
|
7
|
+
* and hydrating the pre-rendered DOM on the client.
|
|
8
|
+
*
|
|
9
|
+
* ## Features
|
|
10
|
+
*
|
|
11
|
+
* - **`renderToString(template, data)`** — Server-side render a bQuery
|
|
12
|
+
* template to an `SSRResult` containing an `html` string with directive evaluation.
|
|
13
|
+
* - **`hydrateMount(selector, context, { hydrate: true })`** — Reuse
|
|
14
|
+
* existing server-rendered DOM and attach reactive bindings.
|
|
15
|
+
* - **`serializeStoreState(options?)`** — Serialize store state into a
|
|
16
|
+
* `<script>` tag for client-side pickup.
|
|
17
|
+
* - **`deserializeStoreState()`** — Read serialized state on the client.
|
|
18
|
+
* - **`hydrateStore(id, state)` / `hydrateStores(stateMap)`** — Apply
|
|
19
|
+
* server state to client stores.
|
|
20
|
+
*
|
|
21
|
+
* ## Usage
|
|
22
|
+
*
|
|
23
|
+
* ### Server
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { renderToString, serializeStoreState } from '@bquery/bquery/ssr';
|
|
26
|
+
*
|
|
27
|
+
* const { html } = renderToString(
|
|
28
|
+
* '<div id="app"><h1 bq-text="title"></h1></div>',
|
|
29
|
+
* { title: 'Welcome' }
|
|
30
|
+
* );
|
|
31
|
+
*
|
|
32
|
+
* const { scriptTag } = serializeStoreState();
|
|
33
|
+
*
|
|
34
|
+
* // Send to client: html + scriptTag
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* ### Client
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { hydrateMount, deserializeStoreState, hydrateStores } from '@bquery/bquery/ssr';
|
|
40
|
+
* import { signal } from '@bquery/bquery/reactive';
|
|
41
|
+
*
|
|
42
|
+
* // Restore store state from SSR
|
|
43
|
+
* const ssrState = deserializeStoreState();
|
|
44
|
+
* hydrateStores(ssrState);
|
|
45
|
+
*
|
|
46
|
+
* // Hydrate the DOM with reactive bindings
|
|
47
|
+
* const title = signal('Welcome');
|
|
48
|
+
* hydrateMount('#app', { title }, { hydrate: true });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @module bquery/ssr
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
export { hydrateMount } from './hydrate';
|
|
55
|
+
export type { HydrateMountOptions } from './hydrate';
|
|
56
|
+
export { renderToString } from './render';
|
|
57
|
+
export {
|
|
58
|
+
deserializeStoreState,
|
|
59
|
+
hydrateStore,
|
|
60
|
+
hydrateStores,
|
|
61
|
+
serializeStoreState,
|
|
62
|
+
} from './serialize';
|
|
63
|
+
export type { SerializeResult } from './serialize';
|
|
64
|
+
export type {
|
|
65
|
+
DeserializedStoreState,
|
|
66
|
+
HydrationOptions,
|
|
67
|
+
RenderOptions,
|
|
68
|
+
SSRResult,
|
|
69
|
+
SerializeOptions,
|
|
70
|
+
} from './types';
|