@relax.js/core 1.0.2 → 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 (240) hide show
  1. package/README.md +194 -188
  2. package/dist/DependencyInjection.d.ts +42 -24
  3. package/dist/collections/Index.d.ts +2 -0
  4. package/dist/collections/index.js +1 -1
  5. package/dist/collections/index.js.map +4 -4
  6. package/dist/collections/index.mjs +1 -1
  7. package/dist/collections/index.mjs.map +4 -4
  8. package/dist/di/index.js +1 -1
  9. package/dist/di/index.js.map +3 -3
  10. package/dist/di/index.mjs +1 -1
  11. package/dist/di/index.mjs.map +3 -3
  12. package/dist/errors.d.ts +20 -0
  13. package/dist/forms/FormValidator.d.ts +1 -20
  14. package/dist/forms/ValidationRules.d.ts +2 -0
  15. package/dist/forms/index.js +1 -1
  16. package/dist/forms/index.js.map +4 -4
  17. package/dist/forms/index.mjs +1 -1
  18. package/dist/forms/index.mjs.map +4 -4
  19. package/dist/html/TableRenderer.d.ts +1 -0
  20. package/dist/html/index.js.map +2 -2
  21. package/dist/html/index.mjs.map +2 -2
  22. package/dist/html/template.d.ts +4 -0
  23. package/dist/http/http.d.ts +1 -0
  24. package/dist/http/index.js.map +2 -2
  25. package/dist/http/index.mjs.map +2 -2
  26. package/dist/index.d.ts +0 -2
  27. package/dist/index.js +3 -3
  28. package/dist/index.js.map +4 -4
  29. package/dist/index.mjs +3 -3
  30. package/dist/index.mjs.map +4 -4
  31. package/dist/routing/index.js +3 -3
  32. package/dist/routing/index.js.map +3 -3
  33. package/dist/routing/index.mjs +3 -3
  34. package/dist/routing/index.mjs.map +3 -3
  35. package/dist/routing/routeTargetRegistry.d.ts +1 -0
  36. package/dist/routing/types.d.ts +2 -1
  37. package/dist/templates/NodeTemplate.d.ts +2 -0
  38. package/dist/utils/index.js +1 -1
  39. package/dist/utils/index.js.map +2 -2
  40. package/dist/utils/index.mjs +1 -1
  41. package/dist/utils/index.mjs.map +2 -2
  42. package/docs/Architecture.md +333 -333
  43. package/docs/DependencyInjection.md +277 -237
  44. package/docs/Errors.md +87 -87
  45. package/docs/GettingStarted.md +231 -231
  46. package/docs/Pipes.md +5 -5
  47. package/docs/Translations.md +167 -312
  48. package/docs/WhyRelaxjs.md +336 -336
  49. package/docs/api/.nojekyll +1 -0
  50. package/docs/api/assets/hierarchy.js +1 -0
  51. package/docs/api/assets/highlight.css +120 -0
  52. package/docs/api/assets/icons.js +18 -0
  53. package/docs/api/assets/icons.svg +1 -0
  54. package/docs/api/assets/main.js +60 -0
  55. package/docs/api/assets/navigation.js +1 -0
  56. package/docs/api/assets/search.js +1 -0
  57. package/docs/api/assets/style.css +1633 -0
  58. package/docs/api/classes/http.WebSocketClient.html +26 -0
  59. package/docs/api/classes/i18n.LocaleChangeEvent.html +66 -0
  60. package/docs/api/classes/index.Blueprint.html +3 -0
  61. package/docs/api/classes/index.BoundNode.html +3 -0
  62. package/docs/api/classes/index.DigitsValidation.html +10 -0
  63. package/docs/api/classes/index.FormValidator.html +32 -0
  64. package/docs/api/classes/index.HttpError.html +13 -0
  65. package/docs/api/classes/index.LinkedList.html +26 -0
  66. package/docs/api/classes/index.NavigateRouteEvent.html +76 -0
  67. package/docs/api/classes/index.Node.html +15 -0
  68. package/docs/api/classes/index.PageSelectedEvent.html +61 -0
  69. package/docs/api/classes/index.Pager.html +4 -0
  70. package/docs/api/classes/index.RangeValidation.html +15 -0
  71. package/docs/api/classes/index.RelaxError.html +17 -0
  72. package/docs/api/classes/index.RequiredValidation.html +10 -0
  73. package/docs/api/classes/index.RouteError.html +11 -0
  74. package/docs/api/classes/index.RouteGuardError.html +12 -0
  75. package/docs/api/classes/index.RouteLink.html +779 -0
  76. package/docs/api/classes/index.RouteTarget.html +788 -0
  77. package/docs/api/classes/index.SSEClient.html +13 -0
  78. package/docs/api/classes/index.SSEDataEvent.html +63 -0
  79. package/docs/api/classes/index.ServiceCollection.html +28 -0
  80. package/docs/api/classes/index.ServiceContainer.html +24 -0
  81. package/docs/api/classes/index.SortChangeEvent.html +61 -0
  82. package/docs/api/classes/index.TableRenderer.html +5 -0
  83. package/docs/api/classes/index.TableSorter.html +4 -0
  84. package/docs/api/enums/index.GuardResult.html +9 -0
  85. package/docs/api/functions/elements.formError.html +6 -0
  86. package/docs/api/functions/elements.selectOne.html +6 -0
  87. package/docs/api/functions/i18n.getCurrentLocale.html +3 -0
  88. package/docs/api/functions/i18n.loadNamespace.html +7 -0
  89. package/docs/api/functions/i18n.loadNamespaces.html +6 -0
  90. package/docs/api/functions/i18n.onMissingTranslation.html +7 -0
  91. package/docs/api/functions/i18n.setLocale.html +7 -0
  92. package/docs/api/functions/i18n.setMessageFormatter.html +7 -0
  93. package/docs/api/functions/i18n.t.html +9 -0
  94. package/docs/api/functions/index.BooleanConverter.html +6 -0
  95. package/docs/api/functions/index.ContainerService.html +13 -0
  96. package/docs/api/functions/index.DateConverter.html +11 -0
  97. package/docs/api/functions/index.Inject.html +16 -0
  98. package/docs/api/functions/index.NumberConverter.html +5 -0
  99. package/docs/api/functions/index.RegisterValidator.html +7 -0
  100. package/docs/api/functions/index.applyPipes.html +17 -0
  101. package/docs/api/functions/index.asyncHandler.html +11 -0
  102. package/docs/api/functions/index.capitalizePipe.html +4 -0
  103. package/docs/api/functions/index.clearPendingNavigations.html +1 -0
  104. package/docs/api/functions/index.compileTemplate.html +26 -0
  105. package/docs/api/functions/index.configure.html +5 -0
  106. package/docs/api/functions/index.createBluePrint.html +1 -0
  107. package/docs/api/functions/index.createConverterFromDataType.html +4 -0
  108. package/docs/api/functions/index.createConverterFromInputType.html +5 -0
  109. package/docs/api/functions/index.createPipeRegistry.html +12 -0
  110. package/docs/api/functions/index.currencyPipe.html +9 -0
  111. package/docs/api/functions/index.datePipe.html +9 -0
  112. package/docs/api/functions/index.daysAgoPipe.html +8 -0
  113. package/docs/api/functions/index.defaultPipe.html +5 -0
  114. package/docs/api/functions/index.defineRoutes.html +8 -0
  115. package/docs/api/functions/index.del.html +8 -0
  116. package/docs/api/functions/index.findRouteByName.html +5 -0
  117. package/docs/api/functions/index.findRouteByUrl.html +4 -0
  118. package/docs/api/functions/index.firstPipe.html +4 -0
  119. package/docs/api/functions/index.generateSequentialId.html +21 -0
  120. package/docs/api/functions/index.get.html +9 -0
  121. package/docs/api/functions/index.getDataConverter.html +11 -0
  122. package/docs/api/functions/index.getParentComponent.html +18 -0
  123. package/docs/api/functions/index.getValidator.html +4 -0
  124. package/docs/api/functions/index.html.html +19 -0
  125. package/docs/api/functions/index.joinPipe.html +5 -0
  126. package/docs/api/functions/index.keysPipe.html +4 -0
  127. package/docs/api/functions/index.lastPipe.html +4 -0
  128. package/docs/api/functions/index.lowercasePipe.html +4 -0
  129. package/docs/api/functions/index.mapFormToClass.html +17 -0
  130. package/docs/api/functions/index.matchRoute.html +5 -0
  131. package/docs/api/functions/index.navigate.html +8 -0
  132. package/docs/api/functions/index.onError.html +8 -0
  133. package/docs/api/functions/index.piecesPipe.html +8 -0
  134. package/docs/api/functions/index.post.html +9 -0
  135. package/docs/api/functions/index.printRoutes.html +2 -0
  136. package/docs/api/functions/index.put.html +9 -0
  137. package/docs/api/functions/index.readData.html +17 -0
  138. package/docs/api/functions/index.registerRouteTarget.html +9 -0
  139. package/docs/api/functions/index.reportError.html +10 -0
  140. package/docs/api/functions/index.request.html +8 -0
  141. package/docs/api/functions/index.resolveValue.html +18 -0
  142. package/docs/api/functions/index.setFetch.html +6 -0
  143. package/docs/api/functions/index.setFormData.html +17 -0
  144. package/docs/api/functions/index.shortenPipe.html +5 -0
  145. package/docs/api/functions/index.startRouting.html +6 -0
  146. package/docs/api/functions/index.ternaryPipe.html +6 -0
  147. package/docs/api/functions/index.trimPipe.html +4 -0
  148. package/docs/api/functions/index.unregisterRouteTarget.html +3 -0
  149. package/docs/api/functions/index.uppercasePipe.html +4 -0
  150. package/docs/api/hierarchy.html +1 -0
  151. package/docs/api/index.html +323 -0
  152. package/docs/api/interfaces/http.SimpleDataEvent.html +3 -0
  153. package/docs/api/interfaces/http.WebSocketAbstraction.html +9 -0
  154. package/docs/api/interfaces/http.WebSocketCodec.html +4 -0
  155. package/docs/api/interfaces/http.WebSocketOptions.html +20 -0
  156. package/docs/api/interfaces/index.CompiledTemplate.html +10 -0
  157. package/docs/api/interfaces/index.DataLoader.html +19 -0
  158. package/docs/api/interfaces/index.EngineConfig.html +11 -0
  159. package/docs/api/interfaces/index.ErrorContext.html +4 -0
  160. package/docs/api/interfaces/index.FormReaderOptions.html +8 -0
  161. package/docs/api/interfaces/index.HttpOptions.html +16 -0
  162. package/docs/api/interfaces/index.HttpResponse.html +17 -0
  163. package/docs/api/interfaces/index.LoadRoute.html +7 -0
  164. package/docs/api/interfaces/index.NavigateOptions.html +7 -0
  165. package/docs/api/interfaces/index.PipeRegistry.html +12 -0
  166. package/docs/api/interfaces/index.RegistrationOptions.html +22 -0
  167. package/docs/api/interfaces/index.RenderTemplate.html +7 -0
  168. package/docs/api/interfaces/index.RequestOptions.html +11 -0
  169. package/docs/api/interfaces/index.Routable.html +10 -0
  170. package/docs/api/interfaces/index.Route.html +13 -0
  171. package/docs/api/interfaces/index.RouteGuard.html +2 -0
  172. package/docs/api/interfaces/index.RouteValue.html +6 -0
  173. package/docs/api/interfaces/index.SSEOptions.html +24 -0
  174. package/docs/api/interfaces/index.ValidationContext.html +8 -0
  175. package/docs/api/interfaces/index.ValidatorOptions.html +14 -0
  176. package/docs/api/media/Architecture.md +333 -0
  177. package/docs/api/media/DependencyInjection.md +277 -0
  178. package/docs/api/media/GettingStarted.md +231 -0
  179. package/docs/api/media/HttpClient.md +459 -0
  180. package/docs/api/media/Pipes.md +211 -0
  181. package/docs/api/media/Routing.md +332 -0
  182. package/docs/api/media/WhyRelaxjs.md +336 -0
  183. package/docs/api/media/forms.md +99 -0
  184. package/docs/api/media/html.md +175 -0
  185. package/docs/api/media/i18n.md +354 -0
  186. package/docs/api/media/utilities.md +143 -0
  187. package/docs/api/media/validation.md +351 -0
  188. package/docs/api/modules/collections_Index.html +1 -0
  189. package/docs/api/modules/di.html +1 -0
  190. package/docs/api/modules/elements.html +1 -0
  191. package/docs/api/modules/forms.html +1 -0
  192. package/docs/api/modules/html.html +1 -0
  193. package/docs/api/modules/http.html +1 -0
  194. package/docs/api/modules/i18n.html +1 -0
  195. package/docs/api/modules/index.html +1 -0
  196. package/docs/api/modules/routing.html +1 -0
  197. package/docs/api/modules/utils.html +1 -0
  198. package/docs/api/modules.html +1 -0
  199. package/docs/api/types/http.WebSocketFactory.html +2 -0
  200. package/docs/api/types/i18n.MessageFormatter.html +3 -0
  201. package/docs/api/types/i18n.MissingTranslationHandler.html +1 -0
  202. package/docs/api/types/index.Constructor.html +7 -0
  203. package/docs/api/types/index.ConverterFunc.html +2 -0
  204. package/docs/api/types/index.DataType.html +2 -0
  205. package/docs/api/types/index.InputType.html +2 -0
  206. package/docs/api/types/index.PipeFunction.html +6 -0
  207. package/docs/api/types/index.RouteData.html +1 -0
  208. package/docs/api/types/index.RouteMatchResult.html +9 -0
  209. package/docs/api/types/index.RouteParamType.html +1 -0
  210. package/docs/api/types/index.RouteSegmentType.html +2 -0
  211. package/docs/api/types/index.SSEEventFactory.html +5 -0
  212. package/docs/api/types/index.ServiceScope.html +10 -0
  213. package/docs/api/types/index.SortColumn.html +3 -0
  214. package/docs/api/variables/i18n.formatICU.html +3 -0
  215. package/docs/api/variables/index.container.html +6 -0
  216. package/docs/api/variables/index.defaultPipes.html +6 -0
  217. package/docs/api/variables/index.internalRoutes.html +1 -0
  218. package/docs/api/variables/index.serviceCollection.html +6 -0
  219. package/docs/api.json +93171 -0
  220. package/docs/elements/dom.md +102 -102
  221. package/docs/forms/creating-form-components.md +924 -924
  222. package/docs/forms/form-api.md +94 -94
  223. package/docs/forms/forms.md +99 -99
  224. package/docs/forms/patterns.md +311 -311
  225. package/docs/forms/reading-writing.md +365 -365
  226. package/docs/forms/validation.md +351 -351
  227. package/docs/html/TableRenderer.md +291 -291
  228. package/docs/html/html.md +175 -175
  229. package/docs/html/index.md +54 -54
  230. package/docs/html/template.md +422 -422
  231. package/docs/http/HttpClient.md +459 -459
  232. package/docs/http/ServerSentEvents.md +184 -184
  233. package/docs/http/index.md +109 -109
  234. package/docs/i18n/i18n.md +49 -4
  235. package/docs/i18n/intl-standard.md +178 -178
  236. package/docs/routing/RouteLink.md +98 -98
  237. package/docs/routing/Routing.md +332 -332
  238. package/docs/routing/layouts.md +207 -207
  239. package/docs/utilities.md +143 -143
  240. 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