@buzola/router 0.0.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 (114) hide show
  1. package/dist/__tests__/create-page.test.d.ts +2 -0
  2. package/dist/__tests__/create-page.test.d.ts.map +1 -0
  3. package/dist/__tests__/create-page.test.js +457 -0
  4. package/dist/__tests__/create-page.test.js.map +1 -0
  5. package/dist/__tests__/define-routes.test.d.ts +2 -0
  6. package/dist/__tests__/define-routes.test.d.ts.map +1 -0
  7. package/dist/__tests__/define-routes.test.js +42 -0
  8. package/dist/__tests__/define-routes.test.js.map +1 -0
  9. package/dist/__tests__/matcher.test.d.ts +2 -0
  10. package/dist/__tests__/matcher.test.d.ts.map +1 -0
  11. package/dist/__tests__/matcher.test.js +108 -0
  12. package/dist/__tests__/matcher.test.js.map +1 -0
  13. package/dist/__tests__/router.test.d.ts +2 -0
  14. package/dist/__tests__/router.test.d.ts.map +1 -0
  15. package/dist/__tests__/router.test.js +327 -0
  16. package/dist/__tests__/router.test.js.map +1 -0
  17. package/dist/__tests__/type-safety.test.d.ts +15 -0
  18. package/dist/__tests__/type-safety.test.d.ts.map +1 -0
  19. package/dist/__tests__/type-safety.test.js +163 -0
  20. package/dist/__tests__/type-safety.test.js.map +1 -0
  21. package/dist/__tests__/types.test.d.ts +2 -0
  22. package/dist/__tests__/types.test.d.ts.map +1 -0
  23. package/dist/__tests__/types.test.js +22 -0
  24. package/dist/__tests__/types.test.js.map +1 -0
  25. package/dist/define/create-page.d.ts +87 -0
  26. package/dist/define/create-page.d.ts.map +1 -0
  27. package/dist/define/create-page.js +305 -0
  28. package/dist/define/create-page.js.map +1 -0
  29. package/dist/define/define-routes.d.ts +34 -0
  30. package/dist/define/define-routes.d.ts.map +1 -0
  31. package/dist/define/define-routes.js +53 -0
  32. package/dist/define/define-routes.js.map +1 -0
  33. package/dist/engine/matcher.d.ts +8 -0
  34. package/dist/engine/matcher.d.ts.map +1 -0
  35. package/dist/engine/matcher.js +79 -0
  36. package/dist/engine/matcher.js.map +1 -0
  37. package/dist/engine/navigation-adapter.d.ts +13 -0
  38. package/dist/engine/navigation-adapter.d.ts.map +1 -0
  39. package/dist/engine/navigation-adapter.js +156 -0
  40. package/dist/engine/navigation-adapter.js.map +1 -0
  41. package/dist/engine/route-tree.d.ts +21 -0
  42. package/dist/engine/route-tree.d.ts.map +1 -0
  43. package/dist/engine/route-tree.js +95 -0
  44. package/dist/engine/route-tree.js.map +1 -0
  45. package/dist/engine/router.d.ts +162 -0
  46. package/dist/engine/router.d.ts.map +1 -0
  47. package/dist/engine/router.js +400 -0
  48. package/dist/engine/router.js.map +1 -0
  49. package/dist/engine/schema.d.ts +46 -0
  50. package/dist/engine/schema.d.ts.map +1 -0
  51. package/dist/engine/schema.js +110 -0
  52. package/dist/engine/schema.js.map +1 -0
  53. package/dist/engine/types.d.ts +183 -0
  54. package/dist/engine/types.d.ts.map +1 -0
  55. package/dist/engine/types.js +2 -0
  56. package/dist/engine/types.js.map +1 -0
  57. package/dist/engine/utils.d.ts +7 -0
  58. package/dist/engine/utils.d.ts.map +1 -0
  59. package/dist/engine/utils.js +17 -0
  60. package/dist/engine/utils.js.map +1 -0
  61. package/dist/index.d.ts +14 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +12 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/react/context.d.ts +21 -0
  66. package/dist/react/context.d.ts.map +1 -0
  67. package/dist/react/context.js +7 -0
  68. package/dist/react/context.js.map +1 -0
  69. package/dist/react/error-boundary.d.ts +24 -0
  70. package/dist/react/error-boundary.d.ts.map +1 -0
  71. package/dist/react/error-boundary.js +37 -0
  72. package/dist/react/error-boundary.js.map +1 -0
  73. package/dist/react/hooks.d.ts +85 -0
  74. package/dist/react/hooks.d.ts.map +1 -0
  75. package/dist/react/hooks.js +161 -0
  76. package/dist/react/hooks.js.map +1 -0
  77. package/dist/react/index.d.ts +12 -0
  78. package/dist/react/index.d.ts.map +1 -0
  79. package/dist/react/index.js +7 -0
  80. package/dist/react/index.js.map +1 -0
  81. package/dist/react/link.d.ts +42 -0
  82. package/dist/react/link.d.ts.map +1 -0
  83. package/dist/react/link.js +38 -0
  84. package/dist/react/link.js.map +1 -0
  85. package/dist/react/outlet.d.ts +13 -0
  86. package/dist/react/outlet.d.ts.map +1 -0
  87. package/dist/react/outlet.js +46 -0
  88. package/dist/react/outlet.js.map +1 -0
  89. package/dist/react/provider.d.ts +22 -0
  90. package/dist/react/provider.d.ts.map +1 -0
  91. package/dist/react/provider.js +37 -0
  92. package/dist/react/provider.js.map +1 -0
  93. package/package.json +29 -0
  94. package/src/__tests__/create-page.test.ts +588 -0
  95. package/src/__tests__/matcher.test.ts +127 -0
  96. package/src/__tests__/router.test.ts +424 -0
  97. package/src/__tests__/type-safety.test.tsx +207 -0
  98. package/src/define/create-page.tsx +472 -0
  99. package/src/engine/matcher.ts +88 -0
  100. package/src/engine/navigation-adapter.ts +191 -0
  101. package/src/engine/route-tree.ts +129 -0
  102. package/src/engine/router.ts +471 -0
  103. package/src/engine/schema.ts +130 -0
  104. package/src/engine/types.ts +203 -0
  105. package/src/engine/utils.ts +16 -0
  106. package/src/env.d.ts +120 -0
  107. package/src/index.ts +61 -0
  108. package/src/react/context.ts +24 -0
  109. package/src/react/error-boundary.tsx +56 -0
  110. package/src/react/hooks.ts +211 -0
  111. package/src/react/index.ts +16 -0
  112. package/src/react/link.tsx +93 -0
  113. package/src/react/outlet.tsx +67 -0
  114. package/src/react/provider.tsx +60 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/engine/router.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAiB,eAAe,EAAE,iBAAiB,EAAc,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAO/H;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;;CAKhD;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;AAE3D,MAAM,WAAW,aAAa;IAC7B,wBAAwB;IACxB,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,8CAA8C;IAC9C,OAAO,EAAE,iBAAiB,CAAA;IAC1B,mDAAmD;IACnD,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/C;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;GAGG;AACH,qBAAa,MAAM;IAClB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAA8B;IAClE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAwB;IACrD,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,qBAAqB,CAAwB;IACrD,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,YAAY,CAAI;IACxB,OAAO,CAAC,sBAAsB,CAAC,CAAiB;IAChD,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,qBAAqB,CAAoD;IACjF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;gBAE7B,OAAO,EAAE,aAAa;IAqBlC;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED;;OAEG;IACH,QAAQ,IAAI,WAAW;IAIvB;;OAEG;IACH,SAAS,CAAC,UAAU,EAAE,gBAAgB,GAAG,MAAM,IAAI;IAOnD;;;OAGG;IACH,KAAK,IAAI,MAAM,IAAI;IAwGnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI;IAOrD;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI;IAKhG;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM;IAStE;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM;IAiDnE;;;OAGG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAOvC;;;;;;;OAOG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IA0B/F;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;;OAGG;IACH,aAAa,IAAI,IAAI;IAMrB;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAO9C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,IAAI;IAOrC;;OAEG;IACH,OAAO,IAAI,IAAI;IAOf;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI;IAUvC;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,QAAQ;CAMhB"}
@@ -0,0 +1,400 @@
1
+ import { matchRoutes } from './matcher';
2
+ import { extractParamNames } from './utils';
3
+ function isGuardRedirect(value) {
4
+ return typeof value === 'object' && value !== null && 'redirect' in value && typeof value.redirect === 'string';
5
+ }
6
+ /**
7
+ * Thrown when a route guard prevents navigation.
8
+ */
9
+ export class NavigationAbortedError extends Error {
10
+ constructor() {
11
+ super('Navigation aborted by route guard');
12
+ this.name = 'NavigationAbortedError';
13
+ }
14
+ }
15
+ /**
16
+ * Central Router orchestrator.
17
+ * Intercepts all navigations via the Navigation API and manages route matching.
18
+ */
19
+ export class Router {
20
+ routes;
21
+ adapter;
22
+ viewTransitions;
23
+ _basePath;
24
+ persistentParamsFn;
25
+ pageRegistry;
26
+ subscribers = new Set();
27
+ invalidationListeners = new Set();
28
+ state;
29
+ navigationId = 0;
30
+ currentAbortController;
31
+ stopFn;
32
+ blockers = new Set();
33
+ pendingScrollBehavior = 'after-transition';
34
+ _loaderCacheSize;
35
+ constructor(options) {
36
+ this.routes = options.routes;
37
+ this.adapter = options.adapter;
38
+ this.viewTransitions = options.viewTransitions ?? false;
39
+ this._basePath = options.basePath ? options.basePath.replace(/\/$/, '') : '';
40
+ this.persistentParamsFn = options.persistentParams;
41
+ this.pageRegistry = options.pageRegistry ?? {};
42
+ this._loaderCacheSize = options.loaderCacheSize ?? 0;
43
+ // Initialize state from current URL
44
+ const url = this.adapter.getCurrentURL();
45
+ const matches = matchRoutes(this.routes, this.createMatchUrl(url)) ?? [];
46
+ this.state = {
47
+ location: url,
48
+ matches,
49
+ isPending: false,
50
+ navigationState: this.adapter.getState(),
51
+ };
52
+ }
53
+ /**
54
+ * The configured base path (e.g., "/app"). Empty string if none.
55
+ */
56
+ get basePath() {
57
+ return this._basePath;
58
+ }
59
+ /**
60
+ * Number of previously visited URLs to keep cached per page component.
61
+ */
62
+ get loaderCacheSize() {
63
+ return this._loaderCacheSize;
64
+ }
65
+ /**
66
+ * Get the current router state.
67
+ */
68
+ getState() {
69
+ return this.state;
70
+ }
71
+ /**
72
+ * Subscribe to state changes. Returns an unsubscribe function.
73
+ */
74
+ subscribe(subscriber) {
75
+ this.subscribers.add(subscriber);
76
+ return () => {
77
+ this.subscribers.delete(subscriber);
78
+ };
79
+ }
80
+ /**
81
+ * Start intercepting navigations.
82
+ * Call this once when the router is initialized.
83
+ */
84
+ start() {
85
+ const handler = (event) => {
86
+ if (!event.canIntercept)
87
+ return;
88
+ const url = new URL(event.destination.url);
89
+ const matchUrl = this.createMatchUrl(url);
90
+ const matches = matchRoutes(this.routes, matchUrl);
91
+ if (!matches)
92
+ return;
93
+ const currentNavId = ++this.navigationId;
94
+ const useViewTransition = event.viewTransition || this.viewTransitions;
95
+ const scrollBehavior = this.pendingScrollBehavior;
96
+ this.pendingScrollBehavior = 'after-transition';
97
+ // Abort any in-flight guard from a previous navigation
98
+ if (this.currentAbortController) {
99
+ this.currentAbortController.abort();
100
+ }
101
+ const controller = new AbortController();
102
+ this.currentAbortController = controller;
103
+ event.intercept({
104
+ scroll: scrollBehavior,
105
+ handler: async () => {
106
+ // Check blockers before setting pending state
107
+ for (const blocker of this.blockers) {
108
+ if (this.navigationId !== currentNavId)
109
+ return;
110
+ const shouldProceed = await blocker();
111
+ if (!shouldProceed) {
112
+ throw new NavigationAbortedError();
113
+ }
114
+ }
115
+ // Set pending state
116
+ this.setState({
117
+ ...this.state,
118
+ isPending: true,
119
+ });
120
+ // Run route guards (outer → inner)
121
+ for (const match of matches) {
122
+ // A newer navigation has started — abandon this one
123
+ if (this.navigationId !== currentNavId)
124
+ return;
125
+ if (match.node.beforeEnter) {
126
+ const result = await match.node.beforeEnter(match, { signal: controller.signal });
127
+ if (result === false) {
128
+ // Guard prevented navigation
129
+ if (this.navigationId === currentNavId) {
130
+ this.setState({
131
+ ...this.state,
132
+ isPending: false,
133
+ });
134
+ }
135
+ throw new NavigationAbortedError();
136
+ }
137
+ if (isGuardRedirect(result)) {
138
+ // Guard requested redirect — don't reset isPending, the redirect
139
+ // navigation will take over the pending state.
140
+ if (this.navigationId === currentNavId) {
141
+ const redirectURL = new URL(result.redirect, url);
142
+ const redirectMatches = matchRoutes(this.routes, this.createMatchUrl(redirectURL));
143
+ if (!redirectMatches) {
144
+ throw new Error(`[buzola] Guard redirect target "${result.redirect}" does not match any route.`);
145
+ }
146
+ this.navigate(result.redirect, { replace: true });
147
+ }
148
+ throw new NavigationAbortedError();
149
+ }
150
+ }
151
+ }
152
+ // A newer navigation has started — abandon this one
153
+ if (this.navigationId !== currentNavId)
154
+ return;
155
+ // Perform the DOM update
156
+ const doUpdate = () => {
157
+ this.setState({
158
+ location: url,
159
+ matches,
160
+ isPending: false,
161
+ navigationState: this.adapter.getState(),
162
+ });
163
+ };
164
+ if (useViewTransition && typeof document !== 'undefined' && 'startViewTransition' in document) {
165
+ ;
166
+ document.startViewTransition(doUpdate);
167
+ }
168
+ else {
169
+ doUpdate();
170
+ }
171
+ },
172
+ });
173
+ };
174
+ this.adapter.addEventListener('navigate', handler);
175
+ const stop = () => {
176
+ this.adapter.removeEventListener('navigate', handler);
177
+ };
178
+ this.stopFn = stop;
179
+ return stop;
180
+ }
181
+ /**
182
+ * Navigate programmatically.
183
+ * The `to` path should not include the base path — it is prepended automatically.
184
+ */
185
+ navigate(to, options) {
186
+ if (options?.resetScroll === false) {
187
+ this.pendingScrollBehavior = 'manual';
188
+ }
189
+ this.adapter.navigate(this._basePath + to, options);
190
+ }
191
+ /**
192
+ * Navigate to a page by its page ID.
193
+ * Looks up the route pattern from the page registry and builds the URL.
194
+ */
195
+ navigateToPage(pageId, params, options) {
196
+ const path = this.buildPagePath(pageId, params);
197
+ this.navigate(this.stripBasePath(path), options);
198
+ }
199
+ /**
200
+ * Build a URL path for a page ID with the given params.
201
+ * Path params are substituted into the route pattern; extra params become query string.
202
+ */
203
+ buildPagePath(pageId, params) {
204
+ const pattern = this.pageRegistry[pageId];
205
+ if (!pattern) {
206
+ throw new Error(`[buzola] Unknown page "${pageId}". Is it registered in the page registry?`);
207
+ }
208
+ const resolved = this.resolveParams(pattern, params);
209
+ return this.buildPath(pattern, resolved);
210
+ }
211
+ /**
212
+ * Go back in history.
213
+ */
214
+ back() {
215
+ this.adapter.back();
216
+ }
217
+ /**
218
+ * Go forward in history.
219
+ */
220
+ forward() {
221
+ this.adapter.forward();
222
+ }
223
+ /**
224
+ * Build a URL from a path pattern and params.
225
+ * The returned path includes the base path prefix.
226
+ */
227
+ buildPath(pattern, params) {
228
+ const segments = pattern.split('/');
229
+ const result = [];
230
+ const missing = [];
231
+ for (const segment of segments) {
232
+ if (segment.startsWith(':')) {
233
+ // Catch-all param (:slug+)
234
+ const isCatchAll = segment.endsWith('+');
235
+ const paramName = isCatchAll ? segment.slice(1, -1) : segment.slice(1);
236
+ const value = params?.[paramName];
237
+ if (value === undefined) {
238
+ missing.push(paramName);
239
+ }
240
+ else {
241
+ if (isCatchAll) {
242
+ // Catch-all values may contain slashes — insert raw
243
+ result.push(value);
244
+ }
245
+ else {
246
+ result.push(encodeURIComponent(value));
247
+ }
248
+ }
249
+ }
250
+ else {
251
+ result.push(segment);
252
+ }
253
+ }
254
+ if (missing.length > 0) {
255
+ if (!params) {
256
+ throw new Error(`Missing params for path "${pattern}": ${missing.join(', ')}`);
257
+ }
258
+ throw new Error(`Missing param "${missing[0]}" for path "${pattern}"`);
259
+ }
260
+ // Extra params (not in path pattern) → query string
261
+ const pathParamNames = new Set(extractParamNames(pattern));
262
+ const search = new URLSearchParams();
263
+ if (params) {
264
+ for (const [key, value] of Object.entries(params)) {
265
+ if (!pathParamNames.has(key) && value !== undefined) {
266
+ search.set(key, value);
267
+ }
268
+ }
269
+ }
270
+ const path = this._basePath + result.join('/');
271
+ const qs = search.toString();
272
+ return qs ? `${path}?${qs}` : path;
273
+ }
274
+ /**
275
+ * Strip the base path prefix from a pathname.
276
+ * Returns the pathname relative to the base path.
277
+ */
278
+ stripBasePath(pathname) {
279
+ if (this._basePath && pathname.startsWith(this._basePath)) {
280
+ return pathname.slice(this._basePath.length) || '/';
281
+ }
282
+ return pathname;
283
+ }
284
+ /**
285
+ * Resolve params for a route pattern by merging:
286
+ * 1. Explicitly provided params (highest priority)
287
+ * 2. Current URL match params
288
+ * 3. persistentParams() callback (fallback)
289
+ *
290
+ * Only fills params that are present in the target pattern.
291
+ */
292
+ resolveParams(pattern, explicitParams) {
293
+ const paramNames = this.extractParamNames(pattern);
294
+ const currentParams = this.getCurrentParams();
295
+ const fallbackParams = this.persistentParamsFn?.() ?? {};
296
+ const result = {};
297
+ for (const name of paramNames) {
298
+ const value = explicitParams?.[name] ?? currentParams[name] ?? fallbackParams[name];
299
+ if (value !== undefined) {
300
+ result[name] = value;
301
+ }
302
+ }
303
+ // Pass through extra explicit params (not in pattern) for search params
304
+ if (explicitParams) {
305
+ const pathParamNames = new Set(paramNames);
306
+ for (const [key, value] of Object.entries(explicitParams)) {
307
+ if (!pathParamNames.has(key) && value !== undefined) {
308
+ result[key] = value;
309
+ }
310
+ }
311
+ }
312
+ return result;
313
+ }
314
+ /**
315
+ * Extract parameter names from a route pattern.
316
+ */
317
+ extractParamNames(pattern) {
318
+ return extractParamNames(pattern);
319
+ }
320
+ /**
321
+ * Get merged params from all current route matches.
322
+ */
323
+ getCurrentParams() {
324
+ const params = {};
325
+ for (const match of this.state.matches) {
326
+ Object.assign(params, match.params);
327
+ }
328
+ return params;
329
+ }
330
+ /**
331
+ * Trigger all registered invalidation listeners.
332
+ * Used to re-run page loaders in the background.
333
+ */
334
+ invalidateAll() {
335
+ for (const listener of this.invalidationListeners) {
336
+ listener();
337
+ }
338
+ }
339
+ /**
340
+ * Register an invalidation listener. Returns an unsubscribe function.
341
+ */
342
+ onInvalidate(listener) {
343
+ this.invalidationListeners.add(listener);
344
+ return () => {
345
+ this.invalidationListeners.delete(listener);
346
+ };
347
+ }
348
+ /**
349
+ * Register a navigation blocker.
350
+ * The blocker function is called before each navigation.
351
+ * It must return a Promise that resolves to `true` to allow or `false` to block.
352
+ * Returns an unsubscribe function.
353
+ */
354
+ addBlocker(fn) {
355
+ this.blockers.add(fn);
356
+ return () => {
357
+ this.blockers.delete(fn);
358
+ };
359
+ }
360
+ /**
361
+ * Dispose the router — clear all subscribers and reset state.
362
+ */
363
+ dispose() {
364
+ this.stopFn?.();
365
+ this.stopFn = undefined;
366
+ this.subscribers.clear();
367
+ this.invalidationListeners.clear();
368
+ }
369
+ /**
370
+ * Update the route tree (for HMR).
371
+ */
372
+ updateRoutes(routes) {
373
+ this.routes = routes;
374
+ // Re-match current URL with new routes
375
+ const matches = matchRoutes(this.routes, this.createMatchUrl(this.state.location)) ?? [];
376
+ this.setState({
377
+ ...this.state,
378
+ matches,
379
+ });
380
+ }
381
+ /**
382
+ * Create a URL with basePath stripped for route matching.
383
+ */
384
+ createMatchUrl(url) {
385
+ if (!this._basePath)
386
+ return url;
387
+ const stripped = new URL(url);
388
+ if (stripped.pathname.startsWith(this._basePath)) {
389
+ stripped.pathname = stripped.pathname.slice(this._basePath.length) || '/';
390
+ }
391
+ return stripped;
392
+ }
393
+ setState(newState) {
394
+ this.state = newState;
395
+ for (const subscriber of this.subscribers) {
396
+ subscriber(this.state);
397
+ }
398
+ }
399
+ }
400
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/engine/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { StandardSchema } from './types';
2
+ /**
3
+ * Built-in minimal Standard Schema builders for route params.
4
+ * Use these when you don't need a full schema library like Zod or Valibot.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { s } from '@buzola/router'
9
+ *
10
+ * const page = createPage()
11
+ * .params({ id: s.string(), tab: s.optional(s.string()) })
12
+ * .route('/project/:id')
13
+ * .render(({ params }) => <div>{params.id}</div>)
14
+ * ```
15
+ *
16
+ * Or use string literals for common types:
17
+ * ```ts
18
+ * createPage()
19
+ * .params({ id: 'uuid', order: 'number', text: '?string', tags: '?string[]' })
20
+ * ```
21
+ */
22
+ declare function string(): StandardSchema<string>;
23
+ declare function optional(schema: StandardSchema<string>): StandardSchema<string | undefined>;
24
+ export declare function isOptionalSchema(schema: StandardSchema): boolean;
25
+ declare function object<T extends Record<string, StandardSchema>>(shape: T): StandardSchema<{
26
+ [K in keyof T]: T[K] extends StandardSchema<infer V> ? V : never;
27
+ }> & {
28
+ __buzolaKeys: {
29
+ name: string;
30
+ optional: boolean;
31
+ array: boolean;
32
+ }[];
33
+ };
34
+ export declare const s: {
35
+ object: typeof object;
36
+ string: typeof string;
37
+ optional: typeof optional;
38
+ };
39
+ export type ParamLiteral = 'string' | 'number' | 'uuid' | '?string' | '?number' | '?uuid' | 'string[]' | 'number[]' | '?string[]' | '?number[]';
40
+ export declare function resolveParamLiteral(literal: ParamLiteral): {
41
+ schema: StandardSchema;
42
+ optional: boolean;
43
+ array: boolean;
44
+ };
45
+ export {};
46
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/engine/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,iBAAS,MAAM,IAAI,cAAc,CAAC,MAAM,CAAC,CAQxC;AAED,iBAAS,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,CAQpF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAGhE;AAED,iBAAS,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EACvD,KAAK,EAAE,CAAC,GACN,cAAc,CAAC;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CAAE,CAAC,GAAG;IACzF,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CACnE,CAkBA;AAED,eAAO,MAAM,CAAC;;;;CAA+B,CAAA;AAI7C,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,CAAA;AAe/I,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG;IAC3D,MAAM,EAAE,cAAc,CAAA;IACtB,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,OAAO,CAAA;CACd,CAkCA"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Built-in minimal Standard Schema builders for route params.
3
+ * Use these when you don't need a full schema library like Zod or Valibot.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { s } from '@buzola/router'
8
+ *
9
+ * const page = createPage()
10
+ * .params({ id: s.string(), tab: s.optional(s.string()) })
11
+ * .route('/project/:id')
12
+ * .render(({ params }) => <div>{params.id}</div>)
13
+ * ```
14
+ *
15
+ * Or use string literals for common types:
16
+ * ```ts
17
+ * createPage()
18
+ * .params({ id: 'uuid', order: 'number', text: '?string', tags: '?string[]' })
19
+ * ```
20
+ */
21
+ function string() {
22
+ return {
23
+ '~standard': {
24
+ version: 1,
25
+ vendor: 'buzola',
26
+ validate: (v) => typeof v === 'string' ? { value: v } : { issues: [{ message: 'expected string' }] },
27
+ },
28
+ };
29
+ }
30
+ function optional(schema) {
31
+ return {
32
+ '~standard': {
33
+ version: 1,
34
+ vendor: 'buzola',
35
+ validate: (v) => v === undefined || v === '' ? { value: undefined } : schema['~standard'].validate(v),
36
+ },
37
+ };
38
+ }
39
+ export function isOptionalSchema(schema) {
40
+ const result = schema['~standard'].validate(undefined);
41
+ return !('issues' in result);
42
+ }
43
+ function object(shape) {
44
+ return {
45
+ __buzolaKeys: Object.entries(shape).map(([name, s]) => ({ name, optional: isOptionalSchema(s), array: false })),
46
+ '~standard': {
47
+ version: 1,
48
+ vendor: 'buzola',
49
+ validate: (v) => {
50
+ const input = (v ?? {});
51
+ const result = {};
52
+ for (const [key, schema] of Object.entries(shape)) {
53
+ const r = schema['~standard'].validate(input[key]);
54
+ if ('issues' in r)
55
+ return r;
56
+ result[key] = r.value;
57
+ }
58
+ return { value: result };
59
+ },
60
+ },
61
+ };
62
+ }
63
+ export const s = { object, string, optional };
64
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
65
+ const scalarValidators = {
66
+ string: (v) => typeof v === 'string' ? { value: v } : { issues: [{ message: 'expected string' }] },
67
+ number: (v) => {
68
+ const n = Number(v);
69
+ return Number.isNaN(n) ? { issues: [{ message: 'expected number' }] } : { value: n };
70
+ },
71
+ uuid: (v) => typeof v === 'string' && UUID_RE.test(v) ? { value: v } : { issues: [{ message: 'expected UUID' }] },
72
+ };
73
+ export function resolveParamLiteral(literal) {
74
+ const isOpt = literal.startsWith('?');
75
+ const rest = isOpt ? literal.slice(1) : literal;
76
+ const isArr = rest.endsWith('[]');
77
+ const baseType = isArr ? rest.slice(0, -2) : rest;
78
+ const validateScalar = scalarValidators[baseType];
79
+ if (!validateScalar)
80
+ throw new Error(`Unknown param type: ${baseType}`);
81
+ let validate;
82
+ if (isArr) {
83
+ validate = (v) => {
84
+ if (isOpt && (v === undefined || (Array.isArray(v) && v.length === 0)))
85
+ return { value: undefined };
86
+ if (!Array.isArray(v))
87
+ return { issues: [{ message: `expected ${baseType}[]` }] };
88
+ const result = [];
89
+ for (const item of v) {
90
+ const r = validateScalar(item);
91
+ if ('issues' in r)
92
+ return r;
93
+ result.push(r.value);
94
+ }
95
+ return { value: result };
96
+ };
97
+ }
98
+ else if (isOpt) {
99
+ validate = (v) => v === undefined || v === '' ? { value: undefined } : validateScalar(v);
100
+ }
101
+ else {
102
+ validate = validateScalar;
103
+ }
104
+ return {
105
+ schema: { '~standard': { version: 1, vendor: 'buzola', validate } },
106
+ optional: isOpt,
107
+ array: isArr,
108
+ };
109
+ }
110
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/engine/schema.ts"],"names":[],"mappings":"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"}