@relax.js/core 1.0.3 → 1.0.4

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 (234) hide show
  1. package/README.md +194 -188
  2. package/dist/DependencyInjection.d.ts +42 -24
  3. package/dist/di/index.js +1 -1
  4. package/dist/di/index.js.map +3 -3
  5. package/dist/di/index.mjs +1 -1
  6. package/dist/di/index.mjs.map +3 -3
  7. package/dist/errors.d.ts +20 -0
  8. package/dist/forms/FormValidator.d.ts +1 -20
  9. package/dist/forms/ValidationRules.d.ts +2 -0
  10. package/dist/forms/index.js +1 -1
  11. package/dist/forms/index.js.map +4 -4
  12. package/dist/forms/index.mjs +1 -1
  13. package/dist/forms/index.mjs.map +4 -4
  14. package/dist/html/TableRenderer.d.ts +1 -0
  15. package/dist/html/index.js.map +2 -2
  16. package/dist/html/index.mjs.map +2 -2
  17. package/dist/html/template.d.ts +4 -0
  18. package/dist/http/http.d.ts +1 -0
  19. package/dist/http/index.js.map +2 -2
  20. package/dist/http/index.mjs.map +2 -2
  21. package/dist/index.js +3 -3
  22. package/dist/index.js.map +3 -3
  23. package/dist/index.mjs +3 -3
  24. package/dist/index.mjs.map +3 -3
  25. package/dist/routing/index.js +3 -3
  26. package/dist/routing/index.js.map +3 -3
  27. package/dist/routing/index.mjs +3 -3
  28. package/dist/routing/index.mjs.map +3 -3
  29. package/dist/routing/routeTargetRegistry.d.ts +1 -0
  30. package/dist/routing/types.d.ts +2 -1
  31. package/dist/templates/NodeTemplate.d.ts +2 -0
  32. package/dist/utils/index.js +1 -1
  33. package/dist/utils/index.js.map +2 -2
  34. package/dist/utils/index.mjs +1 -1
  35. package/dist/utils/index.mjs.map +2 -2
  36. package/docs/Architecture.md +333 -333
  37. package/docs/DependencyInjection.md +277 -237
  38. package/docs/Errors.md +87 -87
  39. package/docs/GettingStarted.md +231 -231
  40. package/docs/Pipes.md +5 -5
  41. package/docs/Translations.md +167 -312
  42. package/docs/WhyRelaxjs.md +336 -336
  43. package/docs/api/.nojekyll +1 -0
  44. package/docs/api/assets/hierarchy.js +1 -0
  45. package/docs/api/assets/highlight.css +120 -0
  46. package/docs/api/assets/icons.js +18 -0
  47. package/docs/api/assets/icons.svg +1 -0
  48. package/docs/api/assets/main.js +60 -0
  49. package/docs/api/assets/navigation.js +1 -0
  50. package/docs/api/assets/search.js +1 -0
  51. package/docs/api/assets/style.css +1633 -0
  52. package/docs/api/classes/http.WebSocketClient.html +26 -0
  53. package/docs/api/classes/i18n.LocaleChangeEvent.html +66 -0
  54. package/docs/api/classes/index.Blueprint.html +3 -0
  55. package/docs/api/classes/index.BoundNode.html +3 -0
  56. package/docs/api/classes/index.DigitsValidation.html +10 -0
  57. package/docs/api/classes/index.FormValidator.html +32 -0
  58. package/docs/api/classes/index.HttpError.html +13 -0
  59. package/docs/api/classes/index.LinkedList.html +26 -0
  60. package/docs/api/classes/index.NavigateRouteEvent.html +76 -0
  61. package/docs/api/classes/index.Node.html +15 -0
  62. package/docs/api/classes/index.PageSelectedEvent.html +61 -0
  63. package/docs/api/classes/index.Pager.html +4 -0
  64. package/docs/api/classes/index.RangeValidation.html +15 -0
  65. package/docs/api/classes/index.RelaxError.html +17 -0
  66. package/docs/api/classes/index.RequiredValidation.html +10 -0
  67. package/docs/api/classes/index.RouteError.html +11 -0
  68. package/docs/api/classes/index.RouteGuardError.html +12 -0
  69. package/docs/api/classes/index.RouteLink.html +779 -0
  70. package/docs/api/classes/index.RouteTarget.html +788 -0
  71. package/docs/api/classes/index.SSEClient.html +13 -0
  72. package/docs/api/classes/index.SSEDataEvent.html +63 -0
  73. package/docs/api/classes/index.ServiceCollection.html +28 -0
  74. package/docs/api/classes/index.ServiceContainer.html +24 -0
  75. package/docs/api/classes/index.SortChangeEvent.html +61 -0
  76. package/docs/api/classes/index.TableRenderer.html +5 -0
  77. package/docs/api/classes/index.TableSorter.html +4 -0
  78. package/docs/api/enums/index.GuardResult.html +9 -0
  79. package/docs/api/functions/elements.formError.html +6 -0
  80. package/docs/api/functions/elements.selectOne.html +6 -0
  81. package/docs/api/functions/i18n.getCurrentLocale.html +3 -0
  82. package/docs/api/functions/i18n.loadNamespace.html +7 -0
  83. package/docs/api/functions/i18n.loadNamespaces.html +6 -0
  84. package/docs/api/functions/i18n.onMissingTranslation.html +7 -0
  85. package/docs/api/functions/i18n.setLocale.html +7 -0
  86. package/docs/api/functions/i18n.setMessageFormatter.html +7 -0
  87. package/docs/api/functions/i18n.t.html +9 -0
  88. package/docs/api/functions/index.BooleanConverter.html +6 -0
  89. package/docs/api/functions/index.ContainerService.html +13 -0
  90. package/docs/api/functions/index.DateConverter.html +11 -0
  91. package/docs/api/functions/index.Inject.html +16 -0
  92. package/docs/api/functions/index.NumberConverter.html +5 -0
  93. package/docs/api/functions/index.RegisterValidator.html +7 -0
  94. package/docs/api/functions/index.applyPipes.html +17 -0
  95. package/docs/api/functions/index.asyncHandler.html +11 -0
  96. package/docs/api/functions/index.capitalizePipe.html +4 -0
  97. package/docs/api/functions/index.clearPendingNavigations.html +1 -0
  98. package/docs/api/functions/index.compileTemplate.html +26 -0
  99. package/docs/api/functions/index.configure.html +5 -0
  100. package/docs/api/functions/index.createBluePrint.html +1 -0
  101. package/docs/api/functions/index.createConverterFromDataType.html +4 -0
  102. package/docs/api/functions/index.createConverterFromInputType.html +5 -0
  103. package/docs/api/functions/index.createPipeRegistry.html +12 -0
  104. package/docs/api/functions/index.currencyPipe.html +9 -0
  105. package/docs/api/functions/index.datePipe.html +9 -0
  106. package/docs/api/functions/index.daysAgoPipe.html +8 -0
  107. package/docs/api/functions/index.defaultPipe.html +5 -0
  108. package/docs/api/functions/index.defineRoutes.html +8 -0
  109. package/docs/api/functions/index.del.html +8 -0
  110. package/docs/api/functions/index.findRouteByName.html +5 -0
  111. package/docs/api/functions/index.findRouteByUrl.html +4 -0
  112. package/docs/api/functions/index.firstPipe.html +4 -0
  113. package/docs/api/functions/index.generateSequentialId.html +21 -0
  114. package/docs/api/functions/index.get.html +9 -0
  115. package/docs/api/functions/index.getDataConverter.html +11 -0
  116. package/docs/api/functions/index.getParentComponent.html +18 -0
  117. package/docs/api/functions/index.getValidator.html +4 -0
  118. package/docs/api/functions/index.html.html +19 -0
  119. package/docs/api/functions/index.joinPipe.html +5 -0
  120. package/docs/api/functions/index.keysPipe.html +4 -0
  121. package/docs/api/functions/index.lastPipe.html +4 -0
  122. package/docs/api/functions/index.lowercasePipe.html +4 -0
  123. package/docs/api/functions/index.mapFormToClass.html +17 -0
  124. package/docs/api/functions/index.matchRoute.html +5 -0
  125. package/docs/api/functions/index.navigate.html +8 -0
  126. package/docs/api/functions/index.onError.html +8 -0
  127. package/docs/api/functions/index.piecesPipe.html +8 -0
  128. package/docs/api/functions/index.post.html +9 -0
  129. package/docs/api/functions/index.printRoutes.html +2 -0
  130. package/docs/api/functions/index.put.html +9 -0
  131. package/docs/api/functions/index.readData.html +17 -0
  132. package/docs/api/functions/index.registerRouteTarget.html +9 -0
  133. package/docs/api/functions/index.reportError.html +10 -0
  134. package/docs/api/functions/index.request.html +8 -0
  135. package/docs/api/functions/index.resolveValue.html +18 -0
  136. package/docs/api/functions/index.setFetch.html +6 -0
  137. package/docs/api/functions/index.setFormData.html +17 -0
  138. package/docs/api/functions/index.shortenPipe.html +5 -0
  139. package/docs/api/functions/index.startRouting.html +6 -0
  140. package/docs/api/functions/index.ternaryPipe.html +6 -0
  141. package/docs/api/functions/index.trimPipe.html +4 -0
  142. package/docs/api/functions/index.unregisterRouteTarget.html +3 -0
  143. package/docs/api/functions/index.uppercasePipe.html +4 -0
  144. package/docs/api/hierarchy.html +1 -0
  145. package/docs/api/index.html +323 -0
  146. package/docs/api/interfaces/http.SimpleDataEvent.html +3 -0
  147. package/docs/api/interfaces/http.WebSocketAbstraction.html +9 -0
  148. package/docs/api/interfaces/http.WebSocketCodec.html +4 -0
  149. package/docs/api/interfaces/http.WebSocketOptions.html +20 -0
  150. package/docs/api/interfaces/index.CompiledTemplate.html +10 -0
  151. package/docs/api/interfaces/index.DataLoader.html +19 -0
  152. package/docs/api/interfaces/index.EngineConfig.html +11 -0
  153. package/docs/api/interfaces/index.ErrorContext.html +4 -0
  154. package/docs/api/interfaces/index.FormReaderOptions.html +8 -0
  155. package/docs/api/interfaces/index.HttpOptions.html +16 -0
  156. package/docs/api/interfaces/index.HttpResponse.html +17 -0
  157. package/docs/api/interfaces/index.LoadRoute.html +7 -0
  158. package/docs/api/interfaces/index.NavigateOptions.html +7 -0
  159. package/docs/api/interfaces/index.PipeRegistry.html +12 -0
  160. package/docs/api/interfaces/index.RegistrationOptions.html +22 -0
  161. package/docs/api/interfaces/index.RenderTemplate.html +7 -0
  162. package/docs/api/interfaces/index.RequestOptions.html +11 -0
  163. package/docs/api/interfaces/index.Routable.html +10 -0
  164. package/docs/api/interfaces/index.Route.html +13 -0
  165. package/docs/api/interfaces/index.RouteGuard.html +2 -0
  166. package/docs/api/interfaces/index.RouteValue.html +6 -0
  167. package/docs/api/interfaces/index.SSEOptions.html +24 -0
  168. package/docs/api/interfaces/index.ValidationContext.html +8 -0
  169. package/docs/api/interfaces/index.ValidatorOptions.html +14 -0
  170. package/docs/api/media/Architecture.md +333 -0
  171. package/docs/api/media/DependencyInjection.md +277 -0
  172. package/docs/api/media/GettingStarted.md +231 -0
  173. package/docs/api/media/HttpClient.md +459 -0
  174. package/docs/api/media/Pipes.md +211 -0
  175. package/docs/api/media/Routing.md +332 -0
  176. package/docs/api/media/WhyRelaxjs.md +336 -0
  177. package/docs/api/media/forms.md +99 -0
  178. package/docs/api/media/html.md +175 -0
  179. package/docs/api/media/i18n.md +354 -0
  180. package/docs/api/media/utilities.md +143 -0
  181. package/docs/api/media/validation.md +351 -0
  182. package/docs/api/modules/collections_Index.html +1 -0
  183. package/docs/api/modules/di.html +1 -0
  184. package/docs/api/modules/elements.html +1 -0
  185. package/docs/api/modules/forms.html +1 -0
  186. package/docs/api/modules/html.html +1 -0
  187. package/docs/api/modules/http.html +1 -0
  188. package/docs/api/modules/i18n.html +1 -0
  189. package/docs/api/modules/index.html +1 -0
  190. package/docs/api/modules/routing.html +1 -0
  191. package/docs/api/modules/utils.html +1 -0
  192. package/docs/api/modules.html +1 -0
  193. package/docs/api/types/http.WebSocketFactory.html +2 -0
  194. package/docs/api/types/i18n.MessageFormatter.html +3 -0
  195. package/docs/api/types/i18n.MissingTranslationHandler.html +1 -0
  196. package/docs/api/types/index.Constructor.html +7 -0
  197. package/docs/api/types/index.ConverterFunc.html +2 -0
  198. package/docs/api/types/index.DataType.html +2 -0
  199. package/docs/api/types/index.InputType.html +2 -0
  200. package/docs/api/types/index.PipeFunction.html +6 -0
  201. package/docs/api/types/index.RouteData.html +1 -0
  202. package/docs/api/types/index.RouteMatchResult.html +9 -0
  203. package/docs/api/types/index.RouteParamType.html +1 -0
  204. package/docs/api/types/index.RouteSegmentType.html +2 -0
  205. package/docs/api/types/index.SSEEventFactory.html +5 -0
  206. package/docs/api/types/index.ServiceScope.html +10 -0
  207. package/docs/api/types/index.SortColumn.html +3 -0
  208. package/docs/api/variables/i18n.formatICU.html +3 -0
  209. package/docs/api/variables/index.container.html +6 -0
  210. package/docs/api/variables/index.defaultPipes.html +6 -0
  211. package/docs/api/variables/index.internalRoutes.html +1 -0
  212. package/docs/api/variables/index.serviceCollection.html +6 -0
  213. package/docs/api.json +93171 -0
  214. package/docs/elements/dom.md +102 -102
  215. package/docs/forms/creating-form-components.md +924 -924
  216. package/docs/forms/form-api.md +94 -94
  217. package/docs/forms/forms.md +99 -99
  218. package/docs/forms/patterns.md +311 -311
  219. package/docs/forms/reading-writing.md +365 -365
  220. package/docs/forms/validation.md +351 -351
  221. package/docs/html/TableRenderer.md +291 -291
  222. package/docs/html/html.md +175 -175
  223. package/docs/html/index.md +54 -54
  224. package/docs/html/template.md +422 -422
  225. package/docs/http/HttpClient.md +459 -459
  226. package/docs/http/ServerSentEvents.md +184 -184
  227. package/docs/http/index.md +109 -109
  228. package/docs/i18n/i18n.md +49 -4
  229. package/docs/i18n/intl-standard.md +178 -178
  230. package/docs/routing/RouteLink.md +98 -98
  231. package/docs/routing/Routing.md +332 -332
  232. package/docs/routing/layouts.md +207 -207
  233. package/docs/utilities.md +143 -143
  234. package/package.json +4 -3
@@ -1,207 +1,207 @@
1
- Layouts
2
- =======
3
-
4
- Layouts allow different HTML pages to serve as shells for different parts of your application. Common use cases:
5
-
6
- - Public pages (login, register) with minimal UI
7
- - Authenticated pages with navigation, sidebar, header
8
- - Admin pages with different structure
9
-
10
- ## How It Works
11
-
12
- Each layout is a separate static HTML file. When navigating to a route with a different layout than the current one, the router:
13
-
14
- 1. Stores the target route name and params in `sessionStorage`
15
- 2. Redirects the browser to the new HTML file
16
- 3. On the new page, `startRouting()` reads from `sessionStorage` and navigates to the intended route
17
- 4. The URL is updated to show the route path (not the `.html` file)
18
-
19
- ## File Structure
20
-
21
- ```
22
- /index.html <- default layout (no layout property needed)
23
- /public.html <- public layout
24
- /admin.html <- admin layout
25
- ```
26
-
27
- ## Route Configuration
28
-
29
- ```ts
30
- import { Route, defineRoutes, startRouting } from 'relaxjs/routing';
31
-
32
- const routes: Route[] = [
33
- // Uses public.html
34
- { name: 'login', path: '/login', componentTagName: 'login-page', layout: 'public' },
35
- { name: 'register', path: '/register', componentTagName: 'register-page', layout: 'public' },
36
-
37
- // Uses index.html (default - no layout property needed)
38
- { name: 'home', path: '/', componentTagName: 'home-page' },
39
- { name: 'settings', path: '/settings', componentTagName: 'settings-page' },
40
-
41
- // Uses admin.html
42
- { name: 'admin', path: '/admin', componentTagName: 'admin-dashboard', layout: 'admin' },
43
- ];
44
-
45
- defineRoutes(routes);
46
- startRouting();
47
- ```
48
-
49
- ## Layout HTML Files
50
-
51
- Each layout file must:
52
- - Include `<r-route-target>` where routed components render
53
- - Import and call `defineRoutes()` and `startRouting()`
54
- - Register all components that may be rendered in that layout
55
-
56
- ### index.html (default layout)
57
-
58
- ```html
59
- <!DOCTYPE html>
60
- <html>
61
- <head>
62
- <title>My App</title>
63
- <script type="module" src="/src/app.ts"></script>
64
- </head>
65
- <body>
66
- <app-header></app-header>
67
- <app-sidebar></app-sidebar>
68
- <main>
69
- <r-route-target></r-route-target>
70
- </main>
71
- </body>
72
- </html>
73
- ```
74
-
75
- ### public.html
76
-
77
- ```html
78
- <!DOCTYPE html>
79
- <html>
80
- <head>
81
- <title>My App - Login</title>
82
- <script type="module" src="/src/app.ts"></script>
83
- </head>
84
- <body>
85
- <div class="auth-container">
86
- <r-route-target></r-route-target>
87
- </div>
88
- </body>
89
- </html>
90
- ```
91
-
92
- ## Layout Detection
93
-
94
- The router determines the current layout from the URL:
95
-
96
- | URL | Detected Layout |
97
- |-----|-----------------|
98
- | `/index.html` | `default` |
99
- | `/public.html` | `public` |
100
- | `/admin.html` | `admin` |
101
- | `/` or `/settings` | `default` (inferred) |
102
-
103
- ## Navigation Flow
104
-
105
- When a user on `/settings` (default layout) navigates to `login` (public layout):
106
-
107
- 1. `navigate('login')` is called
108
- 2. Router detects layout mismatch: `default` !== `public`
109
- 3. Stores `{ routeName: 'login', params: {} }` in `sessionStorage`
110
- 4. Redirects browser to `/public.html#layout`
111
- 5. `public.html` loads and calls `startRouting()`
112
- 6. `startRouting()` reads from `sessionStorage`, calls `navigate('login')`
113
- 7. URL updates to `/login`, `login-page` component renders
114
-
115
- ## Shared Routes Configuration
116
-
117
- Since all layout files need the same routes, keep route configuration in a shared module:
118
-
119
- ```ts
120
- // routes.ts
121
- import { Route } from 'relaxjs/routing';
122
-
123
- export const routes: Route[] = [
124
- { name: 'login', path: '/login', componentTagName: 'login-page', layout: 'public' },
125
- { name: 'home', path: '/', componentTagName: 'home-page' },
126
- // ...
127
- ];
128
- ```
129
-
130
- ```ts
131
- // app.ts (imported by all layout HTML files)
132
- import { defineRoutes, startRouting } from 'relaxjs/routing';
133
- import { routes } from './routes';
134
-
135
- defineRoutes(routes);
136
- startRouting();
137
- ```
138
-
139
- ## Error Handling
140
-
141
- If a layout redirect fails (e.g., the HTML file doesn't exist), the router throws an error:
142
-
143
- ```
144
- A redirect failed, does the requested layout exist? "admin"?
145
- ```
146
-
147
- The `#layout` hash in the redirect URL is used to detect this: if the hash is still present after redirect, something went wrong.
148
-
149
- ## Security Considerations
150
-
151
- Layout files are static HTML served to the browser. This has security implications:
152
-
153
- ### Route Exposure
154
-
155
- A file like `admin.html` contains (or imports) route configurations that reveal admin URLs. Anyone requesting the file can see what endpoints exist, even without authentication.
156
-
157
- ### Client-Side Guards Are Not Security
158
-
159
- Route guards in Relaxjs prevent components from rendering, but they don't protect data. An attacker can:
160
- - Read the JavaScript bundle to find all routes
161
- - Call backend APIs directly, bypassing the UI entirely
162
-
163
- **The real security boundary is always your backend API.** Every API endpoint must validate authentication and authorization.
164
-
165
- ### Server-Side Protection
166
-
167
- For defense in depth, protect sensitive layout files at the HTTP server level:
168
-
169
- **Nginx:**
170
- ```nginx
171
- location /admin.html {
172
- auth_request /auth/verify;
173
- error_page 401 = @unauthorized;
174
- }
175
-
176
- location @unauthorized {
177
- return 302 /login;
178
- }
179
- ```
180
-
181
- **Express:**
182
- ```ts
183
- app.get('/admin.html', verifyJwt, (req, res) => {
184
- res.sendFile('admin.html');
185
- });
186
- ```
187
-
188
- **Caddy:**
189
- ```
190
- admin.html {
191
- forward_auth /auth/verify
192
- }
193
- ```
194
-
195
- ### Alternatives
196
-
197
- If hiding routes is important:
198
-
199
- 1. **Single layout with dynamic navigation**: Load admin navigation only after auth verification
200
- 2. **Separate builds**: Build different bundles for public/authenticated/admin with different route configurations
201
- 3. **Server-rendered shells**: Generate layout HTML server-side based on user role
202
-
203
- ### Recommendation
204
-
205
- 1. Always secure your backend APIs with proper authentication/authorization
206
- 2. Protect sensitive layout files at the server level in production
207
- 3. Don't rely on client-side guards for security. They're for UX, not protection
1
+ Layouts
2
+ =======
3
+
4
+ Layouts allow different HTML pages to serve as shells for different parts of your application. Common use cases:
5
+
6
+ - Public pages (login, register) with minimal UI
7
+ - Authenticated pages with navigation, sidebar, header
8
+ - Admin pages with different structure
9
+
10
+ ## How It Works
11
+
12
+ Each layout is a separate static HTML file. When navigating to a route with a different layout than the current one, the router:
13
+
14
+ 1. Stores the target route name and params in `sessionStorage`
15
+ 2. Redirects the browser to the new HTML file
16
+ 3. On the new page, `startRouting()` reads from `sessionStorage` and navigates to the intended route
17
+ 4. The URL is updated to show the route path (not the `.html` file)
18
+
19
+ ## File Structure
20
+
21
+ ```
22
+ /index.html <- default layout (no layout property needed)
23
+ /public.html <- public layout
24
+ /admin.html <- admin layout
25
+ ```
26
+
27
+ ## Route Configuration
28
+
29
+ ```ts
30
+ import { Route, defineRoutes, startRouting } from '@relax.js/core/routing';
31
+
32
+ const routes: Route[] = [
33
+ // Uses public.html
34
+ { name: 'login', path: '/login', componentTagName: 'login-page', layout: 'public' },
35
+ { name: 'register', path: '/register', componentTagName: 'register-page', layout: 'public' },
36
+
37
+ // Uses index.html (default - no layout property needed)
38
+ { name: 'home', path: '/', componentTagName: 'home-page' },
39
+ { name: 'settings', path: '/settings', componentTagName: 'settings-page' },
40
+
41
+ // Uses admin.html
42
+ { name: 'admin', path: '/admin', componentTagName: 'admin-dashboard', layout: 'admin' },
43
+ ];
44
+
45
+ defineRoutes(routes);
46
+ startRouting();
47
+ ```
48
+
49
+ ## Layout HTML Files
50
+
51
+ Each layout file must:
52
+ - Include `<r-route-target>` where routed components render
53
+ - Import and call `defineRoutes()` and `startRouting()`
54
+ - Register all components that may be rendered in that layout
55
+
56
+ ### index.html (default layout)
57
+
58
+ ```html
59
+ <!DOCTYPE html>
60
+ <html>
61
+ <head>
62
+ <title>My App</title>
63
+ <script type="module" src="/src/app.ts"></script>
64
+ </head>
65
+ <body>
66
+ <app-header></app-header>
67
+ <app-sidebar></app-sidebar>
68
+ <main>
69
+ <r-route-target></r-route-target>
70
+ </main>
71
+ </body>
72
+ </html>
73
+ ```
74
+
75
+ ### public.html
76
+
77
+ ```html
78
+ <!DOCTYPE html>
79
+ <html>
80
+ <head>
81
+ <title>My App - Login</title>
82
+ <script type="module" src="/src/app.ts"></script>
83
+ </head>
84
+ <body>
85
+ <div class="auth-container">
86
+ <r-route-target></r-route-target>
87
+ </div>
88
+ </body>
89
+ </html>
90
+ ```
91
+
92
+ ## Layout Detection
93
+
94
+ The router determines the current layout from the URL:
95
+
96
+ | URL | Detected Layout |
97
+ |-----|-----------------|
98
+ | `/index.html` | `default` |
99
+ | `/public.html` | `public` |
100
+ | `/admin.html` | `admin` |
101
+ | `/` or `/settings` | `default` (inferred) |
102
+
103
+ ## Navigation Flow
104
+
105
+ When a user on `/settings` (default layout) navigates to `login` (public layout):
106
+
107
+ 1. `navigate('login')` is called
108
+ 2. Router detects layout mismatch: `default` !== `public`
109
+ 3. Stores `{ routeName: 'login', params: {} }` in `sessionStorage`
110
+ 4. Redirects browser to `/public.html#layout`
111
+ 5. `public.html` loads and calls `startRouting()`
112
+ 6. `startRouting()` reads from `sessionStorage`, calls `navigate('login')`
113
+ 7. URL updates to `/login`, `login-page` component renders
114
+
115
+ ## Shared Routes Configuration
116
+
117
+ Since all layout files need the same routes, keep route configuration in a shared module:
118
+
119
+ ```ts
120
+ // routes.ts
121
+ import { Route } from '@relax.js/core/routing';
122
+
123
+ export const routes: Route[] = [
124
+ { name: 'login', path: '/login', componentTagName: 'login-page', layout: 'public' },
125
+ { name: 'home', path: '/', componentTagName: 'home-page' },
126
+ // ...
127
+ ];
128
+ ```
129
+
130
+ ```ts
131
+ // app.ts (imported by all layout HTML files)
132
+ import { defineRoutes, startRouting } from '@relax.js/core/routing';
133
+ import { routes } from './routes';
134
+
135
+ defineRoutes(routes);
136
+ startRouting();
137
+ ```
138
+
139
+ ## Error Handling
140
+
141
+ If a layout redirect fails (e.g., the HTML file doesn't exist), the router throws an error:
142
+
143
+ ```
144
+ A redirect failed, does the requested layout exist? "admin"?
145
+ ```
146
+
147
+ The `#layout` hash in the redirect URL is used to detect this: if the hash is still present after redirect, something went wrong.
148
+
149
+ ## Security Considerations
150
+
151
+ Layout files are static HTML served to the browser. This has security implications:
152
+
153
+ ### Route Exposure
154
+
155
+ A file like `admin.html` contains (or imports) route configurations that reveal admin URLs. Anyone requesting the file can see what endpoints exist, even without authentication.
156
+
157
+ ### Client-Side Guards Are Not Security
158
+
159
+ Route guards in Relaxjs prevent components from rendering, but they don't protect data. An attacker can:
160
+ - Read the JavaScript bundle to find all routes
161
+ - Call backend APIs directly, bypassing the UI entirely
162
+
163
+ **The real security boundary is always your backend API.** Every API endpoint must validate authentication and authorization.
164
+
165
+ ### Server-Side Protection
166
+
167
+ For defense in depth, protect sensitive layout files at the HTTP server level:
168
+
169
+ **Nginx:**
170
+ ```nginx
171
+ location /admin.html {
172
+ auth_request /auth/verify;
173
+ error_page 401 = @unauthorized;
174
+ }
175
+
176
+ location @unauthorized {
177
+ return 302 /login;
178
+ }
179
+ ```
180
+
181
+ **Express:**
182
+ ```ts
183
+ app.get('/admin.html', verifyJwt, (req, res) => {
184
+ res.sendFile('admin.html');
185
+ });
186
+ ```
187
+
188
+ **Caddy:**
189
+ ```
190
+ admin.html {
191
+ forward_auth /auth/verify
192
+ }
193
+ ```
194
+
195
+ ### Alternatives
196
+
197
+ If hiding routes is important:
198
+
199
+ 1. **Single layout with dynamic navigation**: Load admin navigation only after auth verification
200
+ 2. **Separate builds**: Build different bundles for public/authenticated/admin with different route configurations
201
+ 3. **Server-rendered shells**: Generate layout HTML server-side based on user role
202
+
203
+ ### Recommendation
204
+
205
+ 1. Always secure your backend APIs with proper authentication/authorization
206
+ 2. Protect sensitive layout files at the server level in production
207
+ 3. Don't rely on client-side guards for security. They're for UX, not protection