@ebay/muse-runner 1.0.21

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 (55) hide show
  1. package/.muserc +1 -0
  2. package/README.md +8 -0
  3. package/bin/muse-runner.js +19 -0
  4. package/lib/AppRunner.js +54 -0
  5. package/lib/Command.js +55 -0
  6. package/lib/MuseRunner.js +135 -0
  7. package/lib/PluginRunner.js +67 -0
  8. package/lib/apis/checkUpdate.js +25 -0
  9. package/lib/apis/gitStatus.js +89 -0
  10. package/lib/apis/settings.js +9 -0
  11. package/lib/apis/startPlugin.js +22 -0
  12. package/lib/apis/stopPlugin.js +8 -0
  13. package/lib/apis/terminals.js +118 -0
  14. package/lib/appWorker.js +325 -0
  15. package/lib/reactFastRefresh.js +452 -0
  16. package/lib/server.js +463 -0
  17. package/lib/test.js +20 -0
  18. package/lib/upgrades/up_240102.js +25 -0
  19. package/lib/utils.js +79 -0
  20. package/package.json +49 -0
  21. package/public/index.html +14 -0
  22. package/public/muse-assets/p/@ebay.muse-boot-default/v1.0.25/dist/asset-manifest.json +10 -0
  23. package/public/muse-assets/p/@ebay.muse-boot-default/v1.0.25/dist/boot.js +2 -0
  24. package/public/muse-assets/p/@ebay.muse-boot-default/v1.0.25/dist/static/media/logo.0629cb217459ef0a31a2.png +0 -0
  25. package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/assets/index-BeGfgbtf.css +1 -0
  26. package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/assets/muse-V3RbDVED.png +0 -0
  27. package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/deps-manifest.json +19 -0
  28. package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/main.js +16 -0
  29. package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/readme.txt +1 -0
  30. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/asset-manifest.json +12 -0
  31. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/deps-manifest.json +26 -0
  32. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/info.json +3 -0
  33. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/lib-manifest.json +32768 -0
  34. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/main.js +3 -0
  35. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/main.js.LICENSE.txt +30 -0
  36. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/readme.txt +1 -0
  37. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/report.html +39 -0
  38. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/static/js/205.bfaa7a71.chunk.js +2 -0
  39. package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/static/media/lightOn.f95be1d2e4156b9a7459.svg +1 -0
  40. package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/asset-manifest.json +11 -0
  41. package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/favicon.png +0 -0
  42. package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/info.json +3 -0
  43. package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/lib-manifest.json +3821 -0
  44. package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/main.js +3 -0
  45. package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/main.js.LICENSE.txt +136 -0
  46. package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/static/media/logo.b23b880b0dac2229042c.png +0 -0
  47. package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/static/media/subAppLoading2.bf08007b83457287ade1cedb71bc70f7.svg +7 -0
  48. package/public/muse-assets/p/app-icon.muserunner/v0.0.1/dist/icon.png +0 -0
  49. package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/asset-manifest.json +10 -0
  50. package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/deps-manifest.json +43 -0
  51. package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/main.js +3 -0
  52. package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/main.js.LICENSE.txt +43 -0
  53. package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/readme.txt +2 -0
  54. package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/static/media/vscode.e44746dcd601802dfb4fe3374cfab5b0.svg +18 -0
  55. package/public/muse-sw.js +111 -0
package/lib/server.js ADDED
@@ -0,0 +1,463 @@
1
+ import express from 'express';
2
+ import expressWs from 'express-ws';
3
+ import _ from 'lodash';
4
+ import cors from 'cors';
5
+ import fs from 'fs-extra';
6
+ import path from 'path';
7
+ import Conf from 'conf';
8
+ import museCore from '@ebay/muse-core';
9
+ import * as url from 'url';
10
+ import crypto from 'crypto';
11
+ import { exec } from 'node:child_process';
12
+ import fallback from 'express-history-api-fallback';
13
+ import MuseRunner from './MuseRunner.js';
14
+ import openBrowser from 'react-dev-utils/openBrowser.js';
15
+ import terminals from './apis/terminals.js';
16
+ import gitStatus from './apis/gitStatus.js';
17
+ import settings from './apis/settings.js';
18
+ import startPlugin from './apis/startPlugin.js';
19
+ import stopPlugin from './apis/stopPlugin.js';
20
+ import utils, { handleAsyncError } from './utils.js';
21
+
22
+ const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
23
+
24
+ console.log('Starting Muse Runner...');
25
+
26
+ const config = new Conf({
27
+ projectName: process.env.MUSE_RUNNER_CONFIG_NAME || 'muse-runner',
28
+ });
29
+ console.log('Config path: ', config.path);
30
+ const app = express();
31
+ app.use(express.json({ limit: '5MB' }));
32
+ app.use(express.urlencoded({ extended: true }));
33
+ app.use(cors());
34
+ expressWs(app);
35
+
36
+ const port = parseInt(process.env.MUSE_RUNNER_PORT || '6066', 10);
37
+
38
+ function setupWebSocket(app) {
39
+ const sockets = [];
40
+ app.ws('/api/muse-runner-socket', (ws) => {
41
+ ws.on('close', () => _.pull(sockets, ws));
42
+ sockets.push(ws);
43
+ });
44
+
45
+ return {
46
+ emit(msg) {
47
+ sockets.forEach((socket) => {
48
+ try {
49
+ socket.send(JSON.stringify(msg));
50
+ } catch (e) {
51
+ // ignore socket send error
52
+ }
53
+ });
54
+ },
55
+ };
56
+ }
57
+
58
+ const io = setupWebSocket(app);
59
+
60
+ const bound = [];
61
+ const msgCache = {};
62
+ function bindOutputToSocket(id, output) {
63
+ if (bound.includes(output)) return;
64
+ bound.push(output);
65
+ const arr = [];
66
+ const flush = _.throttle(() => {
67
+ if (!msgCache[id]) msgCache[id] = [];
68
+ const msg = {
69
+ type: 'output',
70
+ data: {
71
+ id: id || `muse-runner`,
72
+ output: arr,
73
+ },
74
+ };
75
+ msgCache[id].push(_.cloneDeep(msg));
76
+ if (msgCache[id].length > 100) msgCache[id].shift();
77
+ io.emit(msg);
78
+ arr.length = 0;
79
+ }, 100);
80
+
81
+ const onData = (data) => {
82
+ arr.push(data.toString().replace(/\n/g, '\n\r'));
83
+ flush();
84
+ };
85
+ if (output.onData) {
86
+ output.onData(onData);
87
+ } else {
88
+ output.on('data', onData);
89
+ }
90
+ }
91
+
92
+ config.onDidAnyChange(() => {
93
+ io.emit({
94
+ type: 'config-data-changed',
95
+ data: config.store,
96
+ });
97
+ });
98
+
99
+ const getRunningData = () => {
100
+ return {
101
+ apps: runner.runningApps.map((r) => ({
102
+ app: r.app,
103
+ env: r.env,
104
+ id: r.id,
105
+ port: r.port,
106
+ })),
107
+ plugins: runner.runningPlugins.map((r) => ({
108
+ name: r.pluginInfo.name,
109
+ dir: r.dir,
110
+ port: r.port,
111
+ })),
112
+ };
113
+ };
114
+ const handleRunningDataChange = () => {
115
+ io.emit({
116
+ type: 'running-data-changed',
117
+ data: getRunningData(),
118
+ });
119
+ };
120
+
121
+ const runner = new MuseRunner();
122
+
123
+ runner.on('start-plugin', ({ pluginRunner }) => {
124
+ pluginRunner.on('exit', (code) => {
125
+ handleRunningDataChange();
126
+ io.emit({
127
+ type: 'plugin-exited',
128
+ data: {
129
+ pluginName: pluginRunner.pluginInfo.name,
130
+ dir: pluginRunner.dir,
131
+ code,
132
+ },
133
+ });
134
+ });
135
+ bindOutputToSocket(`plugin:${pluginRunner.dir}`, pluginRunner.cmd.ptyProcess);
136
+ msgCache[`plugin:${pluginRunner.dir}}`] = [];
137
+ handleRunningDataChange();
138
+ });
139
+
140
+ app.post('/api/clear-msg-cache', (req, res) => {
141
+ const { id } = req.body;
142
+ if (id) {
143
+ delete msgCache[id];
144
+ }
145
+ res.end('ok');
146
+ });
147
+ app.post(
148
+ '/api/start-app',
149
+ handleAsyncError(async (req, res) => {
150
+ const { id } = req.body;
151
+ const appList = config.get('appList', []);
152
+ const app = appList.find((a) => a.id === id);
153
+ if (!app) throw new Error(`App not found: ${id}`);
154
+
155
+ const appRunner = await runner.startApp({
156
+ id,
157
+ app: app.app,
158
+ env: app.env,
159
+ port: app.port,
160
+ });
161
+
162
+ appRunner.on('exit', (code) => {
163
+ handleRunningDataChange();
164
+ io.emit({
165
+ type: 'app-exited',
166
+ data: {
167
+ appId: id,
168
+ code,
169
+ },
170
+ });
171
+ });
172
+ handleRunningDataChange();
173
+ appRunner.worker.on('message', (msg) => {
174
+ if (msg.type === 'call-parent-api') {
175
+ switch (msg.payload.key) {
176
+ case 'get-app-config':
177
+ appRunner.worker.postMessage({
178
+ type: 'resolve-promise',
179
+ payload: {
180
+ promiseId: msg.payload.promiseId,
181
+ result: {
182
+ ...utils.getAppConfig({ id, runner, config }),
183
+ port: appRunner.port,
184
+ },
185
+ },
186
+ });
187
+ break;
188
+ default:
189
+ break;
190
+ }
191
+ }
192
+ });
193
+ bindOutputToSocket(`app:${id}`, appRunner.worker.stdout);
194
+ msgCache[`app:${id}`] = [];
195
+ res.setHeader('Content-Type', 'application/json');
196
+ res.end(
197
+ JSON.stringify({
198
+ id,
199
+ app: app.app,
200
+ env: app.env,
201
+ port: appRunner.port,
202
+ }),
203
+ );
204
+ }),
205
+ );
206
+
207
+ app.post(
208
+ '/api/new-app',
209
+ handleAsyncError(async (req, res) => {
210
+ const id = crypto.randomBytes(6).toString('hex');
211
+ const appList = config.get('appList', []);
212
+ const { app, env, ...rest } = req.body;
213
+ appList.push({ id, app, env, ...rest });
214
+ config.set('appList', appList);
215
+ res.setHeader('Content-Type', 'application/json');
216
+ res.end(JSON.stringify({ id, app, env, ...rest }));
217
+ }),
218
+ );
219
+
220
+ app.post(
221
+ '/api/update-app',
222
+ handleAsyncError(async (req, res) => {
223
+ const appList = config.get('appList', []);
224
+ const { id, app, env, ...rest } = req.body;
225
+ const foundApp = appList.find((a) => a.id === id);
226
+ if (!foundApp) throw new Error(`App not found: ${id}`);
227
+ Object.assign(foundApp, { app, env, ...rest });
228
+ config.set('appList', appList);
229
+ res.end('ok');
230
+ }),
231
+ );
232
+
233
+ app.post(
234
+ '/api/remove-app',
235
+ handleAsyncError(async (req, res) => {
236
+ const appList = config.get('appList', []);
237
+ const { id } = req.body;
238
+ _.remove(appList, (a) => a.id === id);
239
+ config.set('appList', appList);
240
+ res.end('ok');
241
+ }),
242
+ );
243
+
244
+ app.post(
245
+ '/api/stop-app',
246
+ handleAsyncError(async (req, res) => {
247
+ const { id } = req.body;
248
+ await runner.stopApp({ id });
249
+ res.end('ok');
250
+ }),
251
+ );
252
+
253
+ app.post('/api/start-plugin', startPlugin({ config, runner }));
254
+ app.post('/api/stop-plugin', stopPlugin({ runner }));
255
+
256
+ app.post(
257
+ '/api/update-plugin',
258
+ handleAsyncError(async (req, res) => {
259
+ const { dir, pluginName, ...rest } = req.body;
260
+ if (dir && !fs.existsSync(dir)) throw new Error(`Folder not exist: ${dir}`);
261
+ const plugins = config.get('plugins', {});
262
+ if (!plugins[pluginName]) plugins[pluginName] = {};
263
+ Object.assign(plugins[pluginName], { dir, ...rest });
264
+ config.set('plugins', plugins);
265
+ res.end('ok');
266
+ }),
267
+ );
268
+
269
+ app.post(
270
+ '/api/attach-plugin',
271
+ handleAsyncError(async (req, res) => {
272
+ const { appId, pluginName, mode = 'local', ...rest } = req.body;
273
+ const appList = config.get('appList', []);
274
+ const app = appList.find((a) => a.id === appId);
275
+ if (!app) throw new Error(`App not found: ${appId}`);
276
+ app.plugins = app.plugins || [];
277
+
278
+ const toSave = {
279
+ name: pluginName,
280
+ mode,
281
+ ...rest,
282
+ };
283
+ const foundIndex = app.plugins.findIndex((p) => p.name === pluginName);
284
+
285
+ if (foundIndex === -1) {
286
+ app.plugins.push(toSave);
287
+ } else {
288
+ app.plugins[foundIndex] = toSave;
289
+ }
290
+
291
+ config.set('appList', appList);
292
+ res.end('ok');
293
+ }),
294
+ );
295
+
296
+ app.post(
297
+ '/api/detach-plugin',
298
+ handleAsyncError(async (req, res) => {
299
+ const { appId, pluginName } = req.body;
300
+ const appList = config.get('appList', []);
301
+ const app = appList.find((a) => a.id === appId);
302
+ if (!app) throw new Error(`App not found: ${appId}`);
303
+ _.remove(app.plugins, (p) => p.name === pluginName);
304
+ config.set('appList', appList);
305
+ res.end('ok');
306
+ }),
307
+ );
308
+
309
+ // app.post(
310
+ // '/api/link-plugin',
311
+ // handleAsyncError(async (req, res) => {
312
+ // const { mainPlugin, linkedPlugin } = req.body;
313
+ // if (mainPlugin === linkedPlugin) throw new Error('Cannot link with self');
314
+ // const plugins = config.get('plugins', {});
315
+ // if (!plugins[mainPlugin]) {
316
+ // plugins[mainPlugin] = {};
317
+ // }
318
+ // if (!plugins[mainPlugin].linkedPlugins) {
319
+ // plugins[mainPlugin].linkedPlugins = [];
320
+ // }
321
+ // if (!_.find(plugins[mainPlugin].linkedPlugins, { name: linkedPlugin })) {
322
+ // plugins[mainPlugin].linkedPlugins.push({ name: linkedPlugin });
323
+ // }
324
+ // config.set('plugins', plugins);
325
+ // res.end('ok');
326
+ // }),
327
+ // );
328
+
329
+ // app.post(
330
+ // '/api/unlink-plugin',
331
+ // handleAsyncError(async (req, res) => {
332
+ // const { mainPlugin, linkedPlugin } = req.body;
333
+ // const plugins = config.get('plugins', {});
334
+
335
+ // if (plugins[mainPlugin]?.linkedPlugins) {
336
+ // _.remove(plugins[mainPlugin]?.linkedPlugins, (p) => p.name === linkedPlugin);
337
+ // }
338
+ // config.set('plugins', plugins);
339
+ // res.end('ok');
340
+ // }),
341
+ // );
342
+
343
+ app.get(
344
+ '/api/muse-data',
345
+ handleAsyncError(async (req, res) => {
346
+ const key = req.query.key;
347
+ const data = await museCore.data.get(key);
348
+ res.setHeader('Content-Type', 'application/json');
349
+ res.end(JSON.stringify(data));
350
+ }),
351
+ );
352
+
353
+ app.get(
354
+ '/api/init-data',
355
+ handleAsyncError(async (req, res) => {
356
+ const [apps, plugins] = await Promise.all([
357
+ museCore.data.get('muse.apps'),
358
+ museCore.data.get('muse.plugins'),
359
+ ]);
360
+
361
+ if (!apps || !plugins) throw new Error('Failed to get Muse apps or plugins.');
362
+
363
+ res.setHeader('Content-Type', 'application/json');
364
+ res.end(
365
+ JSON.stringify({
366
+ msgCache,
367
+ apps,
368
+ plugins,
369
+ https: process.env.HTTPS === 'true',
370
+ museLocalHost: process.env.MUSE_LOCAL_HOST_NAME || 'localhost',
371
+ }),
372
+ );
373
+ }),
374
+ );
375
+
376
+ app.get(
377
+ '/api/config-data',
378
+ handleAsyncError(async (req, res) => {
379
+ res.setHeader('Content-Type', 'application/json');
380
+ res.end(JSON.stringify(config.store));
381
+ }),
382
+ );
383
+
384
+ app.get(
385
+ '/api/running-data',
386
+ handleAsyncError((req, res) => {
387
+ res.setHeader('Content-Type', 'application/json');
388
+ res.end(JSON.stringify(getRunningData()));
389
+ }),
390
+ );
391
+
392
+ app.post(
393
+ '/api/clear-output',
394
+ handleAsyncError((req, res) => {
395
+ const { id } = req.body;
396
+ if (id) {
397
+ msgCache[id] = [];
398
+ }
399
+ res.end('ok');
400
+ }),
401
+ );
402
+
403
+ app.post(
404
+ '/api/open-code',
405
+ handleAsyncError(async (req, res) => {
406
+ const { dir } = req.body;
407
+ if (!fs.existsSync(dir)) throw new Error(`Folder not exist: ${dir}`);
408
+ exec(`code "${dir}"`);
409
+ res.end('ok');
410
+ }),
411
+ );
412
+
413
+ app.post(
414
+ '/api/sort-apps',
415
+ handleAsyncError(async (req, res) => {
416
+ const { appIds } = req.body;
417
+ const appList = config.get('appList', []);
418
+ appList.sort((a, b) => {
419
+ const aIndex = appIds.indexOf(a.id);
420
+ const bIndex = appIds.indexOf(b.id);
421
+ return aIndex - bIndex;
422
+ });
423
+ config.set('appList', appList);
424
+ res.end('ok');
425
+ }),
426
+ );
427
+
428
+ app.post(
429
+ '/api/sort-plugins',
430
+ handleAsyncError(async (req, res) => {
431
+ const { pluginNames, appId } = req.body;
432
+ const appList = config.get('appList', []);
433
+ const app = appList.find((a) => a.id === appId);
434
+ if (!app) throw new Error(`App not found: ${appId}`);
435
+ app.plugins.sort((a, b) => {
436
+ const aIndex = pluginNames.indexOf(a.name);
437
+ const bIndex = pluginNames.indexOf(b.name);
438
+ return aIndex - bIndex;
439
+ });
440
+ config.set('appList', appList);
441
+ res.end('ok');
442
+ }),
443
+ );
444
+
445
+ app.post('/api/open-browser', (req, res) => {
446
+ const { url } = req.body;
447
+ openBrowser(url);
448
+ res.end('ok');
449
+ });
450
+
451
+ terminals({ app, io, config });
452
+ gitStatus({ app, io, config });
453
+ settings({ app, io, config });
454
+
455
+ // Serving runner Muse app
456
+ // public folder is generated by "muse export muserunner staging ./public"
457
+ app.use(express.static('./public'));
458
+ app.use(fallback('index.html', { root: path.join(__dirname, '../public') }));
459
+
460
+ app.listen(port, () => {
461
+ console.log(`Muse Runner started at: http://localhost:${port}`);
462
+ openBrowser(`http://localhost:${port}`);
463
+ });
package/lib/test.js ADDED
@@ -0,0 +1,20 @@
1
+ import * as os from 'node:os';
2
+ import * as pty from 'node-pty';
3
+
4
+ const shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
5
+
6
+ const ptyProcess = pty.spawn(shell, [], {
7
+ name: 'xterm-color',
8
+ cols: 80,
9
+ rows: 30,
10
+ cwd: process.env.HOME,
11
+ env: process.env
12
+ });
13
+
14
+ ptyProcess.onData((data) => {
15
+ process.stdout.write(data);
16
+ });
17
+
18
+ ptyProcess.write('ls\r');
19
+ ptyProcess.resize(100, 40);
20
+ ptyProcess.write('ls\r');
@@ -0,0 +1,25 @@
1
+ // Upgrade in 20240102
2
+ import _ from 'lodash';
3
+ import Conf from 'conf';
4
+ const config = new Conf({
5
+ projectName: process.env.MUSE_RUNNER_CONFIG_NAME || 'muse-runner-ebay',
6
+ });
7
+
8
+ export default function upgrade240102() {
9
+ console.log('Checking config data...');
10
+ // upgrade plugin config data structure
11
+ if (config.get('pluginDir') && !config.get('plugins')) {
12
+ console.log('Updating config data...');
13
+ const pluginDir = config.get('pluginDir');
14
+ const linkedPlugins = config.get('linkedPlugins') || {};
15
+ const plugins = _.mapValues(pluginDir, (value, key) => ({
16
+ dir: value,
17
+ linkedPlugins: linkedPlugins[key] || undefined,
18
+ }));
19
+
20
+ config.set('plugins', plugins);
21
+ config.delete('pluginDir');
22
+ config.delete('linkedPlugins');
23
+ console.log('Config data updated.');
24
+ }
25
+ }
package/lib/utils.js ADDED
@@ -0,0 +1,79 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import _ from 'lodash';
4
+
5
+ // Detect package manager, we only support npm, yarn or pnpm.
6
+ const pkgManagers = {
7
+ npm: 'package-lock.json',
8
+ pnpm: 'pnpm-lock.yaml',
9
+ yarn: 'yarn.lock',
10
+ };
11
+
12
+ const utils = {
13
+ getPluginInfo: (dir) => {
14
+ const pkgJson = fs.readJsonSync(path.join(dir, 'package.json'));
15
+ return {
16
+ name: pkgJson.name,
17
+ pkgJson,
18
+ type: pkgJson.muse?.type || 'normal',
19
+ esModule: pkgJson.type === 'module',
20
+ devConfig: pkgJson.muse?.devConfig,
21
+ };
22
+ },
23
+ getPkgManager: (dir) => {
24
+ const pmStatus = Object.entries(pkgManagers)
25
+ .map(([name, lockFile]) => {
26
+ return fs.existsSync(path.join(dir, lockFile)) ? name : null;
27
+ })
28
+ .filter(Boolean);
29
+
30
+ if (pmStatus.length > 1) {
31
+ throw new Error(
32
+ `Multiple lock files found: ${pmStatus.join(
33
+ ', ',
34
+ )}. There should be one package manager for one project.`,
35
+ );
36
+ }
37
+
38
+ return pmStatus[0] || 'pnpm';
39
+ },
40
+ getAppConfig: ({ config, runner, id }) => {
41
+ const appList = config.get('appList', []);
42
+ const plugins = config.get('plugins', {});
43
+ const runningPlugins = runner.runningPlugins;
44
+ const app = _.find(appList, { id });
45
+ app.plugins?.forEach((p) => {
46
+ const pluginConfig = plugins[p.name] || {};
47
+ p.dir = pluginConfig.dir;
48
+ const found = runningPlugins.find((p2) => p2.pluginInfo.name === p.name);
49
+ if (found) {
50
+ p.running = true;
51
+ p.port = found.port;
52
+ p.type = found.pluginInfo.type;
53
+ p.protocol = pluginConfig.protocol || (process.env.HTTPS === 'true' ? 'https' : 'http');
54
+ p.esModule = found.pluginInfo.esModule;
55
+ }
56
+
57
+ if (pluginConfig.linkedPlugins) {
58
+ p.linkedPlugins = pluginConfig.linkedPlugins.map((lp) => ({
59
+ name: lp.name,
60
+ dir: plugins[lp.name]?.dir,
61
+ }));
62
+ }
63
+ });
64
+ app.protocol = app.protocol || (process.env.HTTPS === 'true' ? 'https' : 'http');
65
+
66
+ return app;
67
+ },
68
+ };
69
+
70
+ export const handleAsyncError = (fn) => async (req, res) => {
71
+ try {
72
+ return await fn(req, res);
73
+ } catch (e) {
74
+ console.error(e);
75
+ res.status(500).send(e.message);
76
+ }
77
+ };
78
+
79
+ export default utils;
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@ebay/muse-runner",
3
+ "version": "1.0.21",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "muse-runner": "./bin/muse-runner.js"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "lib",
13
+ "public",
14
+ ".muserc"
15
+ ],
16
+ "keywords": [],
17
+ "author": "",
18
+ "license": "ISC",
19
+ "dependencies": {
20
+ "chalk": "^5.3.0",
21
+ "chokidar": "^3.5.3",
22
+ "conf": "^11.0.2",
23
+ "cors": "^2.8.5",
24
+ "express": "^4.18.2",
25
+ "express-history-api-fallback": "^2.2.1",
26
+ "express-ws": "^5.0.2",
27
+ "fs-extra": "^11.1.1",
28
+ "get-port": "^7.0.0",
29
+ "js-plugin": "^1.1.0",
30
+ "lodash": "^4.17.21",
31
+ "node-pty": "^1.0.0",
32
+ "package-json": "^8.1.1",
33
+ "react-dev-utils": "^12.0.1",
34
+ "semver": "^7.5.4",
35
+ "simple-git": "^3.20.0",
36
+ "@ebay/muse-dev-utils": "^1.0.72",
37
+ "@ebay/muse-core": "^1.0.44",
38
+ "@ebay/muse-client": "^1.0.27",
39
+ "@ebay/muse-express-middleware": "^1.0.58"
40
+ },
41
+ "devDependencies": {
42
+ "eslint": "^8.47.0"
43
+ },
44
+ "scripts": {
45
+ "start": "node lib/server.js",
46
+ "build": "muse export muserunner staging ./public",
47
+ "test": "echo \"Error: no test specified\" && exit 1"
48
+ }
49
+ }
@@ -0,0 +1,14 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+ <head>
5
+ <title>Muse Runner</title>
6
+ <link rel="shortcut icon" href="/muse-assets/p/app-icon.muserunner/v0.0.1/dist/icon.png" />
7
+ <script>
8
+ window.MUSE_GLOBAL = {"app":{"name":"muserunner","createdBy":"pwang7","createdAt":"2023-08-21T07:14:47.583Z","owners":["pwang7","leizhang"],"pluginConfig":{"@ebay/muse-layout-antd":{"core":true}},"title":"Muse Runner","config":{"entry":"","theme":"dark","noSSO":true},"dedicatedTeam":"35728|DevX Platform","description":"NOTE: this is a Muse app placeholder, only used for export by \"muse export-app\". It's not expected to be accessed by url.","variables":{"aaa":"aaa"},"iconId":1},"env":{"name":"staging","createdBy":"pwang7","createdAt":"2023-08-21T07:15:30.612Z","url":"muserunner.muse.qa.ebay.com","e2eTestMode":"self-only","variables":{"aaa":"aaa"}},"appName":"muserunner","envName":"staging","plugins":[{"name":"@ebay/muse-boot-default","version":"1.0.25","type":"boot","variables":{"var":"test"}},{"name":"@ebay/muse-layout-antd","version":"1.1.26","type":"normal","esModule":true},{"name":"@ebay/muse-lib-antd","version":"1.2.22","type":"lib"},{"name":"@ebay/muse-lib-react","version":"1.2.20","type":"lib"},{"name":"muse-runner-ui","version":"1.0.26","type":"normal","esModule":false}],"isDev":false,"cdn":"/muse-assets","bootPlugin":"@ebay/muse-boot-default","serviceWorker":"/muse-sw.js"};
9
+ </script>
10
+ </head>
11
+ <body></body>
12
+ <script src="/muse-assets/p/@ebay.muse-boot-default/v1.0.25/dist/boot.js"></script>
13
+ </html>
14
+
@@ -0,0 +1,10 @@
1
+ {
2
+ "files": {
3
+ "main.js": "/boot.js",
4
+ "static/media/logo.png": "/static/media/logo.0629cb217459ef0a31a2.png",
5
+ "boot.js.map": "/boot.js.map"
6
+ },
7
+ "entrypoints": [
8
+ "boot.js"
9
+ ]
10
+ }