@genesislcap/foundation-react-utils 14.496.2-alpha-2c4a633.0 → 14.498.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.
- package/dist/custom-elements.json +245 -0
- package/dist/dts/router/app-routes.d.ts +69 -0
- package/dist/dts/router/app-routes.d.ts.map +1 -0
- package/dist/dts/router/index.d.ts +33 -0
- package/dist/dts/router/index.d.ts.map +1 -0
- package/dist/dts/router/pbc-routes.d.ts +36 -0
- package/dist/dts/router/pbc-routes.d.ts.map +1 -0
- package/dist/dts/router/post-login-redirect.d.ts +25 -0
- package/dist/dts/router/post-login-redirect.d.ts.map +1 -0
- package/dist/dts/router/protected-route.d.ts +80 -0
- package/dist/dts/router/protected-route.d.ts.map +1 -0
- package/dist/dts/router/router.test.d.ts +2 -0
- package/dist/dts/router/router.test.d.ts.map +1 -0
- package/dist/dts/router/single-component.d.ts +52 -0
- package/dist/dts/router/single-component.d.ts.map +1 -0
- package/dist/esm/router/app-routes.js +32 -0
- package/dist/esm/router/index.js +27 -0
- package/dist/esm/router/pbc-routes.js +19 -0
- package/dist/esm/router/post-login-redirect.js +14 -0
- package/dist/esm/router/protected-route.js +46 -0
- package/dist/esm/router/router.test.js +82 -0
- package/dist/esm/router/single-component.js +51 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +39 -14
- package/src/router/app-routes.tsx +141 -0
- package/src/router/index.ts +41 -0
- package/src/router/pbc-routes.ts +56 -0
- package/src/router/post-login-redirect.ts +29 -0
- package/src/router/protected-route.tsx +121 -0
- package/src/router/router.test.ts +107 -0
- package/src/router/single-component.tsx +94 -0
|
@@ -263,6 +263,251 @@
|
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
265
|
]
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"kind": "javascript-module",
|
|
269
|
+
"path": "src/router/index.ts",
|
|
270
|
+
"declarations": [],
|
|
271
|
+
"exports": [
|
|
272
|
+
{
|
|
273
|
+
"kind": "js",
|
|
274
|
+
"name": "ProtectedRoute",
|
|
275
|
+
"declaration": {
|
|
276
|
+
"name": "ProtectedRoute",
|
|
277
|
+
"module": "./protected-route"
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"kind": "js",
|
|
282
|
+
"name": "createProtectedRoute",
|
|
283
|
+
"declaration": {
|
|
284
|
+
"name": "createProtectedRoute",
|
|
285
|
+
"module": "./protected-route"
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"kind": "js",
|
|
290
|
+
"name": "ProtectedRouteProps",
|
|
291
|
+
"declaration": {
|
|
292
|
+
"name": "ProtectedRouteProps",
|
|
293
|
+
"module": "./protected-route"
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
"kind": "js",
|
|
298
|
+
"name": "BoundProtectedRouteProps",
|
|
299
|
+
"declaration": {
|
|
300
|
+
"name": "BoundProtectedRouteProps",
|
|
301
|
+
"module": "./protected-route"
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"kind": "js",
|
|
306
|
+
"name": "CreateProtectedRouteOptions",
|
|
307
|
+
"declaration": {
|
|
308
|
+
"name": "CreateProtectedRouteOptions",
|
|
309
|
+
"module": "./protected-route"
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"kind": "js",
|
|
314
|
+
"name": "buildPostLoginRedirect",
|
|
315
|
+
"declaration": {
|
|
316
|
+
"name": "buildPostLoginRedirect",
|
|
317
|
+
"module": "./post-login-redirect"
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"kind": "js",
|
|
322
|
+
"name": "RedirectableLocationState",
|
|
323
|
+
"declaration": {
|
|
324
|
+
"name": "RedirectableLocationState",
|
|
325
|
+
"module": "./post-login-redirect"
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"kind": "js",
|
|
330
|
+
"name": "readInitialParam",
|
|
331
|
+
"declaration": {
|
|
332
|
+
"name": "readInitialParam",
|
|
333
|
+
"module": "./single-component"
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"kind": "js",
|
|
338
|
+
"name": "createComponentRegistry",
|
|
339
|
+
"declaration": {
|
|
340
|
+
"name": "createComponentRegistry",
|
|
341
|
+
"module": "./single-component"
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"kind": "js",
|
|
346
|
+
"name": "SingleComponentOutlet",
|
|
347
|
+
"declaration": {
|
|
348
|
+
"name": "SingleComponentOutlet",
|
|
349
|
+
"module": "./single-component"
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
"kind": "js",
|
|
354
|
+
"name": "ComponentRegistry",
|
|
355
|
+
"declaration": {
|
|
356
|
+
"name": "ComponentRegistry",
|
|
357
|
+
"module": "./single-component"
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"kind": "js",
|
|
362
|
+
"name": "SingleComponentOutletProps",
|
|
363
|
+
"declaration": {
|
|
364
|
+
"name": "SingleComponentOutletProps",
|
|
365
|
+
"module": "./single-component"
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"kind": "js",
|
|
370
|
+
"name": "renderAppRoutes",
|
|
371
|
+
"declaration": {
|
|
372
|
+
"name": "renderAppRoutes",
|
|
373
|
+
"module": "./app-routes"
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
"kind": "js",
|
|
378
|
+
"name": "AppRouteConfig",
|
|
379
|
+
"declaration": {
|
|
380
|
+
"name": "AppRouteConfig",
|
|
381
|
+
"module": "./app-routes"
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
"kind": "js",
|
|
386
|
+
"name": "RouteRedirect",
|
|
387
|
+
"declaration": {
|
|
388
|
+
"name": "RouteRedirect",
|
|
389
|
+
"module": "./app-routes"
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"kind": "js",
|
|
394
|
+
"name": "RenderAppRoutesOptions",
|
|
395
|
+
"declaration": {
|
|
396
|
+
"name": "RenderAppRoutesOptions",
|
|
397
|
+
"module": "./app-routes"
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"kind": "js",
|
|
402
|
+
"name": "mergePbcRoutes",
|
|
403
|
+
"declaration": {
|
|
404
|
+
"name": "mergePbcRoutes",
|
|
405
|
+
"module": "./pbc-routes"
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
"kind": "js",
|
|
410
|
+
"name": "PbcRouteInput",
|
|
411
|
+
"declaration": {
|
|
412
|
+
"name": "PbcRouteInput",
|
|
413
|
+
"module": "./pbc-routes"
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"kind": "js",
|
|
418
|
+
"name": "MergePbcRoutesOptions",
|
|
419
|
+
"declaration": {
|
|
420
|
+
"name": "MergePbcRoutesOptions",
|
|
421
|
+
"module": "./pbc-routes"
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
"kind": "javascript-module",
|
|
428
|
+
"path": "src/router/pbc-routes.ts",
|
|
429
|
+
"declarations": [
|
|
430
|
+
{
|
|
431
|
+
"kind": "function",
|
|
432
|
+
"name": "mergePbcRoutes",
|
|
433
|
+
"return": {
|
|
434
|
+
"type": {
|
|
435
|
+
"text": "AppRouteConfig[]"
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
"parameters": [
|
|
439
|
+
{
|
|
440
|
+
"name": "staticRoutes",
|
|
441
|
+
"type": {
|
|
442
|
+
"text": "AppRouteConfig[]"
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"name": "pbcRoutes",
|
|
447
|
+
"type": {
|
|
448
|
+
"text": "PbcRouteInput[]"
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
"name": "{ renderPbc }",
|
|
453
|
+
"type": {
|
|
454
|
+
"text": "MergePbcRoutesOptions"
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
"description": "Merge a static route table with PBC routes (e.g. from `getApp().routes`) into\none AppRouteConfig array. PBC routes are guarded, in-layout, and carry\ntheir element/tag + navItems through `data` so downstream consumers (a PBC\ncontainer, nav-item derivation) can read them — matching the `data` shape the\nhand-rolled version produced."
|
|
459
|
+
}
|
|
460
|
+
],
|
|
461
|
+
"exports": [
|
|
462
|
+
{
|
|
463
|
+
"kind": "js",
|
|
464
|
+
"name": "mergePbcRoutes",
|
|
465
|
+
"declaration": {
|
|
466
|
+
"name": "mergePbcRoutes",
|
|
467
|
+
"module": "src/router/pbc-routes.ts"
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
]
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"kind": "javascript-module",
|
|
474
|
+
"path": "src/router/post-login-redirect.ts",
|
|
475
|
+
"declarations": [
|
|
476
|
+
{
|
|
477
|
+
"kind": "function",
|
|
478
|
+
"name": "buildPostLoginRedirect",
|
|
479
|
+
"return": {
|
|
480
|
+
"type": {
|
|
481
|
+
"text": "string"
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
"parameters": [
|
|
485
|
+
{
|
|
486
|
+
"name": "location",
|
|
487
|
+
"type": {
|
|
488
|
+
"text": "{ state?: RedirectableLocationState | null }"
|
|
489
|
+
},
|
|
490
|
+
"description": "The current router location (needs only `state.from`)."
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"name": "defaultPath",
|
|
494
|
+
"default": "'/'",
|
|
495
|
+
"description": "Where to land when nothing was stashed. Defaults to `/`."
|
|
496
|
+
}
|
|
497
|
+
],
|
|
498
|
+
"description": "Build the post-login redirect target from a router location's `state.from`,\npreserving the query string and hash so deep-link params (e.g.\n`?component=<name>`) survive the login bounce. Falls back to `defaultPath`\nwhen there is no stashed origin."
|
|
499
|
+
}
|
|
500
|
+
],
|
|
501
|
+
"exports": [
|
|
502
|
+
{
|
|
503
|
+
"kind": "js",
|
|
504
|
+
"name": "buildPostLoginRedirect",
|
|
505
|
+
"declaration": {
|
|
506
|
+
"name": "buildPostLoginRedirect",
|
|
507
|
+
"module": "src/router/post-login-redirect.ts"
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
]
|
|
266
511
|
}
|
|
267
512
|
]
|
|
268
513
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ComponentType, ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { BoundProtectedRouteProps } from './protected-route';
|
|
3
|
+
/**
|
|
4
|
+
* Declarative description of one app route. The `element` is rendered when the
|
|
5
|
+
* path matches; guarding, layout nesting, and permission are derived from the
|
|
6
|
+
* flags below so the app doesn't hand-write the `<Route>`/`<ProtectedRoute>`
|
|
7
|
+
* boilerplate per route.
|
|
8
|
+
*/
|
|
9
|
+
export interface AppRouteConfig {
|
|
10
|
+
path: string;
|
|
11
|
+
element: ReactNode;
|
|
12
|
+
/** Skip the auth guard (e.g. login, not-permitted). Default `false`. */
|
|
13
|
+
public?: boolean;
|
|
14
|
+
/** Render outside the shared layout. Default `false` (guarded routes sit in the layout). */
|
|
15
|
+
noLayout?: boolean;
|
|
16
|
+
/** Permission code handed to the guard's optional permission check. */
|
|
17
|
+
permissionCode?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Nested child routes rendered inside this route's `element` (which must
|
|
20
|
+
* render an `<Outlet />`). Children use paths relative to this route and
|
|
21
|
+
* inherit its guard — they are rendered as plain routes, not re-guarded.
|
|
22
|
+
*/
|
|
23
|
+
children?: AppRouteConfig[];
|
|
24
|
+
/** Arbitrary metadata preserved for other consumers (nav items, PBC info, ...). */
|
|
25
|
+
data?: Record<string, any>;
|
|
26
|
+
}
|
|
27
|
+
/** A simple `from → to` redirect. */
|
|
28
|
+
export interface RouteRedirect {
|
|
29
|
+
from: string;
|
|
30
|
+
to: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Options for {@link renderAppRoutes}.
|
|
34
|
+
*/
|
|
35
|
+
export interface RenderAppRoutesOptions {
|
|
36
|
+
/** The full route table (static + any merged PBC routes). */
|
|
37
|
+
routes: AppRouteConfig[];
|
|
38
|
+
/**
|
|
39
|
+
* Guard component (typically from `createProtectedRoute`) wrapping every
|
|
40
|
+
* non-public route; receives each route's `permissionCode`.
|
|
41
|
+
*/
|
|
42
|
+
ProtectedRoute: ComponentType<BoundProtectedRouteProps>;
|
|
43
|
+
/**
|
|
44
|
+
* Layout route element (rendering an `<Outlet />`) that wraps in-layout
|
|
45
|
+
* routes. Omit to render every route at the top level.
|
|
46
|
+
*/
|
|
47
|
+
layout?: ReactElement;
|
|
48
|
+
/** `from → to` redirects rendered before the routes. */
|
|
49
|
+
redirects?: RouteRedirect[];
|
|
50
|
+
/** Element for unmatched paths (`*`). */
|
|
51
|
+
notFound?: ReactNode;
|
|
52
|
+
/**
|
|
53
|
+
* When `name` is truthy, short-circuit to single-component mode: render only
|
|
54
|
+
* the public routes (so login / session-restore still work) plus a catch-all
|
|
55
|
+
* rendering `element` behind the guard. See the single-component deep-link.
|
|
56
|
+
*/
|
|
57
|
+
singleComponent?: {
|
|
58
|
+
name: string | null | undefined;
|
|
59
|
+
element: ReactNode;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build the app's `<Routes>` tree from a declarative route table, applying the
|
|
64
|
+
* auth guard, layout nesting, redirects, not-found, and the single-component
|
|
65
|
+
* short-circuit — so a consuming app configures routes instead of hand-writing
|
|
66
|
+
* repetitive `<Route element={<ProtectedRoute>…}>` markup.
|
|
67
|
+
*/
|
|
68
|
+
export declare function renderAppRoutes({ routes, ProtectedRoute, layout, redirects, notFound, singleComponent, }: RenderAppRoutesOptions): ReactElement;
|
|
69
|
+
//# sourceMappingURL=app-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-routes.d.ts","sourceRoot":"","sources":["../../../src/router/app-routes.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAElE;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,CAAC;IACnB,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5B,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,6DAA6D;IAC7D,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB;;;OAGG;IACH,cAAc,EAAE,aAAa,CAAC,wBAAwB,CAAC,CAAC;IACxD;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,wDAAwD;IACxD,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;IAC5B,yCAAyC;IACzC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;OAIG;IACH,eAAe,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,SAAS,CAAA;KAAE,CAAC;CAC3E;AAKD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC9B,MAAM,EACN,cAAc,EACd,MAAM,EACN,SAAc,EACd,QAAQ,EACR,eAAe,GAChB,EAAE,sBAAsB,GAAG,YAAY,CA6DvC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@genesislcap/foundation-react-utils/router`
|
|
3
|
+
*
|
|
4
|
+
* Reusable `react-router-dom` primitives for Genesis Foundation React apps, so
|
|
5
|
+
* the app-shell routing logic doesn't have to be reimplemented per app.
|
|
6
|
+
*
|
|
7
|
+
* Exposed as a subpath (`/router`) rather than from the package root so that
|
|
8
|
+
* consumers which don't route (and don't depend on `react-router-dom`) are
|
|
9
|
+
* unaffected.
|
|
10
|
+
*
|
|
11
|
+
* Key exports:
|
|
12
|
+
* - `ProtectedRoute` / `createProtectedRoute` — auth + permission gate that
|
|
13
|
+
* stashes the full origin location (incl. `search` + `hash`) for post-login
|
|
14
|
+
* restore, and redirects to a not-permitted path when authorized-but-blocked.
|
|
15
|
+
* - `buildPostLoginRedirect` — rebuild the return URL preserving query + hash.
|
|
16
|
+
* - `readInitialParam` / `createComponentRegistry` / `SingleComponentOutlet` —
|
|
17
|
+
* render a single registered component full-screen from a `?param=<name>`
|
|
18
|
+
* deep-link captured before the shell strips the query string.
|
|
19
|
+
* - `renderAppRoutes` — build the app's `<Routes>` from a declarative route
|
|
20
|
+
* table (guarding, layout nesting, redirects, not-found, single-component).
|
|
21
|
+
* - `mergePbcRoutes` — merge static routes with shell/PBC routes into one table.
|
|
22
|
+
*/
|
|
23
|
+
export { ProtectedRoute, createProtectedRoute } from './protected-route';
|
|
24
|
+
export type { ProtectedRouteProps, BoundProtectedRouteProps, CreateProtectedRouteOptions, } from './protected-route';
|
|
25
|
+
export { buildPostLoginRedirect } from './post-login-redirect';
|
|
26
|
+
export type { RedirectableLocationState } from './post-login-redirect';
|
|
27
|
+
export { readInitialParam, createComponentRegistry, SingleComponentOutlet, } from './single-component';
|
|
28
|
+
export type { ComponentRegistry, SingleComponentOutletProps } from './single-component';
|
|
29
|
+
export { renderAppRoutes } from './app-routes';
|
|
30
|
+
export type { AppRouteConfig, RouteRedirect, RenderAppRoutesOptions } from './app-routes';
|
|
31
|
+
export { mergePbcRoutes } from './pbc-routes';
|
|
32
|
+
export type { PbcRouteInput, MergePbcRoutesOptions } from './pbc-routes';
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/router/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzE,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,YAAY,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { AppRouteConfig } from './app-routes';
|
|
3
|
+
/**
|
|
4
|
+
* Minimal shape of a PBC route as provided by the shell (e.g. `getApp().routes`).
|
|
5
|
+
* Kept as an input type — rather than importing `foundation-shell` — so this
|
|
6
|
+
* helper stays dependency-free and the `/router` subpath doesn't pull the shell
|
|
7
|
+
* into apps that don't use PBCs.
|
|
8
|
+
*/
|
|
9
|
+
export interface PbcRouteInput {
|
|
10
|
+
path: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
/** The PBC element (module/loader) the container will mount. */
|
|
13
|
+
element?: unknown;
|
|
14
|
+
/** Explicit custom-element tag, if the container shouldn't derive one. */
|
|
15
|
+
elementTag?: string;
|
|
16
|
+
/** Nav items contributed by this PBC. */
|
|
17
|
+
navItems?: unknown;
|
|
18
|
+
/** Extra per-route settings (e.g. `permissionCode`), spread into `data`. */
|
|
19
|
+
settings?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Options for {@link mergePbcRoutes}.
|
|
23
|
+
*/
|
|
24
|
+
export interface MergePbcRoutesOptions {
|
|
25
|
+
/** Render the element for a PBC route (typically `() => <PBCContainer />`). */
|
|
26
|
+
renderPbc: (pbc: PbcRouteInput) => ReactNode;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Merge a static route table with PBC routes (e.g. from `getApp().routes`) into
|
|
30
|
+
* one {@link AppRouteConfig} array. PBC routes are guarded, in-layout, and carry
|
|
31
|
+
* their element/tag + navItems through `data` so downstream consumers (a PBC
|
|
32
|
+
* container, nav-item derivation) can read them — matching the `data` shape the
|
|
33
|
+
* hand-rolled version produced.
|
|
34
|
+
*/
|
|
35
|
+
export declare function mergePbcRoutes(staticRoutes: AppRouteConfig[], pbcRoutes: PbcRouteInput[], { renderPbc }: MergePbcRoutesOptions): AppRouteConfig[];
|
|
36
|
+
//# sourceMappingURL=pbc-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pbc-routes.d.ts","sourceRoot":"","sources":["../../../src/router/pbc-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,SAAS,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,SAAS,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,cAAc,EAAE,EAC9B,SAAS,EAAE,aAAa,EAAE,EAC1B,EAAE,SAAS,EAAE,EAAE,qBAAqB,GACnC,cAAc,EAAE,CAclB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape of the router location `state` that a route guard stashes before
|
|
3
|
+
* redirecting to login. Structural, so it works with `react-router-dom`'s
|
|
4
|
+
* `Location` without importing it here.
|
|
5
|
+
*/
|
|
6
|
+
export interface RedirectableLocationState {
|
|
7
|
+
from?: {
|
|
8
|
+
pathname: string;
|
|
9
|
+
search?: string;
|
|
10
|
+
hash?: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build the post-login redirect target from a router location's `state.from`,
|
|
15
|
+
* preserving the query string and hash so deep-link params (e.g.
|
|
16
|
+
* `?component=<name>`) survive the login bounce. Falls back to `defaultPath`
|
|
17
|
+
* when there is no stashed origin.
|
|
18
|
+
*
|
|
19
|
+
* @param location - The current router location (needs only `state.from`).
|
|
20
|
+
* @param defaultPath - Where to land when nothing was stashed. Defaults to `/`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildPostLoginRedirect(location: {
|
|
23
|
+
state?: RedirectableLocationState | null;
|
|
24
|
+
}, defaultPath?: string): string;
|
|
25
|
+
//# sourceMappingURL=post-login-redirect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-login-redirect.d.ts","sourceRoot":"","sources":["../../../src/router/post-login-redirect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE;IAAE,KAAK,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAA;CAAE,EACtD,WAAW,SAAM,GAChB,MAAM,CAGR"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for {@link ProtectedRoute}.
|
|
4
|
+
*/
|
|
5
|
+
export interface ProtectedRouteProps {
|
|
6
|
+
/** Whether the current user is authenticated. */
|
|
7
|
+
isAuthenticated: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Whether the current user may view this route. When `false` (and
|
|
10
|
+
* authenticated), redirects to `notPermittedPath` instead of rendering.
|
|
11
|
+
* Defaults to `true`.
|
|
12
|
+
*/
|
|
13
|
+
hasPermission?: boolean;
|
|
14
|
+
/** Path to redirect to when unauthenticated. Defaults to `/login`. */
|
|
15
|
+
loginPath?: string;
|
|
16
|
+
/** Path to redirect to when authenticated but not permitted. Defaults to `/not-permitted`. */
|
|
17
|
+
notPermittedPath?: string;
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Route guard. In order:
|
|
22
|
+
* - not authenticated → redirect to `loginPath`, stashing the full current
|
|
23
|
+
* location in `state.from` (incl. `search` + `hash`) so the login flow can
|
|
24
|
+
* restore the original deep-link via {@link buildPostLoginRedirect};
|
|
25
|
+
* - authenticated but `hasPermission === false` → redirect to `notPermittedPath`;
|
|
26
|
+
* - otherwise → render `children`.
|
|
27
|
+
*
|
|
28
|
+
* Deliberately decoupled from any auth package — pass the booleans in (or use
|
|
29
|
+
* {@link createProtectedRoute} to bind the checks once).
|
|
30
|
+
*/
|
|
31
|
+
export declare function ProtectedRoute({ isAuthenticated, hasPermission, loginPath, notPermittedPath, children, }: ProtectedRouteProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
/**
|
|
33
|
+
* Props of the component returned by {@link createProtectedRoute}. `permissionCode`
|
|
34
|
+
* is forwarded to the bound `hasPermission` check (e.g. by {@link renderAppRoutes}).
|
|
35
|
+
*/
|
|
36
|
+
export interface BoundProtectedRouteProps {
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
/** Route permission code handed to the bound `hasPermission` check. */
|
|
39
|
+
permissionCode?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Options for {@link createProtectedRoute}.
|
|
43
|
+
*/
|
|
44
|
+
export interface CreateProtectedRouteOptions {
|
|
45
|
+
/**
|
|
46
|
+
* Called at render time to determine auth state. Kept as a function (not a
|
|
47
|
+
* boolean) so it is re-evaluated on every render and the util stays free of
|
|
48
|
+
* any specific auth dependency.
|
|
49
|
+
*/
|
|
50
|
+
getIsAuthenticated: () => boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Optional per-route permission check, called at render time with the route's
|
|
53
|
+
* `permissionCode`. Absent → every authenticated user is permitted.
|
|
54
|
+
*/
|
|
55
|
+
hasPermission?: (permissionCode: string | undefined) => boolean;
|
|
56
|
+
/** Path to redirect to when unauthenticated. Defaults to `/login`. */
|
|
57
|
+
loginPath?: string;
|
|
58
|
+
/** Path to redirect to when authenticated but not permitted. Defaults to `/not-permitted`. */
|
|
59
|
+
notPermittedPath?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Bind auth (and optionally permission) checks once and get an ergonomic
|
|
63
|
+
* `<ProtectedRoute>` that only needs `children` (plus an optional
|
|
64
|
+
* `permissionCode`) — ideal when a route table wraps many elements.
|
|
65
|
+
*
|
|
66
|
+
* **Call this at module scope, never inside a component's render.** It returns a
|
|
67
|
+
* new component type each call; invoking it during render recreates that type
|
|
68
|
+
* every render, forcing React to unmount and remount the entire protected
|
|
69
|
+
* subtree (flicker + lost state).
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* const ProtectedRoute = createProtectedRoute({
|
|
74
|
+
* getIsAuthenticated: () => getUser().isAuthenticated,
|
|
75
|
+
* hasPermission: (code) => !code || canView(getUser(), code),
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function createProtectedRoute({ getIsAuthenticated, hasPermission, loginPath, notPermittedPath, }: CreateProtectedRouteOptions): ({ children, permissionCode }: BoundProtectedRouteProps) => import("react/jsx-runtime").JSX.Element;
|
|
80
|
+
//# sourceMappingURL=protected-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protected-route.d.ts","sourceRoot":"","sources":["../../../src/router/protected-route.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,EAC7B,eAAe,EACf,aAAoB,EACpB,SAAoB,EACpB,gBAAmC,EACnC,QAAQ,GACT,EAAE,mBAAmB,2CAYrB;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,OAAO,CAAC;IAClC;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC;IAChE,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,kBAAkB,EAClB,aAAa,EACb,SAAS,EACT,gBAAgB,GACjB,EAAE,2BAA2B,IACQ,8BAA8B,wBAAwB,6CAY3F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.test.d.ts","sourceRoot":"","sources":["../../../src/router/router.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Read a query-string parameter from the current URL.
|
|
4
|
+
*
|
|
5
|
+
* Call this at **module-evaluation time** in your app (i.e. as a top-level
|
|
6
|
+
* `const`), before the app shell's async bootstrap rewrites the URL and drops
|
|
7
|
+
* the query string, and store the result. That way a deep-link param such as
|
|
8
|
+
* `?component=<name>` survives even though it is gone by the time the router
|
|
9
|
+
* mounts.
|
|
10
|
+
*/
|
|
11
|
+
export declare function readInitialParam(key: string): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* A name → component registry with tolerant lookup. Create one with
|
|
14
|
+
* {@link createComponentRegistry}.
|
|
15
|
+
*/
|
|
16
|
+
export interface ComponentRegistry {
|
|
17
|
+
/** The underlying name → component map. */
|
|
18
|
+
entries: Record<string, ComponentType<any>>;
|
|
19
|
+
/** All registered names, for help/error output. */
|
|
20
|
+
available(): string[];
|
|
21
|
+
/** Resolve a registered component by name, tolerant of case and separators. */
|
|
22
|
+
resolve(name: string | null | undefined): ComponentType<any> | undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create a name → component registry whose `resolve` is case- and
|
|
26
|
+
* separator-insensitive (`LimitDistributionChart` === `limit-distribution-chart`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function createComponentRegistry(entries: Record<string, ComponentType<any>>): ComponentRegistry;
|
|
29
|
+
/**
|
|
30
|
+
* Props for {@link SingleComponentOutlet}.
|
|
31
|
+
*/
|
|
32
|
+
export interface SingleComponentOutletProps {
|
|
33
|
+
/** The requested component name (typically captured via {@link readInitialParam}). */
|
|
34
|
+
name: string | null | undefined;
|
|
35
|
+
/** Registry to resolve the name against. */
|
|
36
|
+
registry: ComponentRegistry;
|
|
37
|
+
/**
|
|
38
|
+
* Render when no component matches. Defaults to a plain, unstyled
|
|
39
|
+
* "Unknown component" message; pass your own to theme it.
|
|
40
|
+
*/
|
|
41
|
+
renderUnknown?: (name: string | null | undefined, available: string[]) => ReactNode;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve `name` against `registry` and render the matching component, or a
|
|
45
|
+
* fallback when unmatched.
|
|
46
|
+
*
|
|
47
|
+
* Theming/provider chrome is intentionally left to the caller — wrap this outlet
|
|
48
|
+
* in your app's design-system provider so the standalone component is themed
|
|
49
|
+
* identically to how it appears in-app.
|
|
50
|
+
*/
|
|
51
|
+
export declare function SingleComponentOutlet({ name, registry, renderUnknown, }: SingleComponentOutletProps): import("react/jsx-runtime").JSX.Element;
|
|
52
|
+
//# sourceMappingURL=single-component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"single-component.d.ts","sourceRoot":"","sources":["../../../src/router/single-component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG3D;AAKD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5C,mDAAmD;IACnD,SAAS,IAAI,MAAM,EAAE,CAAC;IACtB,+EAA+E;IAC/E,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;CAC1E;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,GAC1C,iBAAiB,CAiBnB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,sFAAsF;IACtF,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChC,4CAA4C;IAC5C,QAAQ,EAAE,iBAAiB,CAAC;IAC5B;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,SAAS,CAAC;CACrF;AAQD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,IAAI,EACJ,QAAQ,EACR,aAA8B,GAC/B,EAAE,0BAA0B,2CAG5B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Navigate, Route, Routes } from 'react-router-dom';
|
|
3
|
+
const resolvePermissionCode = (route) => { var _a, _b; return (_a = route.permissionCode) !== null && _a !== void 0 ? _a : (_b = route.data) === null || _b === void 0 ? void 0 : _b.permissionCode; };
|
|
4
|
+
/**
|
|
5
|
+
* Build the app's `<Routes>` tree from a declarative route table, applying the
|
|
6
|
+
* auth guard, layout nesting, redirects, not-found, and the single-component
|
|
7
|
+
* short-circuit — so a consuming app configures routes instead of hand-writing
|
|
8
|
+
* repetitive `<Route element={<ProtectedRoute>…}>` markup.
|
|
9
|
+
*/
|
|
10
|
+
export function renderAppRoutes({ routes, ProtectedRoute, layout, redirects = [], notFound, singleComponent, }) {
|
|
11
|
+
const publicRoutes = routes.filter((r) => r.public);
|
|
12
|
+
// Single-component mode: keep public routes reachable (login / session
|
|
13
|
+
// restore) and gate everything else behind the guard rendering the component.
|
|
14
|
+
if (singleComponent === null || singleComponent === void 0 ? void 0 : singleComponent.name) {
|
|
15
|
+
return (_jsxs(Routes, { children: [publicRoutes.map((r) => (_jsx(Route, { path: r.path, element: r.element }, r.path))), _jsx(Route, { path: "*", element: _jsx(ProtectedRoute, { children: singleComponent.element }) })] }));
|
|
16
|
+
}
|
|
17
|
+
const guarded = routes.filter((r) => !r.public);
|
|
18
|
+
const inLayout = guarded.filter((r) => !r.noLayout);
|
|
19
|
+
const topLevelGuarded = guarded.filter((r) => r.noLayout);
|
|
20
|
+
// Nested children render as plain relative routes inside the parent's
|
|
21
|
+
// `<Outlet />`; they inherit the parent's guard, so they are not re-wrapped.
|
|
22
|
+
const renderChild = (c) => {
|
|
23
|
+
var _a;
|
|
24
|
+
return ((_a = c.children) === null || _a === void 0 ? void 0 : _a.length) ? (_jsx(Route, { path: c.path, element: c.element, children: c.children.map(renderChild) }, c.path)) : (_jsx(Route, { path: c.path, element: c.element }, c.path));
|
|
25
|
+
};
|
|
26
|
+
const renderGuarded = (r) => {
|
|
27
|
+
var _a;
|
|
28
|
+
const element = (_jsx(ProtectedRoute, { permissionCode: resolvePermissionCode(r), children: r.element }));
|
|
29
|
+
return ((_a = r.children) === null || _a === void 0 ? void 0 : _a.length) ? (_jsx(Route, { path: r.path, element: element, children: r.children.map(renderChild) }, r.path)) : (_jsx(Route, { path: r.path, element: element }, r.path));
|
|
30
|
+
};
|
|
31
|
+
return (_jsxs(Routes, { children: [redirects.map((r) => (_jsx(Route, { path: r.from, element: _jsx(Navigate, { to: r.to, replace: true }) }, `redirect:${r.from}`))), publicRoutes.map((r) => (_jsx(Route, { path: r.path, element: r.element }, r.path))), topLevelGuarded.map(renderGuarded), layout ? (_jsx(Route, { element: layout, children: inLayout.map(renderGuarded) })) : (inLayout.map(renderGuarded)), notFound ? _jsx(Route, { path: "*", element: notFound }) : null] }));
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@genesislcap/foundation-react-utils/router`
|
|
3
|
+
*
|
|
4
|
+
* Reusable `react-router-dom` primitives for Genesis Foundation React apps, so
|
|
5
|
+
* the app-shell routing logic doesn't have to be reimplemented per app.
|
|
6
|
+
*
|
|
7
|
+
* Exposed as a subpath (`/router`) rather than from the package root so that
|
|
8
|
+
* consumers which don't route (and don't depend on `react-router-dom`) are
|
|
9
|
+
* unaffected.
|
|
10
|
+
*
|
|
11
|
+
* Key exports:
|
|
12
|
+
* - `ProtectedRoute` / `createProtectedRoute` — auth + permission gate that
|
|
13
|
+
* stashes the full origin location (incl. `search` + `hash`) for post-login
|
|
14
|
+
* restore, and redirects to a not-permitted path when authorized-but-blocked.
|
|
15
|
+
* - `buildPostLoginRedirect` — rebuild the return URL preserving query + hash.
|
|
16
|
+
* - `readInitialParam` / `createComponentRegistry` / `SingleComponentOutlet` —
|
|
17
|
+
* render a single registered component full-screen from a `?param=<name>`
|
|
18
|
+
* deep-link captured before the shell strips the query string.
|
|
19
|
+
* - `renderAppRoutes` — build the app's `<Routes>` from a declarative route
|
|
20
|
+
* table (guarding, layout nesting, redirects, not-found, single-component).
|
|
21
|
+
* - `mergePbcRoutes` — merge static routes with shell/PBC routes into one table.
|
|
22
|
+
*/
|
|
23
|
+
export { ProtectedRoute, createProtectedRoute } from './protected-route';
|
|
24
|
+
export { buildPostLoginRedirect } from './post-login-redirect';
|
|
25
|
+
export { readInitialParam, createComponentRegistry, SingleComponentOutlet, } from './single-component';
|
|
26
|
+
export { renderAppRoutes } from './app-routes';
|
|
27
|
+
export { mergePbcRoutes } from './pbc-routes';
|