@l4yercak3/cli 1.2.20 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Pages Command
3
+ * Detect and sync application pages/screens with L4YERCAK3
4
+ */
5
+
6
+ const configManager = require('../config/config-manager');
7
+ const backendClient = require('../api/backend-client');
8
+ const projectDetector = require('../detectors');
9
+ const pageDetector = require('../detectors/page-detector');
10
+ const chalk = require('chalk');
11
+ const inquirer = require('inquirer');
12
+
13
+ /**
14
+ * Get framework display name
15
+ */
16
+ function getFrameworkName(frameworkType) {
17
+ const names = {
18
+ 'nextjs': 'Next.js',
19
+ 'expo': 'Expo',
20
+ 'react-native': 'React Native',
21
+ };
22
+ return names[frameworkType] || frameworkType;
23
+ }
24
+
25
+ /**
26
+ * Handle pages sync command
27
+ */
28
+ async function handlePagesSync() {
29
+ // Check if logged in
30
+ if (!configManager.isLoggedIn()) {
31
+ console.log(chalk.yellow(' ⚠️ You must be logged in first'));
32
+ console.log(chalk.gray('\n Run "l4yercak3 login" to authenticate\n'));
33
+ process.exit(1);
34
+ }
35
+
36
+ console.log(chalk.cyan(' 🔍 Scanning for pages...\n'));
37
+
38
+ // Detect project
39
+ const detection = projectDetector.detect();
40
+
41
+ if (!detection.framework.type) {
42
+ console.log(chalk.yellow(' ⚠️ Could not detect project type'));
43
+ console.log(chalk.gray(' Supported frameworks: Next.js, Expo, React Native\n'));
44
+ process.exit(1);
45
+ }
46
+
47
+ const frameworkName = getFrameworkName(detection.framework.type);
48
+ console.log(chalk.gray(` Framework: ${frameworkName}`));
49
+
50
+ // Check for project configuration
51
+ const projectConfig = configManager.getProjectConfig(detection.projectPath);
52
+
53
+ if (!projectConfig || !projectConfig.applicationId) {
54
+ console.log(chalk.yellow('\n ⚠️ This project is not connected to L4YERCAK3'));
55
+ console.log(chalk.gray(' Run "l4yercak3 spread" first to set up the connection\n'));
56
+ process.exit(1);
57
+ }
58
+
59
+ // Detect pages
60
+ const pages = pageDetector.detect(
61
+ detection.projectPath,
62
+ detection.framework.type,
63
+ detection.framework.metadata
64
+ );
65
+
66
+ if (pages.length === 0) {
67
+ console.log(chalk.yellow('\n ⚠️ No pages found'));
68
+ console.log(chalk.gray(' Make sure your project has page files in the expected locations\n'));
69
+ return;
70
+ }
71
+
72
+ // Categorize pages
73
+ const staticPages = pages.filter(p => p.pageType === 'static');
74
+ const dynamicPages = pages.filter(p => p.pageType === 'dynamic');
75
+ const apiRoutes = pages.filter(p => p.pageType === 'api_route');
76
+
77
+ console.log(chalk.green(`\n ✅ Found ${pages.length} pages/routes\n`));
78
+
79
+ if (staticPages.length > 0) {
80
+ console.log(chalk.gray(` ${staticPages.length} static page(s)`));
81
+ }
82
+ if (dynamicPages.length > 0) {
83
+ console.log(chalk.gray(` ${dynamicPages.length} dynamic page(s)`));
84
+ }
85
+ if (apiRoutes.length > 0) {
86
+ console.log(chalk.gray(` ${apiRoutes.length} API route(s)`));
87
+ }
88
+
89
+ // Show preview
90
+ console.log(chalk.cyan('\n 📋 Pages to sync:\n'));
91
+
92
+ const maxPathLength = Math.max(...pages.map(p => p.path.length), 20);
93
+
94
+ for (const page of pages.slice(0, 15)) {
95
+ const icon = page.pageType === 'api_route' ? '⚡' :
96
+ page.pageType === 'dynamic' ? '🔀' : '📄';
97
+ const paddedPath = page.path.padEnd(maxPathLength);
98
+ console.log(chalk.gray(` ${icon} ${paddedPath} → ${page.name}`));
99
+ }
100
+
101
+ if (pages.length > 15) {
102
+ console.log(chalk.gray(` ... and ${pages.length - 15} more`));
103
+ }
104
+
105
+ // Confirm sync
106
+ console.log('');
107
+ const { confirmSync } = await inquirer.prompt([
108
+ {
109
+ type: 'confirm',
110
+ name: 'confirmSync',
111
+ message: `Sync ${pages.length} pages to L4YERCAK3?`,
112
+ default: true,
113
+ },
114
+ ]);
115
+
116
+ if (!confirmSync) {
117
+ console.log(chalk.gray('\n Sync cancelled.\n'));
118
+ return;
119
+ }
120
+
121
+ // Sync pages
122
+ console.log(chalk.cyan('\n 🔄 Syncing pages...\n'));
123
+
124
+ try {
125
+ const result = await backendClient.bulkRegisterPages(
126
+ projectConfig.applicationId,
127
+ pages.map(p => ({
128
+ path: p.path,
129
+ name: p.name,
130
+ pageType: p.pageType,
131
+ }))
132
+ );
133
+
134
+ console.log(chalk.green(' ✅ Pages synced successfully!\n'));
135
+ console.log(chalk.gray(` Total: ${result.total || pages.length}`));
136
+ if (result.created !== undefined) {
137
+ console.log(chalk.gray(` Created: ${result.created}`));
138
+ }
139
+ if (result.updated !== undefined) {
140
+ console.log(chalk.gray(` Updated: ${result.updated}`));
141
+ }
142
+
143
+ console.log(chalk.cyan('\n 📊 View your pages in the L4YERCAK3 dashboard:'));
144
+ console.log(chalk.gray(' Web Publishing → Applications → Pages & Bindings\n'));
145
+
146
+ } catch (error) {
147
+ console.error(chalk.red(`\n ❌ Failed to sync pages: ${error.message}\n`));
148
+ if (error.code) {
149
+ console.log(chalk.gray(` Error code: ${error.code}`));
150
+ }
151
+ process.exit(1);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Handle pages list command
157
+ */
158
+ async function handlePagesList() {
159
+ // Check if logged in
160
+ if (!configManager.isLoggedIn()) {
161
+ console.log(chalk.yellow(' ⚠️ You must be logged in first'));
162
+ console.log(chalk.gray('\n Run "l4yercak3 login" to authenticate\n'));
163
+ process.exit(1);
164
+ }
165
+
166
+ // Detect project
167
+ const detection = projectDetector.detect();
168
+ const projectConfig = configManager.getProjectConfig(detection.projectPath);
169
+
170
+ if (!projectConfig || !projectConfig.applicationId) {
171
+ console.log(chalk.yellow(' ⚠️ This project is not connected to L4YERCAK3'));
172
+ console.log(chalk.gray(' Run "l4yercak3 spread" first to set up the connection\n'));
173
+ process.exit(1);
174
+ }
175
+
176
+ console.log(chalk.cyan(' 📋 Fetching registered pages...\n'));
177
+
178
+ try {
179
+ const result = await backendClient.getApplicationPages(projectConfig.applicationId);
180
+
181
+ if (!result.pages || result.pages.length === 0) {
182
+ console.log(chalk.yellow(' No pages registered yet'));
183
+ console.log(chalk.gray(' Run "l4yercak3 pages sync" to detect and sync pages\n'));
184
+ return;
185
+ }
186
+
187
+ console.log(chalk.green(` ✅ ${result.pages.length} pages registered\n`));
188
+
189
+ const maxPathLength = Math.max(...result.pages.map(p => p.path.length), 20);
190
+
191
+ for (const page of result.pages) {
192
+ const icon = page.pageType === 'api_route' ? '⚡' :
193
+ page.pageType === 'dynamic' ? '🔀' : '📄';
194
+ const paddedPath = page.path.padEnd(maxPathLength);
195
+ console.log(chalk.gray(` ${icon} ${paddedPath} → ${page.name}`));
196
+ }
197
+
198
+ console.log('');
199
+
200
+ } catch (error) {
201
+ console.error(chalk.red(`\n ❌ Failed to fetch pages: ${error.message}\n`));
202
+ process.exit(1);
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Handle pages detect command (local only, no sync)
208
+ */
209
+ async function handlePagesDetect() {
210
+ console.log(chalk.cyan(' 🔍 Detecting pages...\n'));
211
+
212
+ // Detect project
213
+ const detection = projectDetector.detect();
214
+
215
+ if (!detection.framework.type) {
216
+ console.log(chalk.yellow(' ⚠️ Could not detect project type'));
217
+ console.log(chalk.gray(' Supported frameworks: Next.js, Expo, React Native\n'));
218
+ process.exit(1);
219
+ }
220
+
221
+ const frameworkName = getFrameworkName(detection.framework.type);
222
+ console.log(chalk.gray(` Framework: ${frameworkName}`));
223
+
224
+ if (detection.framework.metadata?.routerType) {
225
+ const routerName = detection.framework.type === 'nextjs'
226
+ ? (detection.framework.metadata.routerType === 'app' ? 'App Router' : 'Pages Router')
227
+ : (detection.framework.metadata.routerType === 'expo-router' ? 'Expo Router' : 'React Navigation');
228
+ console.log(chalk.gray(` Router: ${routerName}`));
229
+ }
230
+
231
+ // Detect pages
232
+ const pages = pageDetector.detect(
233
+ detection.projectPath,
234
+ detection.framework.type,
235
+ detection.framework.metadata
236
+ );
237
+
238
+ if (pages.length === 0) {
239
+ console.log(chalk.yellow('\n ⚠️ No pages found'));
240
+ console.log(chalk.gray(' Make sure your project has page files in the expected locations\n'));
241
+ return;
242
+ }
243
+
244
+ console.log(chalk.green(`\n ✅ Found ${pages.length} pages/routes\n`));
245
+
246
+ // Group by type
247
+ const staticPages = pages.filter(p => p.pageType === 'static');
248
+ const dynamicPages = pages.filter(p => p.pageType === 'dynamic');
249
+ const apiRoutes = pages.filter(p => p.pageType === 'api_route');
250
+
251
+ const maxPathLength = Math.max(...pages.map(p => p.path.length), 20);
252
+
253
+ if (staticPages.length > 0) {
254
+ console.log(chalk.cyan(' 📄 Static Pages:\n'));
255
+ for (const page of staticPages) {
256
+ const paddedPath = page.path.padEnd(maxPathLength);
257
+ console.log(chalk.gray(` ${paddedPath} → ${page.name}`));
258
+ console.log(chalk.gray(` └─ ${page.filePath}`));
259
+ }
260
+ console.log('');
261
+ }
262
+
263
+ if (dynamicPages.length > 0) {
264
+ console.log(chalk.cyan(' 🔀 Dynamic Pages:\n'));
265
+ for (const page of dynamicPages) {
266
+ const paddedPath = page.path.padEnd(maxPathLength);
267
+ console.log(chalk.gray(` ${paddedPath} → ${page.name}`));
268
+ console.log(chalk.gray(` └─ ${page.filePath}`));
269
+ }
270
+ console.log('');
271
+ }
272
+
273
+ if (apiRoutes.length > 0) {
274
+ console.log(chalk.cyan(' ⚡ API Routes:\n'));
275
+ for (const page of apiRoutes) {
276
+ const paddedPath = page.path.padEnd(maxPathLength);
277
+ console.log(chalk.gray(` ${paddedPath} → ${page.name}`));
278
+ console.log(chalk.gray(` └─ ${page.filePath}`));
279
+ }
280
+ console.log('');
281
+ }
282
+
283
+ console.log(chalk.gray(' Run "l4yercak3 pages sync" to sync these pages to L4YERCAK3\n'));
284
+ }
285
+
286
+ /**
287
+ * Main pages command handler
288
+ */
289
+ async function handlePages(args) {
290
+ const subcommand = args[0] || 'sync';
291
+
292
+ switch (subcommand) {
293
+ case 'sync':
294
+ await handlePagesSync();
295
+ break;
296
+ case 'list':
297
+ await handlePagesList();
298
+ break;
299
+ case 'detect':
300
+ await handlePagesDetect();
301
+ break;
302
+ default:
303
+ console.log(chalk.cyan(' 📄 Pages Command\n'));
304
+ console.log(chalk.gray(' Usage: l4yercak3 pages <subcommand>\n'));
305
+ console.log(chalk.gray(' Subcommands:'));
306
+ console.log(chalk.gray(' sync Detect and sync pages to L4YERCAK3 (default)'));
307
+ console.log(chalk.gray(' list List pages registered with L4YERCAK3'));
308
+ console.log(chalk.gray(' detect Detect pages locally (no sync)\n'));
309
+ break;
310
+ }
311
+ }
312
+
313
+ module.exports = {
314
+ command: 'pages',
315
+ description: 'Detect and sync application pages',
316
+ handler: handlePages,
317
+ };