@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.
- package/.muserc +1 -0
- package/README.md +8 -0
- package/bin/muse-runner.js +19 -0
- package/lib/AppRunner.js +54 -0
- package/lib/Command.js +55 -0
- package/lib/MuseRunner.js +135 -0
- package/lib/PluginRunner.js +67 -0
- package/lib/apis/checkUpdate.js +25 -0
- package/lib/apis/gitStatus.js +89 -0
- package/lib/apis/settings.js +9 -0
- package/lib/apis/startPlugin.js +22 -0
- package/lib/apis/stopPlugin.js +8 -0
- package/lib/apis/terminals.js +118 -0
- package/lib/appWorker.js +325 -0
- package/lib/reactFastRefresh.js +452 -0
- package/lib/server.js +463 -0
- package/lib/test.js +20 -0
- package/lib/upgrades/up_240102.js +25 -0
- package/lib/utils.js +79 -0
- package/package.json +49 -0
- package/public/index.html +14 -0
- package/public/muse-assets/p/@ebay.muse-boot-default/v1.0.25/dist/asset-manifest.json +10 -0
- package/public/muse-assets/p/@ebay.muse-boot-default/v1.0.25/dist/boot.js +2 -0
- package/public/muse-assets/p/@ebay.muse-boot-default/v1.0.25/dist/static/media/logo.0629cb217459ef0a31a2.png +0 -0
- package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/assets/index-BeGfgbtf.css +1 -0
- package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/assets/muse-V3RbDVED.png +0 -0
- package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/deps-manifest.json +19 -0
- package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/main.js +16 -0
- package/public/muse-assets/p/@ebay.muse-layout-antd/v1.1.26/dist/readme.txt +1 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/asset-manifest.json +12 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/deps-manifest.json +26 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/info.json +3 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/lib-manifest.json +32768 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/main.js +3 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/main.js.LICENSE.txt +30 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/readme.txt +1 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/report.html +39 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/static/js/205.bfaa7a71.chunk.js +2 -0
- package/public/muse-assets/p/@ebay.muse-lib-antd/v1.2.22/dist/static/media/lightOn.f95be1d2e4156b9a7459.svg +1 -0
- package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/asset-manifest.json +11 -0
- package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/favicon.png +0 -0
- package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/info.json +3 -0
- package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/lib-manifest.json +3821 -0
- package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/main.js +3 -0
- package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/main.js.LICENSE.txt +136 -0
- package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/static/media/logo.b23b880b0dac2229042c.png +0 -0
- package/public/muse-assets/p/@ebay.muse-lib-react/v1.2.20/dist/static/media/subAppLoading2.bf08007b83457287ade1cedb71bc70f7.svg +7 -0
- package/public/muse-assets/p/app-icon.muserunner/v0.0.1/dist/icon.png +0 -0
- package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/asset-manifest.json +10 -0
- package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/deps-manifest.json +43 -0
- package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/main.js +3 -0
- package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/main.js.LICENSE.txt +43 -0
- package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/readme.txt +2 -0
- package/public/muse-assets/p/muse-runner-ui/v1.0.26/dist/static/media/vscode.e44746dcd601802dfb4fe3374cfab5b0.svg +18 -0
- package/public/muse-sw.js +111 -0
package/lib/appWorker.js
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This worker simulates the Muse app server, it manages the plugins and serves the app.
|
|
3
|
+
*
|
|
4
|
+
* - It listens to the parent process for the app config and plugin config change
|
|
5
|
+
* - Running plugins are served plugin runners
|
|
6
|
+
* - If a running plugin is a lib plugin, use URL to load the plugin
|
|
7
|
+
* - Override app and plugin variables from config
|
|
8
|
+
* - If a lib plugin is running at local mode, it has highest priority to load
|
|
9
|
+
*/
|
|
10
|
+
import { workerData, parentPort } from 'node:worker_threads';
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import express from 'express';
|
|
13
|
+
import muse from '@ebay/muse-core';
|
|
14
|
+
import _ from 'lodash';
|
|
15
|
+
import cors from 'cors';
|
|
16
|
+
import https from 'node:https';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
import crypto from 'crypto';
|
|
19
|
+
import museDevUtils from '@ebay/muse-dev-utils/lib/utils.js';
|
|
20
|
+
import * as url from 'url';
|
|
21
|
+
import museAssetsMiddleware from '@ebay/muse-express-middleware/lib/assets.js';
|
|
22
|
+
import museAppMiddleware from '@ebay/muse-express-middleware/lib/app.js';
|
|
23
|
+
|
|
24
|
+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
25
|
+
const host = process.env.MUSE_LOCAL_HOST_NAME || 'localhost';
|
|
26
|
+
|
|
27
|
+
const { port } = workerData;
|
|
28
|
+
const promiseResolvers = {};
|
|
29
|
+
parentPort.on('message', (msg) => {
|
|
30
|
+
if (msg.type === 'resolve-promise') {
|
|
31
|
+
const resolve = promiseResolvers[msg.payload.promiseId];
|
|
32
|
+
if (resolve) {
|
|
33
|
+
resolve(msg.payload.result);
|
|
34
|
+
delete promiseResolvers[msg.payload.promiseId];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const callParentApi = (key) => {
|
|
40
|
+
const promiseId = crypto.randomBytes(12).toString('hex');
|
|
41
|
+
const promise = new Promise((resolve) => {
|
|
42
|
+
promiseResolvers[promiseId] = resolve;
|
|
43
|
+
parentPort.postMessage({
|
|
44
|
+
type: 'call-parent-api',
|
|
45
|
+
payload: {
|
|
46
|
+
promiseId,
|
|
47
|
+
key,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return promise;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
muse.plugin.register({
|
|
56
|
+
name: 'muse-runner',
|
|
57
|
+
museMiddleware: {
|
|
58
|
+
app: {
|
|
59
|
+
processIndexHtml: async (ctx) => {
|
|
60
|
+
// This is to support vite-react
|
|
61
|
+
// This may need to be implemented as a plugin
|
|
62
|
+
const appConfig = await callParentApi('get-app-config');
|
|
63
|
+
const viteProtocolAndPorts = appConfig.plugins
|
|
64
|
+
?.filter((p) => p.esModule && p.running)
|
|
65
|
+
.map((p) => [p.port, p.protocol])
|
|
66
|
+
.filter(Boolean);
|
|
67
|
+
if (!viteProtocolAndPorts || !viteProtocolAndPorts.length) return;
|
|
68
|
+
const importMap = { imports: {} };
|
|
69
|
+
viteProtocolAndPorts.forEach(([vitePort, protocol]) => {
|
|
70
|
+
importMap.imports[`${protocol}://${host}:${vitePort}/@react-refresh`] = `/@react-refresh`;
|
|
71
|
+
});
|
|
72
|
+
ctx.indexHtml = ctx.indexHtml.replace(
|
|
73
|
+
'<head>',
|
|
74
|
+
`<head>
|
|
75
|
+
|
|
76
|
+
<script type="importmap">
|
|
77
|
+
${JSON.stringify(importMap, null, 2)}
|
|
78
|
+
</script>
|
|
79
|
+
<script type="module">
|
|
80
|
+
import RefreshRuntime from "/@react-refresh"
|
|
81
|
+
RefreshRuntime.injectIntoGlobalHook(window)
|
|
82
|
+
window.$RefreshReg$ = () => {}
|
|
83
|
+
window.$RefreshSig$ = () => (type) => type
|
|
84
|
+
window.__vite_plugin_react_preamble_installed__ = true
|
|
85
|
+
</script>`,
|
|
86
|
+
);
|
|
87
|
+
},
|
|
88
|
+
getAppInfo: async () => {
|
|
89
|
+
// NOTE: appConfig always changes, so need to get it every time
|
|
90
|
+
const appConfig = await callParentApi('get-app-config');
|
|
91
|
+
return { appName: appConfig.app, envName: appConfig.env };
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
// Use this ext point to process the app info, and set the env variables
|
|
95
|
+
processAppInfo: async ({ app, env }) => {
|
|
96
|
+
// Get the app config in muse runner from parent process
|
|
97
|
+
// NOTE: appConfig always changes, so need to get it every time
|
|
98
|
+
// This gets all data about the app, including the plugins, variables, envs, etc.
|
|
99
|
+
const appConfig = await callParentApi('get-app-config');
|
|
100
|
+
|
|
101
|
+
// All deployed plugins on the app
|
|
102
|
+
const deployedPluginByName = _.keyBy(env.plugins, 'name');
|
|
103
|
+
|
|
104
|
+
if (!env.variables) env.variables = {};
|
|
105
|
+
if (!env.pluginVariables) env.pluginVariables = {};
|
|
106
|
+
|
|
107
|
+
// Override dev time app variables
|
|
108
|
+
Object.assign(env.variables, appConfig.variables || {});
|
|
109
|
+
|
|
110
|
+
// Override dev time plugin variables
|
|
111
|
+
Object.entries(appConfig.pluginVariables || {}).forEach(([pluginName, variables]) => {
|
|
112
|
+
if (!env.pluginVariables[pluginName]) env.pluginVariables[pluginName] = {};
|
|
113
|
+
Object.assign(env.pluginVariables[pluginName], variables);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// const linkedPlugins = [];
|
|
117
|
+
|
|
118
|
+
// For local installed lib plugins, need to load them from local dev server of the parent
|
|
119
|
+
// plugin because they may have not been deployed.
|
|
120
|
+
// Here use localLibs to store the local lib plugins' urls
|
|
121
|
+
const localLibPluings = {};
|
|
122
|
+
|
|
123
|
+
// Determine how to load the plugins
|
|
124
|
+
appConfig?.plugins?.forEach((p) => {
|
|
125
|
+
// NOTE: if a plugin uses deployed mode but not found, just return
|
|
126
|
+
if (p.mode === 'deployed') return;
|
|
127
|
+
let deployedPlugin = deployedPluginByName[p.name];
|
|
128
|
+
|
|
129
|
+
// If the configured plugin is not deployed, then add it
|
|
130
|
+
// If a plugin is local but not deployed and not running, it's not added
|
|
131
|
+
// The url will be set later
|
|
132
|
+
if (!deployedPlugin && (p.mode !== 'local' || p.running)) {
|
|
133
|
+
deployedPlugin = {
|
|
134
|
+
name: p.name,
|
|
135
|
+
type: p.type,
|
|
136
|
+
};
|
|
137
|
+
deployedPluginByName[p.name] = deployedPlugin;
|
|
138
|
+
env.plugins.push(deployedPlugin);
|
|
139
|
+
}
|
|
140
|
+
// set a flag to avoid being removed
|
|
141
|
+
|
|
142
|
+
switch (p.mode) {
|
|
143
|
+
case 'excluded':
|
|
144
|
+
_.remove(env.plugins, (p2) => p2.name === p.name);
|
|
145
|
+
break;
|
|
146
|
+
case 'version':
|
|
147
|
+
deployedPlugin.version = p.version;
|
|
148
|
+
break;
|
|
149
|
+
case 'url':
|
|
150
|
+
deployedPlugin.url = p.url;
|
|
151
|
+
deployedPlugin.esModule = !!p.urlEsModule;
|
|
152
|
+
break;
|
|
153
|
+
case 'local': {
|
|
154
|
+
if (p.running) {
|
|
155
|
+
const pluginProtocol = p.protocol || 'https';
|
|
156
|
+
if (p.esModule) {
|
|
157
|
+
const entryFile = museDevUtils.getEntryFile(p.dir);
|
|
158
|
+
deployedPlugin.url = `${pluginProtocol}://${host}:${p.port}/${entryFile}`;
|
|
159
|
+
deployedPlugin.esModule = true;
|
|
160
|
+
} else {
|
|
161
|
+
deployedPlugin.url = `${pluginProtocol}://${host}:${p.port}/${
|
|
162
|
+
p.type === 'boot' ? 'boot' : 'main'
|
|
163
|
+
}.js`;
|
|
164
|
+
}
|
|
165
|
+
// isLocal is used to show log in muse-boot
|
|
166
|
+
deployedPlugin.isLocal = true;
|
|
167
|
+
// linkedPlugins.push(
|
|
168
|
+
// ...(p.linkedPlugins || []).map((lp) => ({
|
|
169
|
+
// name: lp.name,
|
|
170
|
+
// parent: p.name,
|
|
171
|
+
// })),
|
|
172
|
+
// );
|
|
173
|
+
|
|
174
|
+
// Get all installed libs, and add them to localLibPluings
|
|
175
|
+
const museLibs = museDevUtils.getMuseLibsByFolder(p.dir);
|
|
176
|
+
// p.linkedPlugins?.forEach((lp) => {
|
|
177
|
+
// museDevUtils.getMuseLibsByFolder(lp.dir).forEach((lib) => {
|
|
178
|
+
// museLibs.push(lib);
|
|
179
|
+
// });
|
|
180
|
+
// });
|
|
181
|
+
|
|
182
|
+
// Serve lib plugins from the first running plugin
|
|
183
|
+
// We don't handle lib plugin version conflicts here because
|
|
184
|
+
// all local running plugins on the app should have the same version of a lib plugin
|
|
185
|
+
// There should be auto update logic to ensure all plugins have the same version of a lib plugin
|
|
186
|
+
// We don't serve lib plugins from remote because maybe a lib plugin has not been deployed yet.
|
|
187
|
+
_.uniqBy(museLibs, 'name').forEach((lib) => {
|
|
188
|
+
if (localLibPluings[lib.name]) return;
|
|
189
|
+
const pid = muse.utils.getPluginId(lib.name);
|
|
190
|
+
localLibPluings[lib.name] = {
|
|
191
|
+
url: `${pluginProtocol}://${host}:${p.port}/muse-assets/local/p/${pid}/dev/main.js`,
|
|
192
|
+
version: lib.version,
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case 'deployed':
|
|
199
|
+
// already return
|
|
200
|
+
break;
|
|
201
|
+
default:
|
|
202
|
+
// some error happened?
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// linkedPlugins.forEach((lp) => {
|
|
208
|
+
// const name = `${lp.name} (linked to ${lp.parent})})`;
|
|
209
|
+
// if (deployedPluginByName[lp.name]) {
|
|
210
|
+
// deployedPluginByName[lp.name].linkedTo = lp.parent;
|
|
211
|
+
// } else {
|
|
212
|
+
// env.plugins.push({
|
|
213
|
+
// name: name,
|
|
214
|
+
// linkedTo: lp.parent,
|
|
215
|
+
// type: lp.type,
|
|
216
|
+
// });
|
|
217
|
+
// }
|
|
218
|
+
// });
|
|
219
|
+
|
|
220
|
+
const configPluginByName = _.keyBy(appConfig.plugins, 'name');
|
|
221
|
+
if (!appConfig.loadAllPlugins) {
|
|
222
|
+
// NOTE: exluded plugins already removed
|
|
223
|
+
env.plugins = env.plugins.filter(
|
|
224
|
+
// boot/init/lib plugins are always loaded for an app
|
|
225
|
+
(p) =>
|
|
226
|
+
app?.pluginConfig?.[p.name]?.core || // if configured as core plugins, always load
|
|
227
|
+
p.type === 'boot' ||
|
|
228
|
+
p.type === 'init' ||
|
|
229
|
+
p.type === 'lib' ||
|
|
230
|
+
configPluginByName[p.name], //|| // NOTE: excluded plugins already removed
|
|
231
|
+
// p.linkedTo, // if a plugin is linked, need to get config, so we need to load it
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// For local installed lib plugins, need to serve them from local dev server if the mode is local or undefined
|
|
236
|
+
const pluginMode = _.mapValues(configPluginByName, 'mode');
|
|
237
|
+
env.plugins.forEach((p) => {
|
|
238
|
+
// For a lib plugin, if installed locally, then serve it from local
|
|
239
|
+
// dev server unless the mode is 'version' or 'deployed' or 'url'
|
|
240
|
+
|
|
241
|
+
// If it's local and running, the url is already set
|
|
242
|
+
if (p.url || p.type !== 'lib' || !localLibPluings[p.name]) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const mode = pluginMode[p.name];
|
|
247
|
+
if (!mode || mode === 'local') {
|
|
248
|
+
p.url = localLibPluings[p.name].url;
|
|
249
|
+
p.deployedVersion = p.version;
|
|
250
|
+
p.version = localLibPluings[p.name].version;
|
|
251
|
+
p.isLocalLib = true;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// For new local installed lib plugins
|
|
256
|
+
_.keys(localLibPluings).forEach((name) => {
|
|
257
|
+
// If lib plugin not deployed and not excluded, add it
|
|
258
|
+
if (_.find(env.plugins, { name }) || pluginMode[name] === 'excluded') return;
|
|
259
|
+
env.plugins.push({
|
|
260
|
+
name: name,
|
|
261
|
+
type: 'lib',
|
|
262
|
+
url: localLibPluings[name].url,
|
|
263
|
+
version: localLibPluings[name].version,
|
|
264
|
+
isLocalLib: true,
|
|
265
|
+
notDeployed: true,
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// If a lib plugin is linked to some other running (local mode) plugin,
|
|
270
|
+
// Then don't load it from anywhere else
|
|
271
|
+
// env.plugins.forEach((p) => {
|
|
272
|
+
// // if (p.linkedTo && !p.running) delete p.url;
|
|
273
|
+
// // TODO: may not need this logic since link mechanism will be changed
|
|
274
|
+
// });
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const app = express();
|
|
281
|
+
app.use(cors());
|
|
282
|
+
|
|
283
|
+
// TODO: vite/client seems useless but just for no error
|
|
284
|
+
app.use('/@react-refresh', express.static(path.join(__dirname, 'reactFastRefresh.js')));
|
|
285
|
+
|
|
286
|
+
app.use(museAssetsMiddleware({}));
|
|
287
|
+
|
|
288
|
+
app.use(
|
|
289
|
+
museAppMiddleware({
|
|
290
|
+
isDev: true,
|
|
291
|
+
isLocal: true,
|
|
292
|
+
cdn: '/muse-assets',
|
|
293
|
+
}),
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const appConfig = await callParentApi('get-app-config');
|
|
297
|
+
const isHttps = appConfig.protocol !== 'http';
|
|
298
|
+
|
|
299
|
+
if (
|
|
300
|
+
isHttps &&
|
|
301
|
+
(!process.env.SSL_CRT_FILE ||
|
|
302
|
+
!process.env.SSL_KEY_FILE ||
|
|
303
|
+
!fs.existsSync(process.env.SSL_KEY_FILE) ||
|
|
304
|
+
!fs.existsSync(process.env.SSL_CRT_FILE))
|
|
305
|
+
) {
|
|
306
|
+
console.log('Failed to start app: SSL_KEY_FILE and SSL_CRT_FILE are required for https');
|
|
307
|
+
process.exit(1);
|
|
308
|
+
} else if (isHttps) {
|
|
309
|
+
https
|
|
310
|
+
.createServer(
|
|
311
|
+
{
|
|
312
|
+
key: fs.readFileSync(process.env.SSL_KEY_FILE),
|
|
313
|
+
cert: fs.readFileSync(process.env.SSL_CRT_FILE),
|
|
314
|
+
},
|
|
315
|
+
app,
|
|
316
|
+
)
|
|
317
|
+
.listen(port);
|
|
318
|
+
|
|
319
|
+
console.log(`Muse app started: https://${host}:${port}`);
|
|
320
|
+
} else {
|
|
321
|
+
app.listen(port, () => {
|
|
322
|
+
const host = process.env.MUSE_LOCAL_HOST_NAME || 'localhost';
|
|
323
|
+
console.log(`Muse app started: http://${host}:${port}`);
|
|
324
|
+
});
|
|
325
|
+
}
|