create-velox-app 0.6.31 → 0.6.52

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 (74) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/GUIDE.md +230 -0
  3. package/dist/cli.js +1 -0
  4. package/dist/index.js +14 -4
  5. package/dist/templates/auth.js +10 -0
  6. package/dist/templates/index.js +30 -1
  7. package/dist/templates/placeholders.js +0 -3
  8. package/dist/templates/rsc-auth.d.ts +12 -0
  9. package/dist/templates/rsc-auth.js +208 -0
  10. package/dist/templates/rsc.js +40 -1
  11. package/dist/templates/shared/css-generator.d.ts +26 -0
  12. package/dist/templates/shared/css-generator.js +553 -0
  13. package/dist/templates/shared/index.d.ts +3 -0
  14. package/dist/templates/shared/index.js +3 -0
  15. package/dist/templates/shared/rsc-styles.d.ts +54 -0
  16. package/dist/templates/shared/rsc-styles.js +68 -0
  17. package/dist/templates/shared/theme.d.ts +133 -0
  18. package/dist/templates/shared/theme.js +141 -0
  19. package/dist/templates/spa.js +10 -0
  20. package/dist/templates/trpc.js +10 -0
  21. package/dist/templates/types.d.ts +2 -1
  22. package/dist/templates/types.js +6 -0
  23. package/package.json +6 -3
  24. package/src/templates/source/api/config/database.ts +13 -32
  25. package/src/templates/source/api/docker-compose.yml +21 -0
  26. package/src/templates/source/root/CLAUDE.auth.md +6 -0
  27. package/src/templates/source/root/CLAUDE.default.md +6 -0
  28. package/src/templates/source/rsc/CLAUDE.md +56 -2
  29. package/src/templates/source/rsc/app/actions/posts.ts +1 -1
  30. package/src/templates/source/rsc/app/actions/users.ts +111 -20
  31. package/src/templates/source/rsc/app/layouts/dashboard.tsx +21 -16
  32. package/src/templates/source/rsc/app/layouts/marketing.tsx +34 -0
  33. package/src/templates/source/rsc/app/layouts/minimal-content.tsx +21 -0
  34. package/src/templates/source/rsc/app/layouts/minimal.tsx +86 -5
  35. package/src/templates/source/rsc/app/layouts/root.tsx +148 -44
  36. package/src/templates/source/rsc/docker-compose.yml +21 -0
  37. package/src/templates/source/rsc/package.json +3 -3
  38. package/src/templates/source/rsc/src/api/database.ts +13 -32
  39. package/src/templates/source/rsc/src/api/handler.ts +1 -1
  40. package/src/templates/source/rsc/src/entry.client.tsx +65 -18
  41. package/src/templates/source/rsc-auth/CLAUDE.md +230 -0
  42. package/src/templates/source/rsc-auth/app/actions/auth.ts +112 -0
  43. package/src/templates/source/rsc-auth/app/actions/users.ts +289 -0
  44. package/src/templates/source/rsc-auth/app/layouts/dashboard.tsx +132 -0
  45. package/src/templates/source/rsc-auth/app/layouts/marketing.tsx +59 -0
  46. package/src/templates/source/rsc-auth/app/layouts/minimal-content.tsx +21 -0
  47. package/src/templates/source/rsc-auth/app/layouts/minimal.tsx +111 -0
  48. package/src/templates/source/rsc-auth/app/layouts/root.tsx +355 -0
  49. package/src/templates/source/rsc-auth/app/pages/_not-found.tsx +15 -0
  50. package/src/templates/source/rsc-auth/app/pages/auth/login.tsx +198 -0
  51. package/src/templates/source/rsc-auth/app/pages/auth/register.tsx +225 -0
  52. package/src/templates/source/rsc-auth/app/pages/dashboard/index.tsx +267 -0
  53. package/src/templates/source/rsc-auth/app/pages/index.tsx +83 -0
  54. package/src/templates/source/rsc-auth/app/pages/users.tsx +47 -0
  55. package/src/templates/source/rsc-auth/app.config.ts +12 -0
  56. package/src/templates/source/rsc-auth/docker-compose.yml +21 -0
  57. package/src/templates/source/rsc-auth/env.example +11 -0
  58. package/src/templates/source/rsc-auth/gitignore +34 -0
  59. package/src/templates/source/rsc-auth/package.json +44 -0
  60. package/src/templates/source/rsc-auth/prisma/schema.prisma +23 -0
  61. package/src/templates/source/rsc-auth/prisma.config.ts +22 -0
  62. package/src/templates/source/rsc-auth/public/favicon.svg +4 -0
  63. package/src/templates/source/rsc-auth/src/api/database.ts +129 -0
  64. package/src/templates/source/rsc-auth/src/api/handler.ts +85 -0
  65. package/src/templates/source/rsc-auth/src/api/procedures/auth.ts +262 -0
  66. package/src/templates/source/rsc-auth/src/api/procedures/health.ts +48 -0
  67. package/src/templates/source/rsc-auth/src/api/procedures/users.ts +87 -0
  68. package/src/templates/source/rsc-auth/src/api/schemas/auth.ts +79 -0
  69. package/src/templates/source/rsc-auth/src/api/schemas/user.ts +38 -0
  70. package/src/templates/source/rsc-auth/src/api/utils/auth.ts +157 -0
  71. package/src/templates/source/rsc-auth/src/entry.client.tsx +63 -0
  72. package/src/templates/source/rsc-auth/src/entry.server.tsx +262 -0
  73. package/src/templates/source/rsc-auth/tsconfig.json +24 -0
  74. package/src/templates/source/shared/scripts/check-client-imports.sh +75 -0
@@ -0,0 +1,553 @@
1
+ /**
2
+ * CSS Generator Functions
3
+ *
4
+ * Generates CSS strings from the theme design system.
5
+ * These functions provide consistent dark mode styling across all RSC templates.
6
+ */
7
+ import { colors, layout, spacing, transitions, typography } from './theme.js';
8
+ /**
9
+ * Global CSS reset and base styles for dark mode
10
+ */
11
+ export function generateGlobalReset() {
12
+ return `
13
+ *,
14
+ *::before,
15
+ *::after {
16
+ box-sizing: border-box;
17
+ margin: 0;
18
+ padding: 0;
19
+ font: inherit;
20
+ }
21
+
22
+ html {
23
+ font-size: 16px;
24
+ -webkit-font-smoothing: antialiased;
25
+ -moz-osx-font-smoothing: grayscale;
26
+ }
27
+
28
+ body {
29
+ background: ${colors.background};
30
+ color: ${colors.text};
31
+ font-family: ${typography.fontFamily.sans};
32
+ line-height: ${typography.lineHeight.normal};
33
+ min-height: 100svh;
34
+ }
35
+
36
+ h1, h2, h3, h4, h5, h6 {
37
+ text-wrap: balance;
38
+ }
39
+
40
+ p, li, figcaption {
41
+ text-wrap: pretty;
42
+ }
43
+
44
+ img, picture, svg, video, canvas {
45
+ max-width: 100%;
46
+ }
47
+
48
+ a {
49
+ color: ${colors.accent};
50
+ text-decoration: none;
51
+ transition: opacity ${transitions.normal};
52
+ }
53
+
54
+ a:hover {
55
+ opacity: 0.8;
56
+ }
57
+
58
+ code {
59
+ font-family: ${typography.fontFamily.mono};
60
+ background: ${colors.codeBg};
61
+ padding: 0.2em 0.4em;
62
+ border-radius: ${layout.borderRadius.sm};
63
+ font-size: ${typography.fontSize.md};
64
+ }
65
+
66
+ ::selection {
67
+ background: ${colors.selection};
68
+ color: ${colors.selectionText};
69
+ }
70
+
71
+ ::-webkit-scrollbar {
72
+ width: 8px;
73
+ height: 8px;
74
+ }
75
+
76
+ ::-webkit-scrollbar-track {
77
+ background: ${colors.scrollbarTrack};
78
+ }
79
+
80
+ ::-webkit-scrollbar-thumb {
81
+ background: ${colors.scrollbarThumb};
82
+ border-radius: ${layout.borderRadius.sm};
83
+ }
84
+
85
+ ::-webkit-scrollbar-thumb:hover {
86
+ background: ${colors.scrollbarThumbHover};
87
+ }
88
+ `.trim();
89
+ }
90
+ /**
91
+ * Root layout styles - Navigation, footer, and main content area
92
+ */
93
+ export function generateRscRootStyles() {
94
+ return `
95
+ ${generateGlobalReset()}
96
+
97
+ .layout {
98
+ min-height: 100vh;
99
+ display: flex;
100
+ flex-direction: column;
101
+ }
102
+
103
+ .nav {
104
+ background: ${colors.surface};
105
+ padding: ${spacing[4]} ${spacing[8]};
106
+ border-bottom: 1px solid ${colors.border};
107
+ }
108
+
109
+ .nav-list {
110
+ display: flex;
111
+ gap: ${spacing[8]};
112
+ list-style: none;
113
+ max-width: ${layout.maxWidth};
114
+ margin: 0 auto;
115
+ align-items: center;
116
+ }
117
+
118
+ .nav-link {
119
+ color: ${colors.text};
120
+ text-decoration: none;
121
+ font-weight: ${typography.fontWeight.medium};
122
+ transition: color ${transitions.normal};
123
+ padding: ${spacing[2]} ${spacing[3]};
124
+ border-radius: ${layout.borderRadius.sm};
125
+ }
126
+
127
+ .nav-link:hover {
128
+ color: ${colors.accent};
129
+ background: ${colors.surfaceHover};
130
+ }
131
+
132
+ .main {
133
+ flex: 1;
134
+ padding: ${spacing[8]};
135
+ max-width: ${layout.maxWidth};
136
+ margin: 0 auto;
137
+ width: 100%;
138
+ }
139
+
140
+ .footer {
141
+ background: ${colors.surface};
142
+ color: ${colors.textMuted};
143
+ text-align: center;
144
+ padding: ${spacing[4]};
145
+ font-size: ${typography.fontSize.base};
146
+ border-top: 1px solid ${colors.border};
147
+ }
148
+
149
+ /* Home page hero section */
150
+ .home-page .hero {
151
+ text-align: center;
152
+ padding: ${spacing[12]} 0;
153
+ }
154
+
155
+ .home-page h1 {
156
+ font-size: ${typography.fontSize['4xl']};
157
+ margin-bottom: ${spacing[3]};
158
+ font-weight: ${typography.fontWeight.bold};
159
+ }
160
+
161
+ .home-page .tagline {
162
+ color: ${colors.textMuted};
163
+ font-size: ${typography.fontSize.xl};
164
+ }
165
+
166
+ /* Stats cards */
167
+ .stats {
168
+ display: flex;
169
+ gap: ${spacing[4]};
170
+ justify-content: center;
171
+ margin: ${spacing[8]} 0;
172
+ flex-wrap: wrap;
173
+ }
174
+
175
+ .stat-card {
176
+ background: ${colors.surface};
177
+ padding: ${spacing[6]} ${spacing[8]};
178
+ border-radius: ${layout.borderRadius.lg};
179
+ border: 1px solid ${colors.border};
180
+ text-align: center;
181
+ min-width: 150px;
182
+ transition: border-color ${transitions.normal};
183
+ }
184
+
185
+ .stat-card:hover {
186
+ border-color: ${colors.accent};
187
+ }
188
+
189
+ .stat-value {
190
+ display: block;
191
+ font-size: ${typography.fontSize['3xl']};
192
+ font-weight: ${typography.fontWeight.bold};
193
+ color: ${colors.accent};
194
+ }
195
+
196
+ .stat-label {
197
+ color: ${colors.textMuted};
198
+ font-size: ${typography.fontSize.base};
199
+ margin-top: ${spacing[2]};
200
+ }
201
+
202
+ /* Features section */
203
+ .features {
204
+ background: ${colors.surface};
205
+ padding: ${spacing[8]};
206
+ border-radius: ${layout.borderRadius.lg};
207
+ border: 1px solid ${colors.border};
208
+ margin-top: ${spacing[8]};
209
+ }
210
+
211
+ .features h2 {
212
+ margin-bottom: ${spacing[6]};
213
+ font-size: ${typography.fontSize['2xl']};
214
+ font-weight: ${typography.fontWeight.semibold};
215
+ }
216
+
217
+ .features ul {
218
+ list-style: none;
219
+ }
220
+
221
+ .features li {
222
+ padding: ${spacing[3]} 0;
223
+ border-bottom: 1px solid ${colors.border};
224
+ color: ${colors.text};
225
+ }
226
+
227
+ .features li:last-child {
228
+ border-bottom: none;
229
+ }
230
+
231
+ .cta {
232
+ text-align: center;
233
+ margin-top: ${spacing[8]};
234
+ color: ${colors.textMuted};
235
+ }
236
+
237
+ /* Users page */
238
+ .users-page h1 {
239
+ margin-bottom: ${spacing[6]};
240
+ font-size: ${typography.fontSize['3xl']};
241
+ font-weight: ${typography.fontWeight.bold};
242
+ }
243
+
244
+ .empty-state {
245
+ color: ${colors.textMuted};
246
+ padding: ${spacing[8]};
247
+ text-align: center;
248
+ background: ${colors.surface};
249
+ border-radius: ${layout.borderRadius.lg};
250
+ border: 1px solid ${colors.border};
251
+ }
252
+
253
+ .user-list {
254
+ list-style: none;
255
+ display: grid;
256
+ gap: ${spacing[4]};
257
+ }
258
+
259
+ .user-card {
260
+ background: ${colors.surface};
261
+ padding: ${spacing[4]};
262
+ border-radius: ${layout.borderRadius.lg};
263
+ border: 1px solid ${colors.border};
264
+ display: flex;
265
+ justify-content: space-between;
266
+ align-items: center;
267
+ transition: border-color ${transitions.normal};
268
+ }
269
+
270
+ .user-card:hover {
271
+ border-color: ${colors.accent};
272
+ }
273
+
274
+ .user-name {
275
+ font-weight: ${typography.fontWeight.semibold};
276
+ color: ${colors.text};
277
+ }
278
+
279
+ .user-email {
280
+ color: ${colors.textMuted};
281
+ font-size: ${typography.fontSize.base};
282
+ }
283
+
284
+ /* About page */
285
+ .about-page h1 {
286
+ font-size: ${typography.fontSize['3xl']};
287
+ margin-bottom: ${spacing[6]};
288
+ font-weight: ${typography.fontWeight.bold};
289
+ }
290
+
291
+ .about-page h2 {
292
+ font-size: ${typography.fontSize['2xl']};
293
+ margin-top: ${spacing[8]};
294
+ margin-bottom: ${spacing[4]};
295
+ font-weight: ${typography.fontWeight.semibold};
296
+ }
297
+
298
+ .about-page p {
299
+ color: ${colors.textMuted};
300
+ margin-bottom: ${spacing[4]};
301
+ line-height: ${typography.lineHeight.relaxed};
302
+ }
303
+ `.trim();
304
+ }
305
+ /**
306
+ * Dashboard layout styles - Sidebar navigation
307
+ */
308
+ export function generateRscDashboardStyles() {
309
+ return `
310
+ .dashboard-layout {
311
+ display: flex;
312
+ gap: ${spacing[8]};
313
+ min-height: 60vh;
314
+ }
315
+
316
+ .dashboard-sidebar {
317
+ width: ${layout.sidebarWidth};
318
+ flex-shrink: 0;
319
+ background: ${colors.surface};
320
+ border-radius: ${layout.borderRadius.lg};
321
+ padding: ${spacing[6]};
322
+ border: 1px solid ${colors.border};
323
+ height: fit-content;
324
+ }
325
+
326
+ .dashboard-sidebar h3 {
327
+ font-size: ${typography.fontSize.sm};
328
+ text-transform: uppercase;
329
+ color: ${colors.textMuted};
330
+ margin-bottom: ${spacing[3]};
331
+ padding: 0 ${spacing[3]};
332
+ font-weight: ${typography.fontWeight.semibold};
333
+ letter-spacing: 0.05em;
334
+ }
335
+
336
+ .sidebar-nav {
337
+ list-style: none;
338
+ }
339
+
340
+ .sidebar-nav a {
341
+ display: block;
342
+ padding: ${spacing[3]};
343
+ color: ${colors.text};
344
+ text-decoration: none;
345
+ border-radius: ${layout.borderRadius.sm};
346
+ transition: background ${transitions.normal};
347
+ }
348
+
349
+ .sidebar-nav a:hover {
350
+ background: ${colors.surfaceHover};
351
+ color: ${colors.accent};
352
+ }
353
+
354
+ .sidebar-nav a.active {
355
+ background: ${colors.accent};
356
+ color: ${colors.textInverse};
357
+ }
358
+
359
+ .dashboard-content {
360
+ flex: 1;
361
+ background: ${colors.surface};
362
+ border-radius: ${layout.borderRadius.lg};
363
+ padding: ${spacing[6]};
364
+ border: 1px solid ${colors.border};
365
+ }
366
+
367
+ .dashboard-badge {
368
+ display: inline-block;
369
+ background: ${colors.accent};
370
+ color: ${colors.textInverse};
371
+ font-size: ${typography.fontSize.xs};
372
+ text-transform: uppercase;
373
+ padding: ${spacing[2]} ${spacing[3]};
374
+ border-radius: ${layout.borderRadius.sm};
375
+ margin-bottom: ${spacing[4]};
376
+ font-weight: ${typography.fontWeight.semibold};
377
+ letter-spacing: 0.05em;
378
+ }
379
+ `.trim();
380
+ }
381
+ /**
382
+ * Minimal layout styles - For auth pages, centered content
383
+ */
384
+ export function generateRscMinimalStyles() {
385
+ return `
386
+ ${generateGlobalReset()}
387
+
388
+ .minimal-body {
389
+ min-height: 100vh;
390
+ display: flex;
391
+ align-items: center;
392
+ justify-content: center;
393
+ padding: ${spacing[8]};
394
+ }
395
+
396
+ .minimal-content {
397
+ width: 100%;
398
+ max-width: 450px;
399
+ }
400
+
401
+ /* Auth card container */
402
+ .auth-card {
403
+ background: ${colors.surface};
404
+ padding: ${spacing[8]};
405
+ border-radius: ${layout.borderRadius.lg};
406
+ border: 1px solid ${colors.border};
407
+ }
408
+
409
+ .auth-card h1 {
410
+ font-size: ${typography.fontSize['2xl']};
411
+ font-weight: ${typography.fontWeight.bold};
412
+ margin-bottom: ${spacing[6]};
413
+ text-align: center;
414
+ }
415
+
416
+ /* Form styles */
417
+ .auth-form {
418
+ margin-top: ${spacing[6]};
419
+ }
420
+
421
+ .form-group {
422
+ margin-bottom: ${spacing[5]};
423
+ }
424
+
425
+ .form-label {
426
+ display: block;
427
+ margin-bottom: ${spacing[2]};
428
+ color: ${colors.text};
429
+ font-weight: ${typography.fontWeight.medium};
430
+ font-size: ${typography.fontSize.base};
431
+ }
432
+
433
+ .form-input {
434
+ width: 100%;
435
+ padding: ${spacing[3]} ${spacing[4]};
436
+ border-radius: ${layout.borderRadius.sm};
437
+ border: 1px solid ${colors.border};
438
+ background: ${colors.background};
439
+ color: ${colors.text};
440
+ font-size: ${typography.fontSize.base};
441
+ transition: border-color ${transitions.normal}, background ${transitions.normal};
442
+ }
443
+
444
+ .form-input:focus {
445
+ outline: none;
446
+ border-color: ${colors.borderFocus};
447
+ background: ${colors.surface};
448
+ }
449
+
450
+ .form-input:hover {
451
+ border-color: ${colors.borderHover};
452
+ }
453
+
454
+ .form-hint {
455
+ display: block;
456
+ color: ${colors.textMuted};
457
+ font-size: ${typography.fontSize.sm};
458
+ margin-top: ${spacing[2]};
459
+ }
460
+
461
+ /* Buttons */
462
+ .btn {
463
+ width: 100%;
464
+ padding: ${spacing[3]} ${spacing[5]};
465
+ border: none;
466
+ border-radius: ${layout.borderRadius.sm};
467
+ cursor: pointer;
468
+ font-weight: ${typography.fontWeight.medium};
469
+ font-size: ${typography.fontSize.base};
470
+ transition: background ${transitions.normal}, opacity ${transitions.normal};
471
+ }
472
+
473
+ .btn-primary {
474
+ background: ${colors.accent};
475
+ color: ${colors.textInverse};
476
+ }
477
+
478
+ .btn-primary:hover:not(:disabled) {
479
+ background: ${colors.accentHover};
480
+ }
481
+
482
+ .btn-primary:disabled {
483
+ opacity: 0.6;
484
+ cursor: not-allowed;
485
+ }
486
+
487
+ /* Error message */
488
+ .error-message {
489
+ padding: ${spacing[3]};
490
+ background: ${colors.errorBg};
491
+ color: ${colors.errorText};
492
+ border-radius: ${layout.borderRadius.sm};
493
+ margin-bottom: ${spacing[4]};
494
+ border: 1px solid ${colors.error};
495
+ font-size: ${typography.fontSize.base};
496
+ }
497
+
498
+ /* Footer text */
499
+ .auth-footer {
500
+ margin-top: ${spacing[6]};
501
+ text-align: center;
502
+ color: ${colors.textMuted};
503
+ font-size: ${typography.fontSize.base};
504
+ }
505
+
506
+ .auth-footer a {
507
+ color: ${colors.accent};
508
+ font-weight: ${typography.fontWeight.medium};
509
+ }
510
+
511
+ .auth-footer a:hover {
512
+ opacity: 0.8;
513
+ }
514
+ `.trim();
515
+ }
516
+ /**
517
+ * Marketing layout styles - Banner/badge
518
+ */
519
+ export function generateRscMarketingStyles() {
520
+ return `
521
+ .marketing-layout {
522
+ position: relative;
523
+ }
524
+
525
+ .marketing-banner {
526
+ background: ${colors.surface};
527
+ border: 1px solid ${colors.border};
528
+ border-radius: ${layout.borderRadius.lg};
529
+ padding: ${spacing[4]} ${spacing[6]};
530
+ margin-bottom: ${spacing[6]};
531
+ display: flex;
532
+ align-items: center;
533
+ gap: ${spacing[4]};
534
+ }
535
+
536
+ .marketing-banner .badge {
537
+ display: inline-block;
538
+ background: ${colors.accent};
539
+ color: ${colors.textInverse};
540
+ font-size: ${typography.fontSize.xs};
541
+ text-transform: uppercase;
542
+ padding: ${spacing[2]} ${spacing[3]};
543
+ border-radius: ${layout.borderRadius.sm};
544
+ font-weight: ${typography.fontWeight.semibold};
545
+ letter-spacing: 0.05em;
546
+ }
547
+
548
+ .marketing-banner span:not(.badge) {
549
+ color: ${colors.textMuted};
550
+ font-size: ${typography.fontSize.base};
551
+ }
552
+ `.trim();
553
+ }
@@ -3,6 +3,9 @@
3
3
  *
4
4
  * Re-exports all shared template generators for workspace projects.
5
5
  */
6
+ export * from './css-generator.js';
6
7
  export * from './root.js';
8
+ export * from './rsc-styles.js';
9
+ export * from './theme.js';
7
10
  export * from './web-base.js';
8
11
  export * from './web-styles.js';
@@ -3,6 +3,9 @@
3
3
  *
4
4
  * Re-exports all shared template generators for workspace projects.
5
5
  */
6
+ export * from './css-generator.js';
6
7
  export * from './root.js';
8
+ export * from './rsc-styles.js';
9
+ export * from './theme.js';
7
10
  export * from './web-base.js';
8
11
  export * from './web-styles.js';
@@ -0,0 +1,54 @@
1
+ /**
2
+ * RSC Navigation Configurations
3
+ *
4
+ * Provides navigation item configs for RSC templates.
5
+ * Separates basic RSC nav from auth-aware RSC nav.
6
+ */
7
+ /**
8
+ * Navigation item structure
9
+ */
10
+ export interface NavItem {
11
+ href: string;
12
+ label: string;
13
+ authRequired?: boolean;
14
+ guestOnly?: boolean;
15
+ }
16
+ /**
17
+ * Navigation items for basic RSC template (no auth)
18
+ *
19
+ * Routes:
20
+ * - / (Home)
21
+ * - /users (Users list)
22
+ * - /about (About page)
23
+ * - /docs/getting-started (Documentation)
24
+ */
25
+ export declare const RSC_NAV_ITEMS: NavItem[];
26
+ /**
27
+ * Navigation items for RSC-Auth template (with authentication)
28
+ *
29
+ * Routes:
30
+ * - / (Home)
31
+ * - /users (Users list)
32
+ * - /dashboard (Dashboard - auth required)
33
+ * - /auth/login (Login - guest only)
34
+ * - /auth/register (Register - guest only)
35
+ */
36
+ export declare const RSC_AUTH_NAV_ITEMS: NavItem[];
37
+ /**
38
+ * Filter navigation items based on authentication status
39
+ *
40
+ * @param items - Full navigation items list
41
+ * @param isAuthenticated - Whether the user is authenticated
42
+ * @returns Filtered navigation items
43
+ */
44
+ export declare function filterNavByAuth(items: NavItem[], isAuthenticated: boolean): NavItem[];
45
+ /**
46
+ * Detect authentication from cookie header (server-side)
47
+ *
48
+ * This is a simple cookie-based auth detection for navigation purposes.
49
+ * The actual auth validation happens in the API layer.
50
+ *
51
+ * @param cookieHeader - Cookie header string from request
52
+ * @returns Whether an access token cookie exists
53
+ */
54
+ export declare function hasAuthToken(cookieHeader: string | undefined | null): boolean;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * RSC Navigation Configurations
3
+ *
4
+ * Provides navigation item configs for RSC templates.
5
+ * Separates basic RSC nav from auth-aware RSC nav.
6
+ */
7
+ /**
8
+ * Navigation items for basic RSC template (no auth)
9
+ *
10
+ * Routes:
11
+ * - / (Home)
12
+ * - /users (Users list)
13
+ * - /about (About page)
14
+ * - /docs/getting-started (Documentation)
15
+ */
16
+ export const RSC_NAV_ITEMS = [
17
+ { href: '/', label: 'Home' },
18
+ { href: '/users', label: 'Users' },
19
+ { href: '/about', label: 'About' },
20
+ { href: '/docs/getting-started', label: 'Docs' },
21
+ ];
22
+ /**
23
+ * Navigation items for RSC-Auth template (with authentication)
24
+ *
25
+ * Routes:
26
+ * - / (Home)
27
+ * - /users (Users list)
28
+ * - /dashboard (Dashboard - auth required)
29
+ * - /auth/login (Login - guest only)
30
+ * - /auth/register (Register - guest only)
31
+ */
32
+ export const RSC_AUTH_NAV_ITEMS = [
33
+ { href: '/', label: 'Home' },
34
+ { href: '/users', label: 'Users' },
35
+ { href: '/dashboard', label: 'Dashboard', authRequired: true },
36
+ { href: '/auth/login', label: 'Login', guestOnly: true },
37
+ { href: '/auth/register', label: 'Register', guestOnly: true },
38
+ ];
39
+ /**
40
+ * Filter navigation items based on authentication status
41
+ *
42
+ * @param items - Full navigation items list
43
+ * @param isAuthenticated - Whether the user is authenticated
44
+ * @returns Filtered navigation items
45
+ */
46
+ export function filterNavByAuth(items, isAuthenticated) {
47
+ return items.filter((item) => {
48
+ if (item.authRequired && !isAuthenticated)
49
+ return false;
50
+ if (item.guestOnly && isAuthenticated)
51
+ return false;
52
+ return true;
53
+ });
54
+ }
55
+ /**
56
+ * Detect authentication from cookie header (server-side)
57
+ *
58
+ * This is a simple cookie-based auth detection for navigation purposes.
59
+ * The actual auth validation happens in the API layer.
60
+ *
61
+ * @param cookieHeader - Cookie header string from request
62
+ * @returns Whether an access token cookie exists
63
+ */
64
+ export function hasAuthToken(cookieHeader) {
65
+ if (!cookieHeader)
66
+ return false;
67
+ return cookieHeader.includes('accessToken=');
68
+ }