@juuno-sdk/cli 1.0.6 → 1.0.8

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,94 @@
1
+ /**
2
+ * Shared CLI command routing logic.
3
+ * Used by both cli.js (production) and cli-dev.js (development).
4
+ */
5
+
6
+ /**
7
+ * Helper function to parse auth options from args.
8
+ */
9
+ export function parseAuthOptions(args) {
10
+ const emailIndex = args.indexOf('--email');
11
+ const passwordIndex = args.indexOf('--password');
12
+ const tokenIndex = args.indexOf('--token');
13
+
14
+ return {
15
+ email: emailIndex !== -1 ? args[emailIndex + 1] : undefined,
16
+ password: passwordIndex !== -1 ? args[passwordIndex + 1] : undefined,
17
+ token: tokenIndex !== -1 ? args[tokenIndex + 1] : undefined,
18
+ };
19
+ }
20
+
21
+ /**
22
+ * Execute a CLI command with the given import prefix.
23
+ *
24
+ * @param {string} command - The command to execute
25
+ * @param {string[]} args - Command arguments
26
+ * @param {string} importPrefix - Path prefix for imports (e.g., '../src/' or '../dist/cli/src/')
27
+ * @returns {Promise<number>} Exit code (0 for success, 1 for error)
28
+ */
29
+ export async function runCommand(command, args, importPrefix) {
30
+ try {
31
+ // Handle login command.
32
+ if (command === 'login') {
33
+ const { login } = await import(`${importPrefix}login/index.js`);
34
+ const authOptions = parseAuthOptions(args);
35
+ await login({ email: authOptions.email, password: authOptions.password });
36
+ return 0;
37
+ }
38
+
39
+ // Handle logout command.
40
+ if (command === 'logout') {
41
+ const { logout } = await import(`${importPrefix}logout/index.js`);
42
+ await logout();
43
+ return 0;
44
+ }
45
+
46
+ // Handle whoami command.
47
+ if (command === 'whoami') {
48
+ const { whoami } = await import(`${importPrefix}whoami/index.js`);
49
+ await whoami();
50
+ return 0;
51
+ }
52
+
53
+ // Handle deploy command.
54
+ if (command === 'deploy') {
55
+ const { deployApp } = await import(`${importPrefix}deploy/index.js`);
56
+ const buildDirIndex = args.indexOf('--build-dir');
57
+ const buildDir =
58
+ buildDirIndex !== -1 ? args[buildDirIndex + 1] : './dist';
59
+ const authOptions = parseAuthOptions(args);
60
+ await deployApp({ buildDir, ...authOptions });
61
+ return 0;
62
+ }
63
+
64
+ // Handle list command.
65
+ if (command === 'list') {
66
+ const { listApps } = await import(`${importPrefix}list/index.js`);
67
+ const authOptions = parseAuthOptions(args);
68
+ await listApps(authOptions);
69
+ return 0;
70
+ }
71
+
72
+ // Handle info command.
73
+ if (command === 'info') {
74
+ const { getAppInfo } = await import(`${importPrefix}info/index.js`);
75
+ const appId = args[1];
76
+
77
+ if (!appId || appId.startsWith('--')) {
78
+ console.error('Error: App ID is required');
79
+ console.error('Usage: juuno-cli info <app-id> [options]');
80
+ return 1;
81
+ }
82
+
83
+ const authOptions = parseAuthOptions(args);
84
+ await getAppInfo({ appId, ...authOptions });
85
+ return 0;
86
+ }
87
+
88
+ // Command not recognized - return error code.
89
+ return 1;
90
+ } catch (error) {
91
+ // Let errors propagate to the caller for proper handling.
92
+ throw error;
93
+ }
94
+ }
package/bin/cli.js CHANGED
@@ -1,17 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { spawn } from 'child_process';
4
3
  import { fileURLToPath } from 'url';
5
4
  import { dirname, join } from 'path';
6
- import {
7
- readFileSync,
8
- writeFileSync,
9
- mkdirSync,
10
- copyFileSync,
11
- readdirSync,
12
- rmSync,
13
- } from 'fs';
14
- import { tmpdir } from 'os';
5
+ import { runCommand } from './cli-router.js';
15
6
 
16
7
  const __filename = fileURLToPath(import.meta.url);
17
8
  const __dirname = dirname(__filename);
@@ -22,19 +13,6 @@ const args = process.argv.slice(2);
22
13
  // Check if first argument is a command.
23
14
  const command = args[0];
24
15
 
25
- // Helper function to parse auth options from args.
26
- function parseAuthOptions(args) {
27
- const emailIndex = args.indexOf('--email');
28
- const passwordIndex = args.indexOf('--password');
29
- const tokenIndex = args.indexOf('--token');
30
-
31
- return {
32
- email: emailIndex !== -1 ? args[emailIndex + 1] : undefined,
33
- password: passwordIndex !== -1 ? args[passwordIndex + 1] : undefined,
34
- token: tokenIndex !== -1 ? args[tokenIndex + 1] : undefined,
35
- };
36
- }
37
-
38
16
  // Handle help command.
39
17
  if (args.includes('--help') || args.includes('-h') || command === 'help') {
40
18
  console.log(`
@@ -108,80 +86,28 @@ Examples:
108
86
  process.exit(0);
109
87
  }
110
88
 
111
- // Handle login command.
112
- if (command === 'login') {
113
- const { login } = await import('../dist/cli/src/login/index.js');
114
-
115
- const authOptions = parseAuthOptions(args);
116
-
117
- await login({ email: authOptions.email, password: authOptions.password });
118
- process.exit(0);
119
- }
120
-
121
- // Handle logout command.
122
- if (command === 'logout') {
123
- const { logout } = await import('../dist/cli/src/logout/index.js');
124
-
125
- await logout();
126
- process.exit(0);
127
- }
128
-
129
- // Handle whoami command.
130
- if (command === 'whoami') {
131
- const { whoami } = await import('../dist/cli/src/whoami/index.js');
132
-
133
- await whoami();
134
- process.exit(0);
135
- }
136
-
137
- // Handle deploy command.
138
- if (command === 'deploy') {
139
- const { deployApp } = await import('../dist/cli/src/deploy/index.js');
140
-
141
- const buildDirIndex = args.indexOf('--build-dir');
142
- const buildDir = buildDirIndex !== -1 ? args[buildDirIndex + 1] : './dist';
143
-
144
- const authOptions = parseAuthOptions(args);
145
-
146
- await deployApp({ buildDir, ...authOptions });
147
- process.exit(0);
148
- }
149
-
150
- // Handle list command.
151
- if (command === 'list') {
152
- const { listApps } = await import('../dist/cli/src/list/index.js');
153
-
154
- const authOptions = parseAuthOptions(args);
155
-
156
- await listApps(authOptions);
157
- process.exit(0);
158
- }
159
-
160
- // Handle info command.
161
- if (command === 'info') {
162
- const { getAppInfo } = await import('../dist/cli/src/info/index.js');
163
-
164
- const appIdx = args[1];
165
-
166
- if (!appIdx || appIdx.startsWith('--')) {
167
- console.error('Error: App ID is required');
168
- console.error('Usage: juuno-cli info <app-id> [options]');
169
- process.exit(1);
170
- }
171
-
172
- const authOptions = parseAuthOptions(args);
173
-
174
- await getAppInfo({ appIdx, ...authOptions });
175
- process.exit(0);
89
+ // Handle commands via shared router (uses built JS imports for production).
90
+ if (
91
+ command === 'login' ||
92
+ command === 'logout' ||
93
+ command === 'whoami' ||
94
+ command === 'deploy' ||
95
+ command === 'list' ||
96
+ command === 'info'
97
+ ) {
98
+ const exitCode = await runCommand(command, args, '../dist/cli/src/');
99
+ process.exit(exitCode);
176
100
  }
177
101
 
178
102
  // Handle simulator command (default behavior).
179
103
  // Remove the command from args if it was 'dev'.
104
+ let simulatorArgs = args;
180
105
  if (command === 'dev') {
181
- args.shift();
106
+ simulatorArgs = args.slice(1);
182
107
  }
183
- const appUrlIndex = args.indexOf('--app');
184
- const portIndex = args.indexOf('--port');
108
+
109
+ const appUrlIndex = simulatorArgs.indexOf('--app');
110
+ const portIndex = simulatorArgs.indexOf('--port');
185
111
 
186
112
  if (appUrlIndex === -1) {
187
113
  console.error('Error: --app parameter is required for simulator');
@@ -190,8 +116,8 @@ if (appUrlIndex === -1) {
190
116
  process.exit(1);
191
117
  }
192
118
 
193
- const appUrl = args[appUrlIndex + 1];
194
- const port = portIndex !== -1 ? args[portIndex + 1] : '5004';
119
+ const appUrl = simulatorArgs[appUrlIndex + 1];
120
+ const port = portIndex !== -1 ? simulatorArgs[portIndex + 1] : '5004';
195
121
 
196
122
  if (!appUrl) {
197
123
  console.error('Error: --app parameter requires a URL value');
@@ -201,143 +127,6 @@ if (!appUrl) {
201
127
  // Path to the built dist directory.
202
128
  const distPath = join(__dirname, '..', 'dist');
203
129
 
204
- // Create a temporary directory for the modified dist.
205
- const tempDir = join(tmpdir(), `juuno-simulator-${Date.now()}`);
206
- mkdirSync(tempDir, { recursive: true });
207
-
208
- // Copy all files from dist to temp directory.
209
- function copyDir(src, dest) {
210
- const entries = readdirSync(src, { withFileTypes: true });
211
-
212
- for (const entry of entries) {
213
- const srcPath = join(src, entry.name);
214
- const destPath = join(dest, entry.name);
215
-
216
- if (entry.isDirectory()) {
217
- mkdirSync(destPath, { recursive: true });
218
- copyDir(srcPath, destPath);
219
- } else {
220
- copyFileSync(srcPath, destPath);
221
- }
222
- }
223
- }
224
-
225
- copyDir(distPath, tempDir);
226
-
227
- // Inject the app URL and import map CDN URLs into index.html.
228
- const indexPath = join(tempDir, 'index.html');
229
- let indexHtml = readFileSync(indexPath, 'utf-8');
230
-
231
- // Fill in the import map with CDN URLs for vue and @juuno-sdk/app-sdk.
232
- indexHtml = indexHtml.replace(
233
- '"vue": ""',
234
- '"vue": "https://cdn.jsdelivr.net/npm/vue@3.5.22/dist/vue.esm-browser.prod.js"',
235
- );
236
- indexHtml = indexHtml.replace(
237
- '"@juuno-sdk/app-sdk": ""',
238
- '"@juuno-sdk/app-sdk": "https://cdn.jsdelivr.net/npm/@juuno-sdk/app-sdk@1.0.2/dist/index.js"',
239
- );
240
-
241
- // Fill in CDN URLs for externalized dependencies from the SDK.
242
- indexHtml = indexHtml.replace(
243
- '"@vueuse/core": ""',
244
- '"@vueuse/core": "https://cdn.jsdelivr.net/npm/@vueuse/core@11.4.1/index.mjs"',
245
- );
246
- indexHtml = indexHtml.replace(
247
- '"@tiptap/vue-3": ""',
248
- '"@tiptap/vue-3": "https://cdn.jsdelivr.net/npm/@tiptap/vue-3@2.10.5/dist/index.js"',
249
- );
250
- indexHtml = indexHtml.replace(
251
- '"@tiptap/starter-kit": ""',
252
- '"@tiptap/starter-kit": "https://cdn.jsdelivr.net/npm/@tiptap/starter-kit@2.10.5/dist/index.js"',
253
- );
254
- indexHtml = indexHtml.replace(
255
- '"@tiptap/extension-underline": ""',
256
- '"@tiptap/extension-underline": "https://cdn.jsdelivr.net/npm/@tiptap/extension-underline@2.10.5/dist/index.js"',
257
- );
258
- indexHtml = indexHtml.replace(
259
- '"lodash-es": ""',
260
- '"lodash-es": "https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.js"',
261
- );
262
- indexHtml = indexHtml.replace(
263
- '"date-fns": ""',
264
- '"date-fns": "https://cdn.jsdelivr.net/npm/date-fns@4.1.0/index.mjs"',
265
- );
266
- indexHtml = indexHtml.replace(
267
- '"url-parse": ""',
268
- '"url-parse": "https://cdn.jsdelivr.net/npm/url-parse@1.5.10/dist/url-parse.min.js"',
269
- );
270
-
271
- // Fill in the import map with external app entrypoints.
272
- indexHtml = indexHtml.replace(
273
- '"external-app/player": ""',
274
- `"external-app/player": "${appUrl}/player/index.js"`,
275
- );
276
- indexHtml = indexHtml.replace(
277
- '"external-app/config": ""',
278
- `"external-app/config": "${appUrl}/config/index.js"`,
279
- );
280
-
281
- // Inject the app URL as a global variable before any scripts load.
282
- const injection = `
283
- <script>
284
- window.__JUUNO_EXTERNAL_APP_URL__ = '${appUrl}';
285
- </script>
286
- `;
287
-
288
- indexHtml = indexHtml.replace('</head>', `${injection}</head>`);
289
- writeFileSync(indexPath, indexHtml);
290
-
291
- console.log(`
292
- 🚀 Juuno App Simulator Starting...
293
-
294
- External App: ${appUrl}
295
- Simulator URL: http://localhost:${port}
296
-
297
- Press Ctrl+C to stop
298
- `);
299
-
300
- // Serve the modified temp directory.
301
- const server = spawn(
302
- 'npx',
303
- ['sirv-cli', tempDir, '--port', port, '--cors', '--single'],
304
- {
305
- stdio: 'inherit',
306
- shell: true,
307
- },
308
- );
309
-
310
- server.on('error', (err) => {
311
- console.error('Failed to start server:', err);
312
- process.exit(1);
313
- });
314
-
315
- server.on('exit', (code) => {
316
- if (code !== 0) {
317
- console.error(`Server exited with code ${code}`);
318
- }
319
- process.exit(code);
320
- });
321
-
322
- // Cleanup function.
323
- function cleanup() {
324
- try {
325
- rmSync(tempDir, { recursive: true, force: true });
326
- } catch (err) {
327
- // Ignore cleanup errors.
328
- }
329
- }
330
-
331
- // Handle termination.
332
- process.on('SIGINT', () => {
333
- console.log('\n\n👋 Stopping simulator...');
334
- server.kill();
335
- cleanup();
336
- process.exit(0);
337
- });
338
-
339
- process.on('SIGTERM', () => {
340
- server.kill();
341
- cleanup();
342
- process.exit(0);
343
- });
130
+ // Launch simulator (imports from built JS).
131
+ const { launchSimulator } = await import('../dist/cli/src/simulator/index.js');
132
+ launchSimulator(appUrl, port, distPath);
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/deploy/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAY7E;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAiFD;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAwFrE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/deploy/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAa7E;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6ED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAyFrE"}
@@ -115,10 +115,11 @@ export async function deployApp(options) {
115
115
  }
116
116
  console.log('✅ Deployment successful!');
117
117
  console.log('');
118
- if (result.app) {
118
+ if (result.data) {
119
119
  console.log('📋 App Details:');
120
- console.log(` Name: ${result.app.name}`);
121
- console.log(` ID: ${result.app.idx}`);
120
+ console.log(` ID: ${result.data.id}`);
121
+ console.log(` Name: ${result.data.name}`);
122
+ console.log(` Version: ${result.data.version}`);
122
123
  console.log('');
123
124
  }
124
125
  if (result.message) {
@@ -3,7 +3,7 @@ import { type AuthOptions } from '../auth/index.js';
3
3
  * Info command options.
4
4
  */
5
5
  export interface InfoOptions extends AuthOptions {
6
- appIdx: string;
6
+ appId: string;
7
7
  }
8
8
  /**
9
9
  * Gets and displays detailed information about a specific app.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/info/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,MAAM,EAAE,MAAM,CAAC;CAChB;AAsHD;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCpE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/info/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,KAAK,EAAE,MAAM,CAAC;CACf;AA0HD;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCpE"}
@@ -2,9 +2,9 @@ import { getAuthToken, getApiUrl } from '../auth/index.js';
2
2
  /**
3
3
  * Fetches detailed information about a specific app.
4
4
  */
5
- async function fetchAppInfo(token, appIdx) {
5
+ async function fetchAppInfo(token, appId) {
6
6
  const apiUrl = getApiUrl();
7
- const infoUrl = `${apiUrl}/api/v1/developer/apps/${appIdx}`;
7
+ const infoUrl = `${apiUrl}/api/v1/developer/apps/${appId}`;
8
8
  try {
9
9
  const response = await fetch(infoUrl, {
10
10
  method: 'GET',
@@ -18,10 +18,10 @@ async function fetchAppInfo(token, appIdx) {
18
18
  throw new Error(`Failed to fetch app info: ${response.status} ${response.statusText}\n${errorText}`);
19
19
  }
20
20
  const data = (await response.json());
21
- if (!data.success || !data.app) {
21
+ if (!data.success || !data.data) {
22
22
  throw new Error(`Failed to fetch app info: ${data.message || 'Unknown error'}`);
23
23
  }
24
- return data.app;
24
+ return data.data;
25
25
  }
26
26
  catch (error) {
27
27
  if (error instanceof Error) {
@@ -54,7 +54,7 @@ function displayAppInfo(app) {
54
54
  console.log('─'.repeat(60));
55
55
  console.log('');
56
56
  console.log(`Name: ${app.name}`);
57
- console.log(`ID: ${app.idx}`);
57
+ console.log(`ID: ${app.id}`);
58
58
  if (app.description) {
59
59
  console.log(`Description: ${app.description}`);
60
60
  }
@@ -80,7 +80,7 @@ function displayAppInfo(app) {
80
80
  export async function getAppInfo(options) {
81
81
  console.log('📦 Juuno CLI - App Info');
82
82
  console.log('');
83
- if (!options.appIdx || options.appIdx.trim().length === 0) {
83
+ if (!options.appId || options.appId.trim().length === 0) {
84
84
  console.error('❌ App ID is required');
85
85
  console.error(' Usage: juuno-cli info <app-id>');
86
86
  process.exit(1);
@@ -96,10 +96,10 @@ export async function getAppInfo(options) {
96
96
  console.error(`❌ ${error instanceof Error ? error.message : String(error)}`);
97
97
  process.exit(1);
98
98
  }
99
- console.log(`📡 Fetching app info for: ${options.appIdx}`);
99
+ console.log(`📡 Fetching app info for: ${options.appId}`);
100
100
  let appInfo;
101
101
  try {
102
- appInfo = await fetchAppInfo(token, options.appIdx);
102
+ appInfo = await fetchAppInfo(token, options.appId);
103
103
  console.log(' ✓ Info retrieved');
104
104
  console.log('');
105
105
  }
@@ -4,6 +4,17 @@ import { type AuthOptions } from '../auth/index.js';
4
4
  */
5
5
  export interface ListOptions extends AuthOptions {
6
6
  }
7
+ /**
8
+ * App summary returned from the list endpoint.
9
+ */
10
+ export interface AppSummary {
11
+ id: string;
12
+ name: string;
13
+ version: string;
14
+ visibility: string;
15
+ role: string;
16
+ last_uploaded_at?: string;
17
+ }
7
18
  /**
8
19
  * Lists all developer apps.
9
20
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/list/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,WAAW;CAAG;AAyGnD;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BlE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/list/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,WAAW;CAAG;AAEnD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAsGD;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BlE"}
@@ -21,7 +21,7 @@ async function fetchAppList(token) {
21
21
  if (!data.success) {
22
22
  throw new Error(`Failed to fetch apps: ${data.message || 'Unknown error'}`);
23
23
  }
24
- return data.apps || [];
24
+ return data.data || [];
25
25
  }
26
26
  catch (error) {
27
27
  if (error instanceof Error) {
@@ -43,20 +43,25 @@ function displayAppList(apps) {
43
43
  }
44
44
  console.log('📱 Your Apps');
45
45
  console.log('');
46
+ const maxIdLength = Math.max(...apps.map((a) => a.id.length), 2);
46
47
  const maxNameLength = Math.max(...apps.map((a) => a.name.length), 4);
47
- const maxTypeLength = Math.max(...apps.map((a) => a.type.length), 4);
48
- const maxIdLength = Math.max(...apps.map((a) => a.idx.length), 2);
48
+ const maxVersionLength = Math.max(...apps.map((a) => a.version.length), 7);
49
49
  const maxRoleLength = Math.max(...apps.map((a) => a.role.length), 4);
50
- const nameCol = maxNameLength + 2;
51
- const typeCol = maxTypeLength + 2;
50
+ const maxLastUploadedAtLength = Math.max(...apps.map((a) => a.last_uploaded_at?.length || 0), 20);
52
51
  const idCol = maxIdLength + 2;
52
+ const nameCol = maxNameLength + 2;
53
+ const versionCol = maxVersionLength + 2;
53
54
  const roleCol = maxRoleLength + 2;
54
- const header = `${'Name'.padEnd(nameCol)}${'Type'.padEnd(typeCol)}${'Role'.padEnd(roleCol)}${'ID'.padEnd(idCol)}`;
55
+ const lastUploadedAtCol = maxLastUploadedAtLength + 2;
56
+ const header = `${'ID'.padEnd(idCol)}${'Name'.padEnd(nameCol)}${'Version'.padEnd(versionCol)}${'Last Uploaded'.padEnd(lastUploadedAtCol)}${'Role'.padEnd(roleCol)}`;
55
57
  const separator = '─'.repeat(header.length);
56
58
  console.log(header);
57
59
  console.log(separator);
58
60
  for (const app of apps) {
59
- const row = `${app.name.padEnd(nameCol)}${app.type.padEnd(typeCol)}${app.role.padEnd(roleCol)}${app.idx.padEnd(idCol)}`;
61
+ const lastUploadedAt = app.last_uploaded_at
62
+ ? new Date(app.last_uploaded_at).toLocaleString()
63
+ : '';
64
+ const row = `${app.id.padEnd(idCol)}${app.name.padEnd(nameCol)}${app.version.padEnd(versionCol)}${lastUploadedAt.padEnd(lastUploadedAtCol)}${app.role.padEnd(roleCol)}`;
60
65
  console.log(row);
61
66
  }
62
67
  console.log('');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Shared simulator logic for launching the app simulator.
3
+ * Used by both cli.js (production) and cli-dev.js (development).
4
+ */
5
+ /**
6
+ * Launch the app simulator.
7
+ *
8
+ * @param appUrl - URL of the external app to load
9
+ * @param port - Port to run the simulator on
10
+ * @param distPath - Path to the built dist directory
11
+ */
12
+ export declare function launchSimulator(appUrl: string, port: string, distPath: string): void;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/simulator/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoCH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,QA8JjB"}