zero-query 1.0.9 → 1.2.0

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 (154) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +2 -0
  3. package/cli/args.js +33 -33
  4. package/cli/commands/build-api.js +443 -0
  5. package/cli/commands/build.js +254 -216
  6. package/cli/commands/bundle.js +1228 -1183
  7. package/cli/commands/create.js +137 -121
  8. package/cli/commands/dev/devtools/index.js +56 -56
  9. package/cli/commands/dev/devtools/js/components.js +49 -49
  10. package/cli/commands/dev/devtools/js/core.js +423 -423
  11. package/cli/commands/dev/devtools/js/elements.js +421 -421
  12. package/cli/commands/dev/devtools/js/network.js +166 -166
  13. package/cli/commands/dev/devtools/js/performance.js +73 -73
  14. package/cli/commands/dev/devtools/js/router.js +105 -105
  15. package/cli/commands/dev/devtools/js/source.js +132 -132
  16. package/cli/commands/dev/devtools/js/stats.js +35 -35
  17. package/cli/commands/dev/devtools/js/tabs.js +79 -79
  18. package/cli/commands/dev/devtools/panel.html +95 -95
  19. package/cli/commands/dev/devtools/styles.css +244 -244
  20. package/cli/commands/dev/index.js +107 -107
  21. package/cli/commands/dev/logger.js +75 -75
  22. package/cli/commands/dev/overlay.js +858 -858
  23. package/cli/commands/dev/server.js +220 -167
  24. package/cli/commands/dev/validator.js +94 -94
  25. package/cli/commands/dev/watcher.js +172 -172
  26. package/cli/help.js +114 -112
  27. package/cli/index.js +52 -52
  28. package/cli/scaffold/default/LICENSE +21 -21
  29. package/cli/scaffold/default/app/app.js +207 -207
  30. package/cli/scaffold/default/app/components/about.js +201 -201
  31. package/cli/scaffold/default/app/components/api-demo.js +143 -143
  32. package/cli/scaffold/default/app/components/contact-card.js +231 -231
  33. package/cli/scaffold/default/app/components/contacts/contacts.css +706 -706
  34. package/cli/scaffold/default/app/components/contacts/contacts.html +200 -200
  35. package/cli/scaffold/default/app/components/contacts/contacts.js +196 -196
  36. package/cli/scaffold/default/app/components/counter.js +127 -127
  37. package/cli/scaffold/default/app/components/home.js +249 -249
  38. package/cli/scaffold/default/app/components/not-found.js +16 -16
  39. package/cli/scaffold/default/app/components/playground/playground.css +115 -115
  40. package/cli/scaffold/default/app/components/playground/playground.html +161 -161
  41. package/cli/scaffold/default/app/components/playground/playground.js +116 -116
  42. package/cli/scaffold/default/app/components/todos.js +225 -225
  43. package/cli/scaffold/default/app/components/toolkit/toolkit.css +97 -97
  44. package/cli/scaffold/default/app/components/toolkit/toolkit.html +146 -146
  45. package/cli/scaffold/default/app/components/toolkit/toolkit.js +280 -280
  46. package/cli/scaffold/default/app/routes.js +15 -15
  47. package/cli/scaffold/default/app/store.js +101 -101
  48. package/cli/scaffold/default/global.css +552 -552
  49. package/cli/scaffold/default/index.html +99 -99
  50. package/cli/scaffold/minimal/app/app.js +85 -85
  51. package/cli/scaffold/minimal/app/components/about.js +68 -68
  52. package/cli/scaffold/minimal/app/components/counter.js +122 -122
  53. package/cli/scaffold/minimal/app/components/home.js +68 -68
  54. package/cli/scaffold/minimal/app/components/not-found.js +16 -16
  55. package/cli/scaffold/minimal/app/routes.js +9 -9
  56. package/cli/scaffold/minimal/app/store.js +36 -36
  57. package/cli/scaffold/minimal/global.css +300 -300
  58. package/cli/scaffold/minimal/index.html +44 -44
  59. package/cli/scaffold/ssr/app/app.js +41 -41
  60. package/cli/scaffold/ssr/app/components/about.js +55 -55
  61. package/cli/scaffold/ssr/app/components/blog/index.js +65 -65
  62. package/cli/scaffold/ssr/app/components/blog/post.js +86 -86
  63. package/cli/scaffold/ssr/app/components/home.js +37 -37
  64. package/cli/scaffold/ssr/app/components/not-found.js +15 -15
  65. package/cli/scaffold/ssr/app/routes.js +8 -8
  66. package/cli/scaffold/ssr/global.css +228 -228
  67. package/cli/scaffold/ssr/index.html +37 -37
  68. package/cli/scaffold/ssr/package.json +8 -8
  69. package/cli/scaffold/ssr/server/data/posts.js +144 -144
  70. package/cli/scaffold/ssr/server/index.js +213 -213
  71. package/cli/scaffold/webrtc/app/app.js +11 -0
  72. package/cli/scaffold/webrtc/app/components/video-room.js +295 -0
  73. package/cli/scaffold/webrtc/app/lib/room.js +252 -0
  74. package/cli/scaffold/webrtc/assets/.gitkeep +0 -0
  75. package/cli/scaffold/webrtc/global.css +250 -0
  76. package/cli/scaffold/webrtc/index.html +21 -0
  77. package/cli/utils.js +305 -287
  78. package/dist/API.md +7264 -0
  79. package/dist/zquery.dist.zip +0 -0
  80. package/dist/zquery.js +10313 -6252
  81. package/dist/zquery.min.js +8 -601
  82. package/index.d.ts +570 -365
  83. package/index.js +311 -232
  84. package/package.json +76 -69
  85. package/src/component.js +1709 -1454
  86. package/src/core.js +921 -921
  87. package/src/diff.js +497 -497
  88. package/src/errors.js +209 -209
  89. package/src/expression.js +922 -922
  90. package/src/http.js +242 -242
  91. package/src/package.json +1 -1
  92. package/src/reactive.js +255 -254
  93. package/src/router.js +843 -773
  94. package/src/ssr.js +418 -418
  95. package/src/store.js +318 -272
  96. package/src/utils.js +515 -515
  97. package/src/webrtc/e2ee.js +351 -0
  98. package/src/webrtc/errors.js +116 -0
  99. package/src/webrtc/ice.js +301 -0
  100. package/src/webrtc/index.js +131 -0
  101. package/src/webrtc/joinToken.js +119 -0
  102. package/src/webrtc/observe.js +172 -0
  103. package/src/webrtc/peer.js +351 -0
  104. package/src/webrtc/reactive.js +268 -0
  105. package/src/webrtc/room.js +625 -0
  106. package/src/webrtc/sdp.js +302 -0
  107. package/src/webrtc/sfu/index.js +43 -0
  108. package/src/webrtc/sfu/livekit.js +131 -0
  109. package/src/webrtc/sfu/mediasoup.js +150 -0
  110. package/src/webrtc/signaling.js +373 -0
  111. package/src/webrtc/turn.js +237 -0
  112. package/tests/_helpers/webrtcFakes.js +289 -0
  113. package/tests/audit.test.js +4158 -4158
  114. package/tests/cli.test.js +1136 -1023
  115. package/tests/compare.test.js +497 -0
  116. package/tests/component.test.js +3969 -3938
  117. package/tests/core.test.js +1910 -1910
  118. package/tests/dev-server.test.js +489 -0
  119. package/tests/diff.test.js +1416 -1416
  120. package/tests/docs.test.js +1664 -0
  121. package/tests/electron-features.test.js +864 -0
  122. package/tests/errors.test.js +619 -619
  123. package/tests/expression.test.js +1056 -1056
  124. package/tests/http.test.js +648 -648
  125. package/tests/reactive.test.js +819 -819
  126. package/tests/router.test.js +2327 -2327
  127. package/tests/ssr.test.js +870 -870
  128. package/tests/store.test.js +830 -830
  129. package/tests/test-minifier.js +153 -153
  130. package/tests/test-ssr.js +27 -27
  131. package/tests/utils.test.js +1377 -1377
  132. package/tests/webrtc/e2ee.test.js +283 -0
  133. package/tests/webrtc/ice.test.js +202 -0
  134. package/tests/webrtc/joinToken.test.js +89 -0
  135. package/tests/webrtc/observe.test.js +111 -0
  136. package/tests/webrtc/peer.test.js +373 -0
  137. package/tests/webrtc/reactive.test.js +235 -0
  138. package/tests/webrtc/room.test.js +406 -0
  139. package/tests/webrtc/sdp.test.js +151 -0
  140. package/tests/webrtc/sfu-livekit.test.js +119 -0
  141. package/tests/webrtc/sfu.test.js +160 -0
  142. package/tests/webrtc/signaling.test.js +251 -0
  143. package/tests/webrtc/turn.test.js +256 -0
  144. package/types/collection.d.ts +383 -383
  145. package/types/component.d.ts +186 -186
  146. package/types/errors.d.ts +135 -135
  147. package/types/http.d.ts +92 -92
  148. package/types/misc.d.ts +201 -201
  149. package/types/reactive.d.ts +98 -98
  150. package/types/router.d.ts +190 -190
  151. package/types/ssr.d.ts +102 -102
  152. package/types/store.d.ts +146 -145
  153. package/types/utils.d.ts +245 -245
  154. package/types/webrtc.d.ts +653 -0
@@ -1,98 +1,98 @@
1
- /**
2
- * Reactive primitives - deep proxies and signals.
3
- *
4
- * @module reactive
5
- */
6
-
7
- /** Marker properties added to every reactive proxy. */
8
- export interface ReactiveProxy<T extends object = object> {
9
- /** Always `true` - indicates this object is wrapped in a reactive Proxy. */
10
- readonly __isReactive: true;
11
- /** The original un-proxied object. */
12
- readonly __raw: T;
13
- }
14
-
15
- /**
16
- * Wrap an object in a deep Proxy that fires `onChange` on every set / delete.
17
- *
18
- * @param target Plain object to make reactive.
19
- * @param onChange Called with `(key, newValue, oldValue)` on every mutation.
20
- * @returns A proxied version of `target` with `__isReactive` and `__raw` markers.
21
- */
22
- export function reactive<T extends object>(
23
- target: T,
24
- onChange: (key: string, value: any, oldValue: any) => void,
25
- ): T & ReactiveProxy<T>;
26
-
27
- /**
28
- * A lightweight reactive primitive (inspired by Solid / Preact signals).
29
- *
30
- * Reading `.value` inside an `effect()` auto-subscribes to changes.
31
- * Writing `.value` triggers all subscribers and dependent effects.
32
- */
33
- export class Signal<T = any> {
34
- constructor(value: T);
35
-
36
- /**
37
- * Get or set the current value.
38
- * The getter automatically tracks dependencies when accessed inside an `effect()`.
39
- */
40
- value: T;
41
-
42
- /** Read the current value *without* creating a subscription (no tracking). */
43
- peek(): T;
44
-
45
- /**
46
- * Manually subscribe to changes.
47
- * @returns An unsubscribe function.
48
- */
49
- subscribe(fn: () => void): () => void;
50
-
51
- toString(): string;
52
- }
53
-
54
- /** Create a new `Signal`. */
55
- export function signal<T>(initial: T): Signal<T>;
56
-
57
- /**
58
- * Create a derived signal that recomputes when its dependencies change.
59
- * The returned signal is effectively read-only.
60
- */
61
- export function computed<T>(fn: () => T): Signal<T>;
62
-
63
- /**
64
- * Create a side-effect that auto-subscribes to signals read during execution.
65
- * Re-runs automatically when any tracked signal changes.
66
- *
67
- * @param fn The effect function. Executed immediately on creation, then on signal changes.
68
- * @returns A dispose function - calling it stops tracking and prevents re-runs.
69
- *
70
- * @example
71
- * const count = signal(0);
72
- * const stop = effect(() => console.log(count.value)); // logs 0
73
- * count.value = 1; // logs 1
74
- * stop(); // effect no longer runs
75
- */
76
- export function effect(fn: () => void): () => void;
77
-
78
- /**
79
- * Batch multiple signal writes - subscribers and effects fire once at the end.
80
- * Nested batches are merged into the outermost one.
81
- *
82
- * @example
83
- * const a = signal(0);
84
- * const b = signal(0);
85
- * batch(() => {
86
- * a.value = 1;
87
- * b.value = 2;
88
- * }); // effects run once with both values updated
89
- */
90
- export function batch(fn: () => void): void;
91
-
92
- /**
93
- * Execute a function without tracking signal reads as dependencies.
94
- * Useful inside effects when you need to read a signal without subscribing.
95
- *
96
- * @returns The return value of `fn`.
97
- */
98
- export function untracked<T>(fn: () => T): T;
1
+ /**
2
+ * Reactive primitives - deep proxies and signals.
3
+ *
4
+ * @module reactive
5
+ */
6
+
7
+ /** Marker properties added to every reactive proxy. */
8
+ export interface ReactiveProxy<T extends object = object> {
9
+ /** Always `true` - indicates this object is wrapped in a reactive Proxy. */
10
+ readonly __isReactive: true;
11
+ /** The original un-proxied object. */
12
+ readonly __raw: T;
13
+ }
14
+
15
+ /**
16
+ * Wrap an object in a deep Proxy that fires `onChange` on every set / delete.
17
+ *
18
+ * @param target Plain object to make reactive.
19
+ * @param onChange Called with `(key, newValue, oldValue)` on every mutation.
20
+ * @returns A proxied version of `target` with `__isReactive` and `__raw` markers.
21
+ */
22
+ export function reactive<T extends object>(
23
+ target: T,
24
+ onChange: (key: string, value: any, oldValue: any) => void,
25
+ ): T & ReactiveProxy<T>;
26
+
27
+ /**
28
+ * A lightweight reactive primitive (inspired by Solid / Preact signals).
29
+ *
30
+ * Reading `.value` inside an `effect()` auto-subscribes to changes.
31
+ * Writing `.value` triggers all subscribers and dependent effects.
32
+ */
33
+ export class Signal<T = any> {
34
+ constructor(value: T);
35
+
36
+ /**
37
+ * Get or set the current value.
38
+ * The getter automatically tracks dependencies when accessed inside an `effect()`.
39
+ */
40
+ value: T;
41
+
42
+ /** Read the current value *without* creating a subscription (no tracking). */
43
+ peek(): T;
44
+
45
+ /**
46
+ * Manually subscribe to changes.
47
+ * @returns An unsubscribe function.
48
+ */
49
+ subscribe(fn: () => void): () => void;
50
+
51
+ toString(): string;
52
+ }
53
+
54
+ /** Create a new `Signal`. */
55
+ export function signal<T>(initial: T): Signal<T>;
56
+
57
+ /**
58
+ * Create a derived signal that recomputes when its dependencies change.
59
+ * The returned signal is effectively read-only.
60
+ */
61
+ export function computed<T>(fn: () => T): Signal<T>;
62
+
63
+ /**
64
+ * Create a side-effect that auto-subscribes to signals read during execution.
65
+ * Re-runs automatically when any tracked signal changes.
66
+ *
67
+ * @param fn The effect function. Executed immediately on creation, then on signal changes.
68
+ * @returns A dispose function - calling it stops tracking and prevents re-runs.
69
+ *
70
+ * @example
71
+ * const count = signal(0);
72
+ * const stop = effect(() => console.log(count.value)); // logs 0
73
+ * count.value = 1; // logs 1
74
+ * stop(); // effect no longer runs
75
+ */
76
+ export function effect(fn: () => void): () => void;
77
+
78
+ /**
79
+ * Batch multiple signal writes - subscribers and effects fire once at the end.
80
+ * Nested batches are merged into the outermost one.
81
+ *
82
+ * @example
83
+ * const a = signal(0);
84
+ * const b = signal(0);
85
+ * batch(() => {
86
+ * a.value = 1;
87
+ * b.value = 2;
88
+ * }); // effects run once with both values updated
89
+ */
90
+ export function batch<R = void>(fn: () => R): R;
91
+
92
+ /**
93
+ * Execute a function without tracking signal reads as dependencies.
94
+ * Useful inside effects when you need to read a signal without subscribing.
95
+ *
96
+ * @returns The return value of `fn`.
97
+ */
98
+ export function untracked<T>(fn: () => T): T;
package/types/router.d.ts CHANGED
@@ -1,190 +1,190 @@
1
- /**
2
- * SPA Router - history and hash-based client-side routing.
3
- *
4
- * @module router
5
- */
6
-
7
- /** A single route definition. */
8
- export interface RouteDefinition {
9
- /**
10
- * URL pattern. Supports `:param` segments and `*` wildcard.
11
- * @example '/user/:id'
12
- */
13
- path: string;
14
-
15
- /** Registered component name (auto-mounted), or a render function. */
16
- component: string | ((route: NavigationContext) => string);
17
-
18
- /** Async function called before mounting (for lazy-loading modules). */
19
- load?: () => Promise<any>;
20
-
21
- /**
22
- * An additional path that also matches this route.
23
- * Missing `:param` values will be `undefined`.
24
- */
25
- fallback?: string;
26
- }
27
-
28
- /** Navigation context passed to guards and `onChange` listeners. */
29
- export interface NavigationContext {
30
- /** The matched route definition. */
31
- route: RouteDefinition;
32
- /** Parsed `:param` values. */
33
- params: Record<string, string>;
34
- /** Parsed query-string values. */
35
- query: Record<string, string>;
36
- /** Matched path (base-stripped in history mode). */
37
- path: string;
38
- }
39
-
40
- /** Router configuration. */
41
- export interface RouterConfig {
42
- /**
43
- * Outlet element where route components are rendered.
44
- * If omitted, the router auto-detects a `<z-outlet>` element in the DOM.
45
- * Acts as an explicit override of the default `<z-outlet>` lookup.
46
- */
47
- el?: string | Element;
48
- /** Routing mode (default: `'history'`; `'hash'` for file:// or hash routing). */
49
- mode?: 'history' | 'hash';
50
- /**
51
- * Base path prefix (e.g. `'/my-app'`).
52
- * Auto-detected from `<base href>` or `window.__ZQ_BASE` if not set.
53
- */
54
- base?: string;
55
- /** Route definitions. */
56
- routes?: RouteDefinition[];
57
- /** Component name to render when no route matches (404). */
58
- fallback?: string;
59
- }
60
-
61
- /** The SPA router instance. */
62
- export interface RouterInstance {
63
- /**
64
- * Push a new state and resolve the route.
65
- * Supports `:param` interpolation when `options.params` is provided.
66
- * Same-path navigation is deduplicated (skipped unless `options.force` is true).
67
- * Hash-only changes on the same route use `replaceState` to avoid extra history entries.
68
- * @example
69
- * router.navigate('/user/:id', { params: { id: 42 } }); // navigates to /user/42
70
- * router.navigate('/dashboard', { state: { from: 'login' } });
71
- */
72
- navigate(path: string, options?: { params?: Record<string, string | number>; state?: any; force?: boolean }): RouterInstance;
73
- /**
74
- * Replace the current state (no new history entry).
75
- * Supports `:param` interpolation when `options.params` is provided.
76
- * @example
77
- * router.replace('/user/:id', { params: { id: 42 } }); // replaces with /user/42
78
- */
79
- replace(path: string, options?: { params?: Record<string, string | number>; state?: any }): RouterInstance;
80
- /** `history.back()` */
81
- back(): RouterInstance;
82
- /** `history.forward()` */
83
- forward(): RouterInstance;
84
- /** `history.go(n)` */
85
- go(n: number): RouterInstance;
86
-
87
- /** Add a route dynamically. Chainable. */
88
- add(route: RouteDefinition): RouterInstance;
89
- /** Remove a route by path. */
90
- remove(path: string): RouterInstance;
91
-
92
- /**
93
- * Navigation guard - runs before each route change.
94
- * Return `false` to cancel, or a `string` to redirect.
95
- */
96
- beforeEach(
97
- fn: (
98
- to: NavigationContext,
99
- from: NavigationContext | null,
100
- ) => boolean | string | void | Promise<boolean | string | void>,
101
- ): RouterInstance;
102
-
103
- /** Post-navigation hook. */
104
- afterEach(
105
- fn: (to: NavigationContext, from: NavigationContext | null) => void | Promise<void>,
106
- ): RouterInstance;
107
-
108
- /**
109
- * Subscribe to route changes.
110
- * @returns An unsubscribe function.
111
- */
112
- onChange(
113
- fn: (to: NavigationContext, from: NavigationContext | null) => void,
114
- ): () => void;
115
-
116
- /**
117
- * Push a lightweight history entry for in-component UI state (modal, tab, panel).
118
- * The URL does NOT change - only a history entry is added so the back button
119
- * can undo the UI change before navigating away from the route.
120
- * @param key - identifier for the substate (e.g. 'modal', 'tab')
121
- * @param data - arbitrary serializable state
122
- * @example
123
- * router.pushSubstate('modal', { id: 'confirm-delete' });
124
- */
125
- pushSubstate(key: string, data?: any): RouterInstance;
126
-
127
- /**
128
- * Register a listener for substate pops (back button on a substate entry).
129
- * The callback receives `(key, data, action)` and should return `true` if it
130
- * handled the pop (prevents route resolution). If no listener returns `true`,
131
- * normal route resolution proceeds.
132
- * @returns An unsubscribe function.
133
- * @example
134
- * const unsub = router.onSubstate((key, data, action) => {
135
- * if (action === 'reset') { resetDefaults(); return true; }
136
- * if (key === 'modal') { closeModal(); return true; }
137
- * });
138
- */
139
- onSubstate(
140
- fn: (key: string | null, data: any, action: 'pop' | 'resolve' | 'reset') => boolean | void,
141
- ): () => void;
142
-
143
- /** Teardown the router and mounted component. */
144
- destroy(): void;
145
-
146
- /** Resolve a path applying the base prefix. */
147
- resolve(path: string): string;
148
-
149
- // -- Properties ----------------------------------------------------------
150
-
151
- /** Current navigation context. */
152
- readonly current: NavigationContext | null;
153
- /** Current path (base-stripped in history mode). */
154
- readonly path: string;
155
- /** Parsed query-string object. */
156
- readonly query: Record<string, string>;
157
- /** Configured base path. */
158
- readonly base: string;
159
- }
160
-
161
- /** Create and activate a client-side SPA router. */
162
- export function createRouter(config: RouterConfig): RouterInstance;
163
-
164
- /** Get the currently active router instance. */
165
- export function getRouter(): RouterInstance | null;
166
-
167
- /** Result of matching a URL path against route definitions. */
168
- export interface RouteMatch {
169
- /** The matched component name, or the fallback if nothing matched. */
170
- component: string;
171
- /** Parsed `:param` values from the URL. */
172
- params: Record<string, string>;
173
- }
174
-
175
- /**
176
- * Match a pathname against an array of route definitions.
177
- * Returns `{ component, params }`. If no route matches, returns the
178
- * fallback component (default `'not-found'`).
179
- *
180
- * DOM-free — works on both server and client.
181
- *
182
- * @param routes - Array of route definitions with `path` and `component`.
183
- * @param pathname - URL path to match, e.g. `'/blog/my-post'`.
184
- * @param fallback - Component name when nothing matches (default `'not-found'`).
185
- */
186
- export function matchRoute(
187
- routes: RouteDefinition[],
188
- pathname: string,
189
- fallback?: string,
190
- ): RouteMatch;
1
+ /**
2
+ * SPA Router - history and hash-based client-side routing.
3
+ *
4
+ * @module router
5
+ */
6
+
7
+ /** A single route definition. */
8
+ export interface RouteDefinition {
9
+ /**
10
+ * URL pattern. Supports `:param` segments and `*` wildcard.
11
+ * @example '/user/:id'
12
+ */
13
+ path: string;
14
+
15
+ /** Registered component name (auto-mounted), or a render function. */
16
+ component: string | ((route: NavigationContext) => string);
17
+
18
+ /** Async function called before mounting (for lazy-loading modules). */
19
+ load?: () => Promise<any>;
20
+
21
+ /**
22
+ * An additional path that also matches this route.
23
+ * Missing `:param` values will be `undefined`.
24
+ */
25
+ fallback?: string;
26
+ }
27
+
28
+ /** Navigation context passed to guards and `onChange` listeners. */
29
+ export interface NavigationContext {
30
+ /** The matched route definition. */
31
+ route: RouteDefinition;
32
+ /** Parsed `:param` values. */
33
+ params: Record<string, string>;
34
+ /** Parsed query-string values. */
35
+ query: Record<string, string>;
36
+ /** Matched path (base-stripped in history mode). */
37
+ path: string;
38
+ }
39
+
40
+ /** Router configuration. */
41
+ export interface RouterConfig {
42
+ /**
43
+ * Outlet element where route components are rendered.
44
+ * If omitted, the router auto-detects a `<z-outlet>` element in the DOM.
45
+ * Acts as an explicit override of the default `<z-outlet>` lookup.
46
+ */
47
+ el?: string | Element;
48
+ /** Routing mode (default: `'history'`; `'hash'` for file:// or hash routing). */
49
+ mode?: 'history' | 'hash';
50
+ /**
51
+ * Base path prefix (e.g. `'/my-app'`).
52
+ * Auto-detected from `<base href>` or `window.__ZQ_BASE` if not set.
53
+ */
54
+ base?: string;
55
+ /** Route definitions. */
56
+ routes?: RouteDefinition[];
57
+ /** Component name to render when no route matches (404). */
58
+ fallback?: string;
59
+ }
60
+
61
+ /** The SPA router instance. */
62
+ export interface RouterInstance {
63
+ /**
64
+ * Push a new state and resolve the route.
65
+ * Supports `:param` interpolation when `options.params` is provided.
66
+ * Same-path navigation is deduplicated (skipped unless `options.force` is true).
67
+ * Hash-only changes on the same route use `replaceState` to avoid extra history entries.
68
+ * @example
69
+ * router.navigate('/user/:id', { params: { id: 42 } }); // navigates to /user/42
70
+ * router.navigate('/dashboard', { state: { from: 'login' } });
71
+ */
72
+ navigate(path: string, options?: { params?: Record<string, string | number>; state?: any; force?: boolean }): RouterInstance;
73
+ /**
74
+ * Replace the current state (no new history entry).
75
+ * Supports `:param` interpolation when `options.params` is provided.
76
+ * @example
77
+ * router.replace('/user/:id', { params: { id: 42 } }); // replaces with /user/42
78
+ */
79
+ replace(path: string, options?: { params?: Record<string, string | number>; state?: any }): RouterInstance;
80
+ /** `history.back()` */
81
+ back(): RouterInstance;
82
+ /** `history.forward()` */
83
+ forward(): RouterInstance;
84
+ /** `history.go(n)` */
85
+ go(n: number): RouterInstance;
86
+
87
+ /** Add a route dynamically. Chainable. */
88
+ add(route: RouteDefinition): RouterInstance;
89
+ /** Remove a route by path. */
90
+ remove(path: string): RouterInstance;
91
+
92
+ /**
93
+ * Navigation guard - runs before each route change.
94
+ * Return `false` to cancel, or a `string` to redirect.
95
+ */
96
+ beforeEach(
97
+ fn: (
98
+ to: NavigationContext,
99
+ from: NavigationContext | null,
100
+ ) => boolean | string | void | Promise<boolean | string | void>,
101
+ ): RouterInstance;
102
+
103
+ /** Post-navigation hook. */
104
+ afterEach(
105
+ fn: (to: NavigationContext, from: NavigationContext | null) => void | Promise<void>,
106
+ ): RouterInstance;
107
+
108
+ /**
109
+ * Subscribe to route changes.
110
+ * @returns An unsubscribe function.
111
+ */
112
+ onChange(
113
+ fn: (to: NavigationContext, from: NavigationContext | null) => void,
114
+ ): () => void;
115
+
116
+ /**
117
+ * Push a lightweight history entry for in-component UI state (modal, tab, panel).
118
+ * The URL does NOT change - only a history entry is added so the back button
119
+ * can undo the UI change before navigating away from the route.
120
+ * @param key - identifier for the substate (e.g. 'modal', 'tab')
121
+ * @param data - arbitrary serializable state
122
+ * @example
123
+ * router.pushSubstate('modal', { id: 'confirm-delete' });
124
+ */
125
+ pushSubstate(key: string, data?: any): RouterInstance;
126
+
127
+ /**
128
+ * Register a listener for substate pops (back button on a substate entry).
129
+ * The callback receives `(key, data, action)` and should return `true` if it
130
+ * handled the pop (prevents route resolution). If no listener returns `true`,
131
+ * normal route resolution proceeds.
132
+ * @returns An unsubscribe function.
133
+ * @example
134
+ * const unsub = router.onSubstate((key, data, action) => {
135
+ * if (action === 'reset') { resetDefaults(); return true; }
136
+ * if (key === 'modal') { closeModal(); return true; }
137
+ * });
138
+ */
139
+ onSubstate(
140
+ fn: (key: string | null, data: any, action: 'pop' | 'resolve' | 'reset') => boolean | void,
141
+ ): () => void;
142
+
143
+ /** Teardown the router and mounted component. */
144
+ destroy(): void;
145
+
146
+ /** Resolve a path applying the base prefix. */
147
+ resolve(path: string): string;
148
+
149
+ // -- Properties ----------------------------------------------------------
150
+
151
+ /** Current navigation context. */
152
+ readonly current: NavigationContext | null;
153
+ /** Current path (base-stripped in history mode). */
154
+ readonly path: string;
155
+ /** Parsed query-string object. */
156
+ readonly query: Record<string, string>;
157
+ /** Configured base path. */
158
+ readonly base: string;
159
+ }
160
+
161
+ /** Create and activate a client-side SPA router. */
162
+ export function createRouter(config: RouterConfig): RouterInstance;
163
+
164
+ /** Get the currently active router instance. */
165
+ export function getRouter(): RouterInstance | null;
166
+
167
+ /** Result of matching a URL path against route definitions. */
168
+ export interface RouteMatch {
169
+ /** The matched component name, or the fallback if nothing matched. */
170
+ component: string;
171
+ /** Parsed `:param` values from the URL. */
172
+ params: Record<string, string>;
173
+ }
174
+
175
+ /**
176
+ * Match a pathname against an array of route definitions.
177
+ * Returns `{ component, params }`. If no route matches, returns the
178
+ * fallback component (default `'not-found'`).
179
+ *
180
+ * DOM-free — works on both server and client.
181
+ *
182
+ * @param routes - Array of route definitions with `path` and `component`.
183
+ * @param pathname - URL path to match, e.g. `'/blog/my-post'`.
184
+ * @param fallback - Component name when nothing matches (default `'not-found'`).
185
+ */
186
+ export function matchRoute(
187
+ routes: RouteDefinition[],
188
+ pathname: string,
189
+ fallback?: string,
190
+ ): RouteMatch;