@juuno-sdk/cli 1.0.8 → 1.0.10

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.
@@ -1,10 +1,9 @@
1
1
  /**
2
- * Shared simulator logic for launching the app simulator.
2
+ * Simulator logic for launching the app simulator.
3
3
  * Used by both cli.js (production) and cli-dev.js (development).
4
4
  */
5
5
  import { spawn } from 'child_process';
6
- import { fileURLToPath } from 'url';
7
- import { dirname, join } from 'path';
6
+ import { join } from 'path';
8
7
  import { readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, rmSync, existsSync, statSync, } from 'fs';
9
8
  import { tmpdir } from 'os';
10
9
  /**
@@ -25,13 +24,37 @@ function copyDir(src, dest) {
25
24
  }
26
25
  }
27
26
  /**
28
- * Launch the app simulator.
29
- *
30
- * @param appUrl - URL of the external app to load
31
- * @param port - Port to run the simulator on
32
- * @param distPath - Path to the built dist directory
27
+ * Launch the app simulator with optional live reload.
33
28
  */
34
29
  export function launchSimulator(appUrl, port, distPath) {
30
+ return launchSimulatorWithOptions({ appUrl, port, distPath });
31
+ }
32
+ /**
33
+ * Fetch the app manifest to get actual resource paths.
34
+ */
35
+ async function fetchManifest(appUrl) {
36
+ try {
37
+ const response = await fetch(`${appUrl}/manifest.json`);
38
+ if (!response.ok) {
39
+ return null;
40
+ }
41
+ return await response.json();
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ /**
48
+ * Launch the app simulator with full options object.
49
+ */
50
+ export async function launchSimulatorWithOptions(options) {
51
+ const { appUrl, port, distPath } = options;
52
+ // Fetch manifest to get actual resource paths.
53
+ const manifest = await fetchManifest(appUrl);
54
+ const playerJs = manifest?.resources?.player?.find((p) => p.endsWith('.js'));
55
+ const configJs = manifest?.resources?.config?.find((p) => p.endsWith('.js'));
56
+ const playerPath = playerJs || '/player.js';
57
+ const configPath = configJs || '/config.js';
35
58
  // Validate that dist directory exists before attempting to copy.
36
59
  if (!existsSync(distPath)) {
37
60
  console.error(`Error: Build directory does not exist: ${distPath}`);
@@ -78,29 +101,31 @@ export function launchSimulator(appUrl, port, distPath) {
78
101
  indexHtml = indexHtml.replace('"lodash-es": ""', '"lodash-es": "https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.js"');
79
102
  indexHtml = indexHtml.replace('"date-fns": ""', '"date-fns": "https://cdn.jsdelivr.net/npm/date-fns@4.1.0/index.mjs"');
80
103
  indexHtml = indexHtml.replace('"url-parse": ""', '"url-parse": "https://cdn.jsdelivr.net/npm/url-parse@1.5.10/dist/url-parse.min.js"');
81
- // Fill in the import map with external app entrypoints.
82
- indexHtml = indexHtml.replace('"external-app/player": ""', `"external-app/player": "${appUrl}/player/index.js"`);
83
- indexHtml = indexHtml.replace('"external-app/config": ""', `"external-app/config": "${appUrl}/config/index.js"`);
84
- // Inject the app URL as a global variable before any scripts load.
85
- const injection = `
104
+ // Fill in the import map with external app entrypoints (from manifest or defaults).
105
+ indexHtml = indexHtml.replace('"external-app/player": ""', `"external-app/player": "${appUrl}${playerPath}"`);
106
+ indexHtml = indexHtml.replace('"external-app/config": ""', `"external-app/config": "${appUrl}${configPath}"`);
107
+ // Inject the app URL as a global variable.
108
+ // Use JSON.stringify for safe injection into JavaScript.
109
+ const appUrlScript = `
86
110
  <script>
87
- window.__JUUNO_EXTERNAL_APP_URL__ = '${appUrl}';
111
+ window.__JUUNO_EXTERNAL_APP_URL__ = ${JSON.stringify(appUrl)};
88
112
  </script>
89
113
  `;
90
- indexHtml = indexHtml.replace('</head>', `${injection}</head>`);
114
+ indexHtml = indexHtml.replace('</head>', `${appUrlScript}</head>`);
91
115
  writeFileSync(indexPath, indexHtml);
92
116
  console.log(`
93
- 🚀 Juuno App Simulator Starting...
117
+ 🚀 Juuno App Simulator
94
118
 
95
- External App: ${appUrl}
96
- Simulator URL: http://localhost:${port}
119
+ External App: ${appUrl}
120
+ Simulator: http://localhost:${port}
97
121
 
98
122
  Press Ctrl+C to stop
99
123
  `);
100
124
  // Serve the modified temp directory.
101
- const server = spawn('npx', ['sirv-cli', tempDir, '--port', port, '--cors', '--single'], {
125
+ // Use npx serve with --single for SPA routing.
126
+ const server = spawn('npx', ['-y', 'serve', tempDir, '-l', port, '--cors', '--single'], {
102
127
  stdio: 'inherit',
103
- shell: true,
128
+ shell: false,
104
129
  });
105
130
  server.on('error', (err) => {
106
131
  console.error('Failed to start server:', err);
@@ -114,10 +139,11 @@ export function launchSimulator(appUrl, port, distPath) {
114
139
  });
115
140
  // Cleanup function.
116
141
  function cleanup() {
142
+ // Remove temp directory.
117
143
  try {
118
144
  rmSync(tempDir, { recursive: true, force: true });
119
145
  }
120
- catch (err) {
146
+ catch {
121
147
  // Ignore cleanup errors.
122
148
  }
123
149
  }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * File system utilities for the Juuno CLI.
3
+ */
4
+ /**
5
+ * Find a file by walking up the directory tree.
6
+ *
7
+ * @param startDir - The directory to start searching from.
8
+ * @param filename - The name of the file to find.
9
+ * @returns The full path to the file if found, or null if not found.
10
+ */
11
+ export declare function findFileUpward(startDir: string, filename: string): string | null;
12
+ //# sourceMappingURL=fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../../src/utils/fs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAkBf"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * File system utilities for the Juuno CLI.
3
+ */
4
+ import { existsSync } from 'fs';
5
+ import { join, resolve } from 'path';
6
+ /**
7
+ * Find a file by walking up the directory tree.
8
+ *
9
+ * @param startDir - The directory to start searching from.
10
+ * @param filename - The name of the file to find.
11
+ * @returns The full path to the file if found, or null if not found.
12
+ */
13
+ export function findFileUpward(startDir, filename) {
14
+ let dir = startDir;
15
+ const root = '/';
16
+ while (dir !== root) {
17
+ const filePath = join(dir, filename);
18
+ if (existsSync(filePath)) {
19
+ return filePath;
20
+ }
21
+ const parent = resolve(dir, '..');
22
+ // Prevent infinite loop if we can't go up further.
23
+ if (parent === dir) {
24
+ break;
25
+ }
26
+ dir = parent;
27
+ }
28
+ return null;
29
+ }