@xbg.solutions/create-frontend 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,774 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Route Generator
5
+ *
6
+ * Generates a new SvelteKit route with TypeScript support, layout, and load functions.
7
+ *
8
+ * Usage:
9
+ * node __scripts__/generate-route.js <route-path> [options]
10
+ * npm run generate:route <route-path> [options]
11
+ *
12
+ * Options:
13
+ * --type <type> Route type: page|layout|api|group (default: page)
14
+ * --auth Require authentication
15
+ * --roles <roles> Required roles (comma-separated)
16
+ * --with-load Generate load function
17
+ * --with-actions Generate form actions
18
+ * --with-error Generate error page
19
+ *
20
+ * Examples:
21
+ * node __scripts__/generate-route.js dashboard --auth --roles=user,admin
22
+ * node __scripts__/generate-route.js api/users --type=api --with-actions
23
+ * node __scripts__/generate-route.js admin --type=layout --auth --roles=admin
24
+ */
25
+
26
+ const fs = require('fs');
27
+ const path = require('path');
28
+
29
+ // Parse command line arguments
30
+ const args = process.argv.slice(2);
31
+ const routePath = args[0];
32
+
33
+ if (!routePath) {
34
+ console.error('āŒ Route path is required!');
35
+ console.log('Usage: node __scripts__/generate-route.js <route-path> [options]');
36
+ console.log('Examples:');
37
+ console.log(' node __scripts__/generate-route.js dashboard');
38
+ console.log(' node __scripts__/generate-route.js api/users --type=api');
39
+ console.log(' node __scripts__/generate-route.js admin --type=layout --auth');
40
+ process.exit(1);
41
+ }
42
+
43
+ // Parse options
44
+ const options = {
45
+ type: 'page',
46
+ auth: false,
47
+ roles: [],
48
+ withLoad: false,
49
+ withActions: false,
50
+ withError: false
51
+ };
52
+
53
+ args.slice(1).forEach(arg => {
54
+ if (arg.startsWith('--type=')) {
55
+ options.type = arg.split('=')[1];
56
+ } else if (arg.startsWith('--roles=')) {
57
+ options.roles = arg.split('=')[1].split(',').map(r => r.trim());
58
+ } else if (arg === '--auth') {
59
+ options.auth = true;
60
+ } else if (arg === '--with-load') {
61
+ options.withLoad = true;
62
+ } else if (arg === '--with-actions') {
63
+ options.withActions = true;
64
+ } else if (arg === '--with-error') {
65
+ options.withError = true;
66
+ }
67
+ });
68
+
69
+ // Validate route type
70
+ if (!['page', 'layout', 'api', 'group'].includes(options.type)) {
71
+ console.error('āŒ Invalid route type. Must be: page, layout, api, or group');
72
+ process.exit(1);
73
+ }
74
+
75
+ // Generate file paths
76
+ const routeDir = path.join('src', 'routes', routePath);
77
+ const isApiRoute = routePath.startsWith('api/') || options.type === 'api';
78
+
79
+ // Ensure directory exists
80
+ if (!fs.existsSync(routeDir)) {
81
+ fs.mkdirSync(routeDir, { recursive: true });
82
+ }
83
+
84
+ // Generate route name for display
85
+ const routeName = routePath
86
+ .split('/')
87
+ .pop()
88
+ .split('-')
89
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
90
+ .join(' ');
91
+
92
+ // Generate page template
93
+ function generatePageTemplate() {
94
+ const authImport = options.auth ? `
95
+ import { authGuard } from '$lib/utils/auth-guard';
96
+ import { authService } from '$lib/services/auth';` : '';
97
+
98
+ const authCode = options.auth ? `
99
+ const user = authService.getUser();
100
+ const claims = authService.getUserClaims();
101
+
102
+ onMount(() => {
103
+ authGuard({
104
+ requiredRoles: ${JSON.stringify(options.roles)},
105
+ redirectTo: '/login',
106
+ currentPath: $page.url.pathname
107
+ });
108
+ });` : '';
109
+
110
+ const rolesCheck = options.roles.length > 0 ? `
111
+ $: hasRequiredRole = ${options.roles.map(role => `$claims?.roles?.includes('${role}')`).join(' || ')};` : '';
112
+
113
+ return `<script lang="ts">
114
+ import { page } from '$app/stores';
115
+ import { onMount } from 'svelte';${authImport}
116
+ import { Button } from '$lib/components/ui/button';
117
+ import { Card, CardHeader, CardTitle, CardContent } from '$lib/components/ui/card';
118
+ ${options.withLoad ? "import type { PageData } from './$types';" : ''}
119
+
120
+ ${options.withLoad ? 'export let data: PageData;' : ''}
121
+
122
+ // Page state
123
+ let loading = false;
124
+ let error: string | null = null;${authCode}${rolesCheck}
125
+
126
+ onMount(() => {
127
+ loadPageData();
128
+ });
129
+
130
+ async function loadPageData() {
131
+ loading = true;
132
+ error = null;
133
+
134
+ try {
135
+ // Load page-specific data
136
+ console.log('Loading ${routeName} data...');
137
+ } catch (err) {
138
+ error = 'Failed to load page data';
139
+ console.error('${routeName} error:', err);
140
+ } finally {
141
+ loading = false;
142
+ }
143
+ }
144
+
145
+ function handleRefresh() {
146
+ loadPageData();
147
+ }
148
+ </script>
149
+
150
+ <svelte:head>
151
+ <title>${routeName}</title>
152
+ <meta name="description" content="${routeName} page" />
153
+ </svelte:head>
154
+
155
+ <div class="container mx-auto py-6">
156
+ <div class="mb-6">
157
+ <h1 class="text-3xl font-bold">${routeName}</h1>
158
+ <p class="text-gray-600">Welcome to the ${routeName.toLowerCase()} page</p>
159
+ </div>
160
+ ${options.auth && options.roles.length > 0 ? `
161
+ {#if !hasRequiredRole}
162
+ <Card>
163
+ <CardContent class="p-6 text-center">
164
+ <h2 class="text-xl font-semibold mb-2">Access Denied</h2>
165
+ <p class="text-gray-600">You don't have permission to view this page.</p>
166
+ <p class="text-sm text-gray-500 mt-2">Required roles: ${options.roles.join(', ')}</p>
167
+ <Button href="/dashboard" variant="outline" class="mt-4">
168
+ Go to Dashboard
169
+ </Button>
170
+ </CardContent>
171
+ </Card>
172
+ {:else}` : ''}
173
+
174
+ {#if loading}
175
+ <div class="flex justify-center py-12">
176
+ <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
177
+ </div>
178
+ {:else if error}
179
+ <Card>
180
+ <CardContent class="p-6">
181
+ <div class="text-center">
182
+ <h2 class="text-xl font-semibold mb-2 text-red-600">Error</h2>
183
+ <p class="text-gray-600 mb-4">{error}</p>
184
+ <Button on:click={handleRefresh} variant="outline">
185
+ Try Again
186
+ </Button>
187
+ </div>
188
+ </CardContent>
189
+ </Card>
190
+ {:else}
191
+ <div class="grid gap-6">
192
+ <Card>
193
+ <CardHeader>
194
+ <CardTitle>${routeName} Content</CardTitle>
195
+ </CardHeader>
196
+ <CardContent>
197
+ <p>Add your page content here.</p>
198
+ ${options.auth ? `
199
+ {#if $user}
200
+ <div class="mt-4 p-4 bg-green-50 rounded-lg">
201
+ <p class="text-green-800">Authenticated as: {$user.email}</p>
202
+ {#if $claims?.roles?.length}
203
+ <p class="text-green-600 text-sm">Roles: {$claims.roles.join(', ')}</p>
204
+ {/if}
205
+ </div>
206
+ {/if}` : ''}
207
+ </CardContent>
208
+ </Card>
209
+ </div>
210
+ {/if}${options.auth && options.roles.length > 0 ? `
211
+ {/if}` : ''}
212
+ </div>`;
213
+ }
214
+
215
+ // Generate layout template
216
+ function generateLayoutTemplate() {
217
+ const authImport = options.auth ? `
218
+ import { authGuard } from '$lib/utils/auth-guard';
219
+ import { authService } from '$lib/services/auth';` : '';
220
+
221
+ const authCode = options.auth ? `
222
+ const user = authService.getUser();
223
+ const claims = authService.getUserClaims();
224
+
225
+ onMount(() => {
226
+ authGuard({
227
+ requiredRoles: ${JSON.stringify(options.roles)},
228
+ redirectTo: '/login',
229
+ currentPath: $page.url.pathname
230
+ });
231
+ });` : '';
232
+
233
+ return `<script lang="ts">
234
+ import { page } from '$app/stores';
235
+ import { onMount } from 'svelte';${authImport}
236
+ import { Button } from '$lib/components/ui/button';
237
+ ${options.withLoad ? "import type { LayoutData } from './$types';" : ''}
238
+
239
+ ${options.withLoad ? 'export let data: LayoutData;' : ''}${authCode}
240
+ </script>
241
+
242
+ <div class="min-h-screen bg-gray-50">
243
+ <!-- Navigation header -->
244
+ <header class="bg-white shadow-sm border-b">
245
+ <div class="container mx-auto px-4">
246
+ <div class="flex items-center justify-between h-16">
247
+ <div class="flex items-center">
248
+ <h1 class="text-xl font-semibold">${routeName}</h1>
249
+ <nav class="ml-8 space-x-4">
250
+ <!-- Add navigation links -->
251
+ </nav>
252
+ </div>
253
+
254
+ <div class="flex items-center space-x-4">
255
+ ${options.auth ? `
256
+ {#if $user}
257
+ <span class="text-sm text-gray-600">Welcome, {$user.email}</span>
258
+ <Button variant="outline" size="sm" on:click={() => authService.logout()}>
259
+ Logout
260
+ </Button>
261
+ {:else}
262
+ <Button href="/login" size="sm">
263
+ Login
264
+ </Button>
265
+ {/if}` : ''}
266
+ </div>
267
+ </div>
268
+ </div>
269
+ </header>
270
+
271
+ <!-- Main content -->
272
+ <main>
273
+ <slot />
274
+ </main>
275
+
276
+ <!-- Footer -->
277
+ <footer class="bg-white border-t mt-auto">
278
+ <div class="container mx-auto px-4 py-4">
279
+ <p class="text-center text-gray-600 text-sm">
280
+ Ā© {new Date().getFullYear()} Your App. All rights reserved.
281
+ </p>
282
+ </div>
283
+ </footer>
284
+ </div>`;
285
+ }
286
+
287
+ // Generate API route template
288
+ function generateApiTemplate() {
289
+ const methods = options.withActions ? ['GET', 'POST', 'PUT', 'DELETE'] : ['GET'];
290
+
291
+ let template = `import { json, error } from '@sveltejs/kit';
292
+ import type { RequestHandler } from './$types';
293
+ import { apiService } from '$lib/services/api/api.service';
294
+ import { handleError } from '$lib/utils/error-handler';
295
+
296
+ // Types
297
+ interface ${routeName}Item {
298
+ id: string;
299
+ // Add your data structure here
300
+ }
301
+
302
+ interface Create${routeName}Request {
303
+ // Add creation request structure
304
+ }
305
+
306
+ interface Update${routeName}Request {
307
+ // Add update request structure
308
+ }
309
+
310
+ `;
311
+
312
+ methods.forEach(method => {
313
+ switch (method) {
314
+ case 'GET':
315
+ template += `
316
+ // GET /${routePath}
317
+ export const GET: RequestHandler = async ({ url, locals }) => {
318
+ try {
319
+ // Optional: Check authentication
320
+ // if (!locals.user) {
321
+ // throw error(401, 'Unauthorized');
322
+ // }
323
+
324
+ // Parse query parameters
325
+ const limit = Number(url.searchParams.get('limit')) || 10;
326
+ const offset = Number(url.searchParams.get('offset')) || 0;
327
+ const search = url.searchParams.get('search') || '';
328
+
329
+ // Fetch data (replace with your data source)
330
+ const items: ${routeName}Item[] = [
331
+ // Mock data - replace with actual data fetching
332
+ ];
333
+
334
+ // Apply search filter if provided
335
+ const filteredItems = search
336
+ ? items.filter(item =>
337
+ Object.values(item).some(value =>
338
+ String(value).toLowerCase().includes(search.toLowerCase())
339
+ )
340
+ )
341
+ : items;
342
+
343
+ // Apply pagination
344
+ const paginatedItems = filteredItems.slice(offset, offset + limit);
345
+
346
+ return json({
347
+ data: paginatedItems,
348
+ meta: {
349
+ total: filteredItems.length,
350
+ limit,
351
+ offset,
352
+ hasMore: offset + limit < filteredItems.length
353
+ }
354
+ });
355
+
356
+ } catch (err) {
357
+ console.error('GET /${routePath} error:', err);
358
+ const errorResponse = handleError(err, 'Failed to fetch ${routeName.toLowerCase()}');
359
+ throw error(500, errorResponse);
360
+ }
361
+ };`;
362
+ break;
363
+
364
+ case 'POST':
365
+ template += `
366
+
367
+ // POST /${routePath}
368
+ export const POST: RequestHandler = async ({ request, locals }) => {
369
+ try {
370
+ // Check authentication
371
+ // if (!locals.user) {
372
+ // throw error(401, 'Unauthorized');
373
+ // }
374
+
375
+ const requestData: Create${routeName}Request = await request.json();
376
+
377
+ // Validate request data
378
+ if (!requestData) {
379
+ throw error(400, 'Invalid request data');
380
+ }
381
+
382
+ // Create new item (replace with your data creation logic)
383
+ const newItem: ${routeName}Item = {
384
+ id: crypto.randomUUID(),
385
+ ...requestData,
386
+ // Add other fields like timestamps, user ID, etc.
387
+ };
388
+
389
+ // Save to database/storage
390
+ // await saveItem(newItem);
391
+
392
+ return json({
393
+ data: newItem,
394
+ message: '${routeName} created successfully'
395
+ }, { status: 201 });
396
+
397
+ } catch (err) {
398
+ console.error('POST /${routePath} error:', err);
399
+ const errorResponse = handleError(err, 'Failed to create ${routeName.toLowerCase()}');
400
+ throw error(500, errorResponse);
401
+ }
402
+ };`;
403
+ break;
404
+
405
+ case 'PUT':
406
+ template += `
407
+
408
+ // PUT /${routePath}/[id]
409
+ export const PUT: RequestHandler = async ({ params, request, locals }) => {
410
+ try {
411
+ // Check authentication
412
+ // if (!locals.user) {
413
+ // throw error(401, 'Unauthorized');
414
+ // }
415
+
416
+ const { id } = params;
417
+ if (!id) {
418
+ throw error(400, 'ID parameter is required');
419
+ }
420
+
421
+ const requestData: Update${routeName}Request = await request.json();
422
+
423
+ // Find existing item
424
+ // const existingItem = await findItemById(id);
425
+ // if (!existingItem) {
426
+ // throw error(404, '${routeName} not found');
427
+ // }
428
+
429
+ // Update item (replace with your update logic)
430
+ const updatedItem: ${routeName}Item = {
431
+ id,
432
+ ...requestData,
433
+ // Preserve certain fields or add timestamps
434
+ };
435
+
436
+ // Save updated item
437
+ // await updateItem(id, updatedItem);
438
+
439
+ return json({
440
+ data: updatedItem,
441
+ message: '${routeName} updated successfully'
442
+ });
443
+
444
+ } catch (err) {
445
+ console.error('PUT /${routePath}/[id] error:', err);
446
+ const errorResponse = handleError(err, 'Failed to update ${routeName.toLowerCase()}');
447
+ throw error(500, errorResponse);
448
+ }
449
+ };`;
450
+ break;
451
+
452
+ case 'DELETE':
453
+ template += `
454
+
455
+ // DELETE /${routePath}/[id]
456
+ export const DELETE: RequestHandler = async ({ params, locals }) => {
457
+ try {
458
+ // Check authentication
459
+ // if (!locals.user) {
460
+ // throw error(401, 'Unauthorized');
461
+ // }
462
+
463
+ const { id } = params;
464
+ if (!id) {
465
+ throw error(400, 'ID parameter is required');
466
+ }
467
+
468
+ // Find existing item
469
+ // const existingItem = await findItemById(id);
470
+ // if (!existingItem) {
471
+ // throw error(404, '${routeName} not found');
472
+ // }
473
+
474
+ // Delete item (replace with your deletion logic)
475
+ // await deleteItem(id);
476
+
477
+ return json({
478
+ message: '${routeName} deleted successfully'
479
+ });
480
+
481
+ } catch (err) {
482
+ console.error('DELETE /${routePath}/[id] error:', err);
483
+ const errorResponse = handleError(err, 'Failed to delete ${routeName.toLowerCase()}');
484
+ throw error(500, errorResponse);
485
+ }
486
+ };`;
487
+ break;
488
+ }
489
+ });
490
+
491
+ return template;
492
+ }
493
+
494
+ // Generate load function
495
+ function generateLoadFunction() {
496
+ const fileName = options.type === 'layout' ? '+layout.ts' : '+page.ts';
497
+
498
+ const authCheck = options.auth ? `
499
+ // Check authentication
500
+ if (!locals.user) {
501
+ throw redirect(302, '/login');
502
+ }
503
+
504
+ // Check role permissions
505
+ const userRoles = locals.claims?.roles || [];
506
+ const requiredRoles = ${JSON.stringify(options.roles)};
507
+
508
+ if (requiredRoles.length > 0 && !requiredRoles.some(role => userRoles.includes(role))) {
509
+ throw redirect(302, '/unauthorized');
510
+ }` : '';
511
+
512
+ return `import type { ${options.type === 'layout' ? 'LayoutLoad' : 'PageLoad'} } from './$types';
513
+ import { error, redirect } from '@sveltejs/kit';
514
+ import { apiService } from '$lib/services/api/api.service';
515
+
516
+ export const load: ${options.type === 'layout' ? 'LayoutLoad' : 'PageLoad'} = async ({ params, url, locals, fetch }) => {${authCheck}
517
+
518
+ try {
519
+ // Load page/layout data
520
+ const data = {
521
+ // Add your data loading logic here
522
+ title: '${routeName}',
523
+ user: locals.user || null,
524
+ claims: locals.claims || null
525
+ };
526
+
527
+ // Example: Load data from API
528
+ // const response = await apiService.get('/api/${routePath}', { fetch });
529
+ // data.items = response.data;
530
+
531
+ return data;
532
+
533
+ } catch (err) {
534
+ console.error('Load function error:', err);
535
+ throw error(500, 'Failed to load page data');
536
+ }
537
+ };`;
538
+ }
539
+
540
+ // Generate form actions
541
+ function generateFormActions() {
542
+ return `import { fail, redirect } from '@sveltejs/kit';
543
+ import type { Actions } from './$types';
544
+ import { apiService } from '$lib/services/api/api.service';
545
+ import { handleError } from '$lib/utils/error-handler';
546
+
547
+ export const actions: Actions = {
548
+ // Default form action
549
+ default: async ({ request, locals }) => {
550
+ ${options.auth ? `
551
+ if (!locals.user) {
552
+ throw redirect(302, '/login');
553
+ }` : ''}
554
+
555
+ const formData = await request.formData();
556
+
557
+ try {
558
+ // Process form data
559
+ const data = {
560
+ // Extract form fields
561
+ // name: formData.get('name')?.toString(),
562
+ // email: formData.get('email')?.toString(),
563
+ };
564
+
565
+ // Validate data
566
+ if (!data) {
567
+ return fail(400, {
568
+ error: 'Invalid form data',
569
+ data
570
+ });
571
+ }
572
+
573
+ // Process the form submission
574
+ // const result = await apiService.post('/api/${routePath}', data);
575
+
576
+ return {
577
+ success: true,
578
+ message: 'Form submitted successfully'
579
+ };
580
+
581
+ } catch (err) {
582
+ console.error('Form action error:', err);
583
+ return fail(500, {
584
+ error: handleError(err, 'Form submission failed'),
585
+ data: Object.fromEntries(formData)
586
+ });
587
+ }
588
+ },
589
+
590
+ // Create action
591
+ create: async ({ request, locals }) => {
592
+ ${options.auth ? `
593
+ if (!locals.user) {
594
+ throw redirect(302, '/login');
595
+ }` : ''}
596
+
597
+ const formData = await request.formData();
598
+
599
+ try {
600
+ // Handle create logic
601
+ return { success: true };
602
+ } catch (err) {
603
+ return fail(500, { error: 'Create failed' });
604
+ }
605
+ },
606
+
607
+ // Update action
608
+ update: async ({ request, locals }) => {
609
+ ${options.auth ? `
610
+ if (!locals.user) {
611
+ throw redirect(302, '/login');
612
+ }` : ''}
613
+
614
+ const formData = await request.formData();
615
+
616
+ try {
617
+ // Handle update logic
618
+ return { success: true };
619
+ } catch (err) {
620
+ return fail(500, { error: 'Update failed' });
621
+ }
622
+ },
623
+
624
+ // Delete action
625
+ delete: async ({ request, locals }) => {
626
+ ${options.auth ? `
627
+ if (!locals.user) {
628
+ throw redirect(302, '/login');
629
+ }` : ''}
630
+
631
+ const formData = await request.formData();
632
+ const id = formData.get('id')?.toString();
633
+
634
+ if (!id) {
635
+ return fail(400, { error: 'ID is required' });
636
+ }
637
+
638
+ try {
639
+ // Handle delete logic
640
+ return { success: true };
641
+ } catch (err) {
642
+ return fail(500, { error: 'Delete failed' });
643
+ }
644
+ }
645
+ };`;
646
+ }
647
+
648
+ // Generate error page
649
+ function generateErrorTemplate() {
650
+ return `<script lang="ts">
651
+ import { page } from '$app/stores';
652
+ import { Button } from '$lib/components/ui/button';
653
+ import { Card, CardHeader, CardTitle, CardContent } from '$lib/components/ui/card';
654
+
655
+ $: error = $page.error;
656
+ $: errorMessage = error?.message || 'An unexpected error occurred';
657
+ $: errorCode = error?.code || 500;
658
+ </script>
659
+
660
+ <svelte:head>
661
+ <title>Error {errorCode}</title>
662
+ </svelte:head>
663
+
664
+ <div class="min-h-screen flex items-center justify-center bg-gray-50 px-4">
665
+ <Card class="max-w-md w-full">
666
+ <CardHeader class="text-center">
667
+ <div class="w-20 h-20 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4">
668
+ <svg class="w-10 h-10 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
669
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
670
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
671
+ </svg>
672
+ </div>
673
+ <CardTitle class="text-2xl text-red-600">Error {errorCode}</CardTitle>
674
+ </CardHeader>
675
+
676
+ <CardContent class="text-center space-y-4">
677
+ <p class="text-gray-600">{errorMessage}</p>
678
+
679
+ <div class="space-y-2">
680
+ <Button href="/" class="w-full">
681
+ Go Home
682
+ </Button>
683
+ <Button href="/dashboard" variant="outline" class="w-full">
684
+ Go to Dashboard
685
+ </Button>
686
+ </div>
687
+
688
+ <details class="text-left mt-4">
689
+ <summary class="cursor-pointer text-sm text-gray-500">
690
+ Error Details
691
+ </summary>
692
+ <pre class="mt-2 p-3 bg-gray-100 rounded text-xs overflow-auto">
693
+ {JSON.stringify(error, null, 2)}
694
+ </pre>
695
+ </details>
696
+ </CardContent>
697
+ </Card>
698
+ </div>`;
699
+ }
700
+
701
+ // Write files
702
+ try {
703
+ console.log(`šŸš€ Generating ${options.type} route: /${routePath}`);
704
+
705
+ let filesToCreate = [];
706
+
707
+ if (isApiRoute || options.type === 'api') {
708
+ // API route
709
+ const serverFile = path.join(routeDir, '+server.ts');
710
+ fs.writeFileSync(serverFile, generateApiTemplate());
711
+ filesToCreate.push(serverFile);
712
+
713
+ } else if (options.type === 'layout') {
714
+ // Layout route
715
+ const layoutFile = path.join(routeDir, '+layout.svelte');
716
+ fs.writeFileSync(layoutFile, generateLayoutTemplate());
717
+ filesToCreate.push(layoutFile);
718
+
719
+ if (options.withLoad) {
720
+ const loadFile = path.join(routeDir, '+layout.ts');
721
+ fs.writeFileSync(loadFile, generateLoadFunction());
722
+ filesToCreate.push(loadFile);
723
+ }
724
+
725
+ } else if (options.type === 'group') {
726
+ // Route group (just create directory with layout)
727
+ const layoutFile = path.join(routeDir, '+layout.svelte');
728
+ fs.writeFileSync(layoutFile, `<slot />`);
729
+ filesToCreate.push(layoutFile);
730
+
731
+ } else {
732
+ // Page route
733
+ const pageFile = path.join(routeDir, '+page.svelte');
734
+ fs.writeFileSync(pageFile, generatePageTemplate());
735
+ filesToCreate.push(pageFile);
736
+
737
+ if (options.withLoad) {
738
+ const loadFile = path.join(routeDir, '+page.ts');
739
+ fs.writeFileSync(loadFile, generateLoadFunction());
740
+ filesToCreate.push(loadFile);
741
+ }
742
+
743
+ if (options.withActions) {
744
+ const actionsFile = path.join(routeDir, '+page.server.ts');
745
+ fs.writeFileSync(actionsFile, generateFormActions());
746
+ filesToCreate.push(actionsFile);
747
+ }
748
+ }
749
+
750
+ if (options.withError) {
751
+ const errorFile = path.join(routeDir, '+error.svelte');
752
+ fs.writeFileSync(errorFile, generateErrorTemplate());
753
+ filesToCreate.push(errorFile);
754
+ }
755
+
756
+ console.log(`āœ… Route files created:`);
757
+ filesToCreate.forEach(file => {
758
+ console.log(` ${file}`);
759
+ });
760
+
761
+ console.log(`\nšŸŽ‰ Route /${routePath} generated successfully!`);
762
+ console.log(`\n🌐 View your route at: http://localhost:5173/${routePath}`);
763
+
764
+ if (options.auth) {
765
+ console.log(`\nšŸ”’ Authentication: Enabled`);
766
+ if (options.roles.length > 0) {
767
+ console.log(` Required roles: ${options.roles.join(', ')}`);
768
+ }
769
+ }
770
+
771
+ } catch (error) {
772
+ console.error('āŒ Error generating route:', error.message);
773
+ process.exit(1);
774
+ }