everything-dev 1.7.2 → 1.8.1
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/dist/api.cjs +1 -1
- package/dist/api.mjs +1 -1
- package/dist/app.cjs +82 -51
- package/dist/app.cjs.map +1 -1
- package/dist/app.mjs +82 -51
- package/dist/app.mjs.map +1 -1
- package/dist/cli/upgrade.cjs.map +1 -1
- package/dist/cli/upgrade.mjs.map +1 -1
- package/dist/components/dev-view.cjs +6 -3
- package/dist/components/dev-view.cjs.map +1 -1
- package/dist/components/dev-view.mjs +6 -3
- package/dist/components/dev-view.mjs.map +1 -1
- package/dist/components/streaming-view.cjs +5 -2
- package/dist/components/streaming-view.cjs.map +1 -1
- package/dist/components/streaming-view.mjs +5 -2
- package/dist/components/streaming-view.mjs.map +1 -1
- package/dist/config.cjs +28 -5
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +28 -5
- package/dist/config.mjs.map +1 -1
- package/dist/contract.cjs +1 -0
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +10 -2
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +10 -2
- package/dist/contract.d.mts.map +1 -1
- package/dist/contract.mjs +1 -0
- package/dist/contract.mjs.map +1 -1
- package/dist/dev-logs.cjs +6 -2
- package/dist/dev-logs.cjs.map +1 -1
- package/dist/dev-logs.mjs +7 -2
- package/dist/dev-logs.mjs.map +1 -1
- package/dist/dev-session.cjs +27 -23
- package/dist/dev-session.cjs.map +1 -1
- package/dist/dev-session.mjs +27 -24
- package/dist/dev-session.mjs.map +1 -1
- package/dist/federation.server.cjs +1 -1
- package/dist/federation.server.mjs +1 -1
- package/dist/host.cjs +4 -3
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts.map +1 -1
- package/dist/host.d.mts.map +1 -1
- package/dist/host.mjs +4 -3
- package/dist/host.mjs.map +1 -1
- package/dist/integrity.cjs +68 -2
- package/dist/integrity.cjs.map +1 -1
- package/dist/integrity.d.cts +14 -1
- package/dist/integrity.d.cts.map +1 -1
- package/dist/integrity.d.mts +14 -1
- package/dist/integrity.d.mts.map +1 -1
- package/dist/integrity.mjs +66 -3
- package/dist/integrity.mjs.map +1 -1
- package/dist/mf.cjs +32 -0
- package/dist/mf.cjs.map +1 -1
- package/dist/mf.d.cts +3 -1
- package/dist/mf.d.cts.map +1 -1
- package/dist/mf.d.mts +3 -1
- package/dist/mf.d.mts.map +1 -1
- package/dist/mf.mjs +32 -1
- package/dist/mf.mjs.map +1 -1
- package/dist/orchestrator.cjs +167 -317
- package/dist/orchestrator.cjs.map +1 -1
- package/dist/orchestrator.d.cts +24 -21
- package/dist/orchestrator.d.cts.map +1 -1
- package/dist/orchestrator.d.mts +24 -21
- package/dist/orchestrator.d.mts.map +1 -1
- package/dist/orchestrator.mjs +168 -316
- package/dist/orchestrator.mjs.map +1 -1
- package/dist/plugin.cjs +38 -107
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +16 -2
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +16 -2
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +39 -108
- package/dist/plugin.mjs.map +1 -1
- package/dist/service-descriptor.cjs +188 -0
- package/dist/service-descriptor.cjs.map +1 -0
- package/dist/service-descriptor.d.cts +107 -0
- package/dist/service-descriptor.d.cts.map +1 -0
- package/dist/service-descriptor.d.mts +107 -0
- package/dist/service-descriptor.d.mts.map +1 -0
- package/dist/service-descriptor.mjs +182 -0
- package/dist/service-descriptor.mjs.map +1 -0
- package/dist/types.cjs +8 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +16 -1
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +16 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +8 -1
- package/dist/types.mjs.map +1 -1
- package/dist/ui/index.cjs +1 -0
- package/dist/ui/index.d.cts +2 -2
- package/dist/ui/index.d.mts +2 -2
- package/dist/ui/index.mjs +2 -2
- package/dist/ui/runtime.cjs +4 -0
- package/dist/ui/runtime.cjs.map +1 -1
- package/dist/ui/runtime.d.cts +2 -1
- package/dist/ui/runtime.d.cts.map +1 -1
- package/dist/ui/runtime.d.mts +2 -1
- package/dist/ui/runtime.d.mts.map +1 -1
- package/dist/ui/runtime.mjs +4 -1
- package/dist/ui/runtime.mjs.map +1 -1
- package/package.json +12 -4
- package/skills/dev-workflow/SKILL.md +105 -0
- package/skills/publish-sync/SKILL.md +130 -0
- package/src/app.ts +98 -204
- package/src/cli/upgrade.ts +20 -4
- package/src/components/dev-view.tsx +8 -3
- package/src/components/streaming-view.ts +7 -2
- package/src/config.ts +40 -8
- package/src/contract.ts +1 -0
- package/src/dev-logs.ts +8 -1
- package/src/dev-session.ts +56 -79
- package/src/host.ts +4 -3
- package/src/integrity.ts +96 -10
- package/src/mf.ts +42 -0
- package/src/orchestrator.ts +232 -411
- package/src/plugin.ts +48 -136
- package/src/service-descriptor.ts +258 -0
- package/src/types.ts +8 -1
- package/src/ui/runtime.ts +5 -0
- package/dist/process-registry.cjs +0 -120
- package/dist/process-registry.cjs.map +0 -1
- package/dist/process-registry.d.cts +0 -25
- package/dist/process-registry.d.cts.map +0 -1
- package/dist/process-registry.d.mts +0 -25
- package/dist/process-registry.d.mts.map +0 -1
- package/dist/process-registry.mjs +0 -119
- package/dist/process-registry.mjs.map +0 -1
- package/src/process-registry.ts +0 -154
package/dist/api.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
require('./sdk.cjs');
|
|
4
|
-
const require_mf = require('./mf.cjs');
|
|
5
4
|
const require_integrity = require('./integrity.cjs');
|
|
5
|
+
const require_mf = require('./mf.cjs');
|
|
6
6
|
let every_plugin = require("every-plugin");
|
|
7
7
|
|
|
8
8
|
//#region src/api.ts
|
package/dist/api.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createPluginRuntime } from "./sdk.mjs";
|
|
2
|
-
import { ensureNodeRuntimePlugin, registerRemote } from "./mf.mjs";
|
|
3
2
|
import { verifySriForUrl } from "./integrity.mjs";
|
|
3
|
+
import { ensureNodeRuntimePlugin, registerRemote } from "./mf.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/api.ts
|
|
6
6
|
async function loadApiPlugin(opts) {
|
package/dist/app.cjs
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
2
2
|
const require_network = require('./network.cjs');
|
|
3
3
|
const require_config = require('./config.cjs');
|
|
4
|
-
require('./orchestrator.cjs');
|
|
5
4
|
let node_fs = require("node:fs");
|
|
6
5
|
let node_path = require("node:path");
|
|
7
|
-
let effect = require("effect");
|
|
8
6
|
let node_net = require("node:net");
|
|
9
7
|
|
|
10
8
|
//#region src/app.ts
|
|
11
9
|
const DEFAULT_HOST_PORT = 3e3;
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const DEFAULT_PLUGIN_PORT_START =
|
|
10
|
+
const DEFAULT_API_PORT = 3001;
|
|
11
|
+
const DEFAULT_AUTH_PORT = 3002;
|
|
12
|
+
const DEFAULT_UI_PORT = 3003;
|
|
13
|
+
const DEFAULT_PLUGIN_PORT_START = 3010;
|
|
16
14
|
function detectLocalPackages(bosConfig, runtimeConfig) {
|
|
17
15
|
const packages = [];
|
|
18
16
|
const configDir = require_config.getProjectRoot();
|
|
@@ -20,7 +18,7 @@ function detectLocalPackages(bosConfig, runtimeConfig) {
|
|
|
20
18
|
if (uiLocalPath && (0, node_fs.existsSync)((0, node_path.join)(uiLocalPath, "package.json"))) packages.push("ui");
|
|
21
19
|
const apiLocalPath = runtimeConfig?.api.localPath ?? require_config.resolveLocalDevelopmentPath(bosConfig?.app.api.development, configDir);
|
|
22
20
|
if (apiLocalPath && (0, node_fs.existsSync)((0, node_path.join)(apiLocalPath, "package.json"))) packages.push("api");
|
|
23
|
-
const hostLocalPath = require_config.resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);
|
|
21
|
+
const hostLocalPath = runtimeConfig?.host?.localPath ?? require_config.resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);
|
|
24
22
|
if (hostLocalPath && (0, node_fs.existsSync)((0, node_path.join)(hostLocalPath, "package.json"))) packages.push("host");
|
|
25
23
|
else if ((0, node_fs.existsSync)((0, node_path.join)(configDir, "host", "package.json"))) packages.push("host");
|
|
26
24
|
for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig?.plugins ?? {})) if (pluginConfig.localPath && (0, node_fs.existsSync)((0, node_path.join)(pluginConfig.localPath, "package.json"))) packages.push(`plugin:${pluginId}`);
|
|
@@ -30,69 +28,98 @@ function detectLocalPackages(bosConfig, runtimeConfig) {
|
|
|
30
28
|
}
|
|
31
29
|
function buildRuntimeConfig(bosConfig, options) {
|
|
32
30
|
const configDir = require_config.getProjectRoot();
|
|
31
|
+
const hostConfig = bosConfig.app.host;
|
|
33
32
|
const uiConfig = bosConfig.app.ui;
|
|
34
33
|
const apiConfig = bosConfig.app.api;
|
|
35
34
|
const authConfig = bosConfig.app.auth;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
function resolveDevelopmentEntry(entry, preferredSource) {
|
|
36
|
+
if (preferredSource === "remote") return {
|
|
37
|
+
source: "remote",
|
|
38
|
+
url: entry.production ?? ""
|
|
39
|
+
};
|
|
40
|
+
const localPath = require_config.resolveLocalDevelopmentPath(entry.development, configDir);
|
|
41
|
+
if (localPath && (0, node_fs.existsSync)(localPath)) return {
|
|
42
|
+
source: "local",
|
|
43
|
+
url: "",
|
|
44
|
+
localPath
|
|
45
|
+
};
|
|
46
|
+
const devUrl = entry.development && !require_config.isLocalDevelopmentTarget(entry.development) ? entry.development.replace(/\/$/, "") : null;
|
|
47
|
+
if (devUrl) return {
|
|
48
|
+
source: "local",
|
|
49
|
+
url: devUrl,
|
|
50
|
+
port: require_config.parsePort(devUrl)
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
source: "remote",
|
|
54
|
+
url: entry.production ?? ""
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const hostEntry = resolveDevelopmentEntry(hostConfig, options.hostSource ?? "local");
|
|
58
|
+
const uiEntry = resolveDevelopmentEntry(uiConfig, options.uiSource ?? "local");
|
|
59
|
+
const apiEntry = resolveDevelopmentEntry(apiConfig, options.apiSource ?? "local");
|
|
60
|
+
const authEntry = authConfig ? resolveDevelopmentEntry(authConfig, options.authSource ?? "local") : void 0;
|
|
61
|
+
const hostUrl = `http://localhost:${DEFAULT_HOST_PORT}`;
|
|
45
62
|
return {
|
|
46
63
|
env: options.env ?? "development",
|
|
47
64
|
account: bosConfig.account,
|
|
48
65
|
domain: bosConfig.domain,
|
|
49
66
|
networkId: require_network.getNetworkIdForAccount(bosConfig.account),
|
|
50
|
-
|
|
67
|
+
host: {
|
|
68
|
+
name: "host",
|
|
69
|
+
url: hostUrl,
|
|
70
|
+
entry: `${hostUrl}/mf-manifest.json`,
|
|
71
|
+
localPath: hostEntry.localPath,
|
|
72
|
+
port: hostEntry.port ?? DEFAULT_HOST_PORT,
|
|
73
|
+
secrets: hostConfig.secrets,
|
|
74
|
+
integrity: hostEntry.source === "remote" ? hostConfig.integrity : void 0,
|
|
75
|
+
source: hostEntry.source,
|
|
76
|
+
remoteUrl: hostEntry.source === "remote" ? hostEntry.url : void 0
|
|
77
|
+
},
|
|
51
78
|
shared: bosConfig.shared,
|
|
52
79
|
ui: uiConfig ? {
|
|
53
80
|
name: uiConfig.name,
|
|
54
|
-
url:
|
|
55
|
-
entry:
|
|
56
|
-
localPath:
|
|
57
|
-
port:
|
|
58
|
-
ssrUrl:
|
|
59
|
-
ssrIntegrity:
|
|
60
|
-
integrity:
|
|
61
|
-
source:
|
|
81
|
+
url: uiEntry.url,
|
|
82
|
+
entry: uiEntry.url ? `${uiEntry.url}/mf-manifest.json` : "/mf-manifest.json",
|
|
83
|
+
localPath: uiEntry.localPath,
|
|
84
|
+
port: uiEntry.port,
|
|
85
|
+
ssrUrl: uiEntry.source === "remote" ? uiConfig.ssr : void 0,
|
|
86
|
+
ssrIntegrity: uiEntry.source === "remote" ? uiConfig.ssrIntegrity : void 0,
|
|
87
|
+
integrity: uiEntry.source === "remote" ? uiConfig.integrity : void 0,
|
|
88
|
+
source: uiEntry.source
|
|
62
89
|
} : {
|
|
63
90
|
name: "ui",
|
|
64
91
|
url: "",
|
|
65
92
|
entry: "/mf-manifest.json",
|
|
66
|
-
source:
|
|
93
|
+
source: uiEntry.source
|
|
67
94
|
},
|
|
68
95
|
api: apiConfig ? {
|
|
69
96
|
name: apiConfig.name,
|
|
70
|
-
url:
|
|
71
|
-
entry:
|
|
72
|
-
localPath:
|
|
73
|
-
port:
|
|
74
|
-
source:
|
|
97
|
+
url: apiEntry.url,
|
|
98
|
+
entry: apiEntry.url ? `${apiEntry.url}/mf-manifest.json` : "/mf-manifest.json",
|
|
99
|
+
localPath: apiEntry.localPath,
|
|
100
|
+
port: apiEntry.port,
|
|
101
|
+
source: apiEntry.source,
|
|
75
102
|
proxy: options.proxy ?? apiConfig.proxy,
|
|
76
103
|
variables: apiConfig.variables,
|
|
77
104
|
secrets: apiConfig.secrets,
|
|
78
|
-
integrity:
|
|
105
|
+
integrity: apiEntry.source === "remote" ? apiConfig.integrity : void 0
|
|
79
106
|
} : {
|
|
80
107
|
name: "api",
|
|
81
108
|
url: "",
|
|
82
109
|
entry: "/mf-manifest.json",
|
|
83
|
-
source:
|
|
110
|
+
source: apiEntry.source
|
|
84
111
|
},
|
|
85
|
-
auth: authConfig ? {
|
|
86
|
-
name: require_config.resolvePluginRuntimeName(void 0,
|
|
87
|
-
url:
|
|
88
|
-
entry:
|
|
89
|
-
localPath:
|
|
90
|
-
port:
|
|
91
|
-
source:
|
|
112
|
+
auth: authEntry && authConfig ? {
|
|
113
|
+
name: require_config.resolvePluginRuntimeName(void 0, authEntry.localPath, authConfig.name),
|
|
114
|
+
url: authEntry.url,
|
|
115
|
+
entry: authEntry.url ? `${authEntry.url}/mf-manifest.json` : "/mf-manifest.json",
|
|
116
|
+
localPath: authEntry.localPath,
|
|
117
|
+
port: authEntry.port,
|
|
118
|
+
source: authEntry.source,
|
|
92
119
|
proxy: authConfig.proxy,
|
|
93
120
|
variables: authConfig.variables,
|
|
94
121
|
secrets: authConfig.secrets,
|
|
95
|
-
integrity:
|
|
122
|
+
integrity: authEntry.source === "remote" ? authConfig.integrity : void 0
|
|
96
123
|
} : void 0,
|
|
97
124
|
plugins: options.plugins
|
|
98
125
|
};
|
|
@@ -135,15 +162,27 @@ function withLocalRuntimeUrl(entry, port) {
|
|
|
135
162
|
}
|
|
136
163
|
async function prepareDevelopmentRuntimeConfig(runtimeConfig, options) {
|
|
137
164
|
const usedPorts = /* @__PURE__ */ new Set();
|
|
138
|
-
const hostPort = await pickAvailablePort(options?.hostPort ??
|
|
165
|
+
const hostPort = await pickAvailablePort(options?.hostPort ?? DEFAULT_HOST_PORT, usedPorts);
|
|
139
166
|
const next = {
|
|
140
167
|
...runtimeConfig,
|
|
141
|
-
|
|
168
|
+
host: {
|
|
169
|
+
...runtimeConfig.host,
|
|
170
|
+
url: `http://localhost:${hostPort}`,
|
|
171
|
+
port: hostPort
|
|
172
|
+
},
|
|
142
173
|
ui: { ...runtimeConfig.ui },
|
|
143
174
|
api: { ...runtimeConfig.api },
|
|
144
175
|
auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : void 0,
|
|
145
176
|
plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : void 0
|
|
146
177
|
};
|
|
178
|
+
if (next.api.source === "local" && next.api.localPath) {
|
|
179
|
+
const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);
|
|
180
|
+
next.api = withLocalRuntimeUrl(next.api, apiPort);
|
|
181
|
+
}
|
|
182
|
+
if (next.auth?.source === "local" && next.auth.localPath) {
|
|
183
|
+
const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);
|
|
184
|
+
next.auth = withLocalRuntimeUrl(next.auth, authPort);
|
|
185
|
+
}
|
|
147
186
|
if (next.ui.source === "local" && next.ui.localPath) {
|
|
148
187
|
const uiPort = await pickAvailablePort(next.ui.port ?? DEFAULT_UI_PORT, usedPorts);
|
|
149
188
|
next.ui = withLocalRuntimeUrl(next.ui, uiPort);
|
|
@@ -152,10 +191,6 @@ async function prepareDevelopmentRuntimeConfig(runtimeConfig, options) {
|
|
|
152
191
|
next.ui.ssrUrl = `http://localhost:${ssrPort}`;
|
|
153
192
|
} else next.ui.ssrUrl = void 0;
|
|
154
193
|
}
|
|
155
|
-
if (next.api.source === "local" && next.api.localPath) {
|
|
156
|
-
const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);
|
|
157
|
-
next.api = withLocalRuntimeUrl(next.api, apiPort);
|
|
158
|
-
}
|
|
159
194
|
if (next.plugins) {
|
|
160
195
|
const entries = Object.entries(next.plugins).sort(([a], [b]) => a.localeCompare(b));
|
|
161
196
|
let pluginBasePort = DEFAULT_PLUGIN_PORT_START;
|
|
@@ -166,10 +201,6 @@ async function prepareDevelopmentRuntimeConfig(runtimeConfig, options) {
|
|
|
166
201
|
pluginBasePort = pluginPort + 1;
|
|
167
202
|
}
|
|
168
203
|
}
|
|
169
|
-
if (next.auth?.source === "local" && next.auth.localPath) {
|
|
170
|
-
const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);
|
|
171
|
-
next.auth = withLocalRuntimeUrl(next.auth, authPort);
|
|
172
|
-
}
|
|
173
204
|
return next;
|
|
174
205
|
}
|
|
175
206
|
|
package/dist/app.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.cjs","names":["getProjectRoot","resolveLocalDevelopmentPath","isLocalDevelopmentTarget","getNetworkIdForAccount","parsePort","resolvePluginRuntimeName"],"sources":["../src/app.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { createConnection } from \"node:net\";\nimport { join } from \"node:path\";\nimport { Effect } from \"effect\";\nimport {\n getProjectRoot,\n isLocalDevelopmentTarget,\n parsePort,\n resolveLocalDevelopmentPath,\n resolvePluginRuntimeName,\n} from \"./config\";\nimport { getNetworkIdForAccount } from \"./network\";\nimport { makeDevProcess, type ProcessCallbacks, type ProcessHandle } from \"./orchestrator\";\nimport type { ProcessRegistry } from \"./process-registry\";\nimport type { BosConfig, RuntimeConfig, RuntimePluginConfig } from \"./types\";\n\nexport interface AppOrchestrator {\n packages: string[];\n env: Record<string, string>;\n description: string;\n bosConfig: BosConfig;\n runtimeConfig: RuntimeConfig;\n port?: number;\n interactive?: boolean;\n}\n\nconst STARTUP_ORDER = [\"ui-ssr\", \"ui\", \"auth\", \"api\", \"plugin\", \"host-build\", \"host\"];\nconst DEFAULT_HOST_PORT = 3000;\nconst DEFAULT_UI_PORT = 3002;\nconst DEFAULT_API_PORT = 3014;\nconst DEFAULT_AUTH_PORT = 3020;\nconst DEFAULT_PLUGIN_PORT_START = 3021;\n\nconst sortByOrder = (packages: string[]): string[] => {\n return [...packages].sort((a, b) => {\n const aIdx = a.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(a);\n const bIdx = b.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return 0;\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n};\n\n// Note: log filtering and persistence lives at the CLI layer.\n\nexport interface DevServersHandle {\n handles: ProcessHandle[];\n shutdown: Effect.Effect<void>;\n}\n\nexport const startDevServers = (\n orchestrator: AppOrchestrator,\n callbacks: ProcessCallbacks,\n registry?: ProcessRegistry,\n) => {\n const run = Effect.gen(function* () {\n const orderedPackages = sortByOrder(orchestrator.packages);\n const handles: ProcessHandle[] = [];\n\n const startProcess = (pkg: string) => {\n const portOverride = pkg === \"host\" ? orchestrator.port : undefined;\n return makeDevProcess(\n pkg,\n orchestrator.env,\n callbacks,\n portOverride,\n orchestrator.bosConfig,\n orchestrator.runtimeConfig,\n registry,\n );\n };\n\n const startGroup = (packages: string[]) =>\n Effect.forEach(packages, startProcess, { concurrency: \"unbounded\" });\n\n const awaitReady = (pkg: string, handle: ProcessHandle) =>\n Effect.race(\n handle.waitForReady,\n Effect.sleep(\"30 seconds\").pipe(\n Effect.andThen(\n Effect.sync(() => {\n callbacks.onLog(pkg, \"Timeout waiting for ready, continuing...\", true);\n }),\n ),\n ),\n );\n\n const nonHostPackages = orderedPackages.filter((pkg) => pkg !== \"host\");\n const hostPackages = orderedPackages.filter((pkg) => pkg === \"host\");\n\n const nonHostHandles = yield* startGroup(nonHostPackages);\n handles.push(...nonHostHandles);\n\n yield* Effect.forEach(\n nonHostHandles.map((handle, index) => ({\n handle,\n pkg: nonHostPackages[index] ?? handle.name,\n })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const hostHandles = yield* startGroup(hostPackages);\n handles.push(...hostHandles);\n\n yield* Effect.forEach(\n hostHandles.map((handle, index) => ({ handle, pkg: hostPackages[index] ?? handle.name })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const shutdown = Effect.gen(function* () {\n const reversed = [...handles].reverse();\n for (const handle of reversed) {\n yield* handle.kill.pipe(Effect.ignore);\n }\n });\n\n return { handles, shutdown } satisfies DevServersHandle;\n });\n\n return run;\n};\n\nexport function detectLocalPackages(\n bosConfig?: BosConfig,\n runtimeConfig?: RuntimeConfig,\n): string[] {\n const packages: string[] = [];\n const configDir = getProjectRoot();\n\n const uiLocalPath =\n runtimeConfig?.ui.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.ui.development, configDir);\n if (uiLocalPath && existsSync(join(uiLocalPath, \"package.json\"))) {\n packages.push(\"ui\");\n }\n\n const apiLocalPath =\n runtimeConfig?.api.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.api.development, configDir);\n if (apiLocalPath && existsSync(join(apiLocalPath, \"package.json\"))) {\n packages.push(\"api\");\n }\n\n const hostLocalPath = resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);\n if (hostLocalPath && existsSync(join(hostLocalPath, \"package.json\"))) {\n packages.push(\"host\");\n } else if (existsSync(join(configDir, \"host\", \"package.json\"))) {\n packages.push(\"host\");\n }\n\n for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig?.plugins ?? {})) {\n if (pluginConfig.localPath && existsSync(join(pluginConfig.localPath, \"package.json\"))) {\n packages.push(`plugin:${pluginId}`);\n }\n }\n\n const authLocalPath =\n runtimeConfig?.auth?.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.auth?.development, configDir);\n if (authLocalPath && existsSync(join(authLocalPath, \"package.json\"))) {\n packages.push(\"auth\");\n }\n\n return packages;\n}\n\nexport function buildRuntimeConfig(\n bosConfig: BosConfig,\n options: {\n uiSource?: \"local\" | \"remote\";\n apiSource?: \"local\" | \"remote\";\n authSource?: \"local\" | \"remote\";\n hostUrl: string;\n proxy?: string;\n env?: \"development\" | \"production\";\n plugins?: Record<string, RuntimePluginConfig>;\n },\n): RuntimeConfig {\n const configDir = getProjectRoot();\n const uiConfig = bosConfig.app.ui;\n const apiConfig = bosConfig.app.api;\n const authConfig = bosConfig.app.auth;\n const uiSource = options.uiSource ?? \"local\";\n const apiSource = options.apiSource ?? \"local\";\n const authSource = options.authSource ?? \"local\";\n const uiLocalPath = resolveLocalDevelopmentPath(uiConfig.development, configDir);\n const apiLocalPath = resolveLocalDevelopmentPath(apiConfig.development, configDir);\n const authLocalPath = authConfig\n ? resolveLocalDevelopmentPath(authConfig.development, configDir)\n : null;\n const uiLocalUrl =\n !uiLocalPath && uiConfig.development && !isLocalDevelopmentTarget(uiConfig.development)\n ? uiConfig.development\n : \"\";\n const apiLocalUrl =\n !apiLocalPath && apiConfig.development && !isLocalDevelopmentTarget(apiConfig.development)\n ? apiConfig.development\n : \"\";\n const authLocalUrl =\n authConfig &&\n !authLocalPath &&\n authConfig.development &&\n !isLocalDevelopmentTarget(authConfig.development)\n ? authConfig.development\n : \"\";\n\n return {\n env: options.env ?? \"development\",\n account: bosConfig.account,\n domain: bosConfig.domain,\n networkId: getNetworkIdForAccount(bosConfig.account),\n hostUrl: options.hostUrl,\n shared: bosConfig.shared,\n ui: uiConfig\n ? {\n name: uiConfig.name,\n url: uiSource === \"remote\" ? (uiConfig.production ?? \"\") : uiLocalUrl,\n entry:\n uiSource === \"remote\"\n ? `${uiConfig.production ?? \"\"}/mf-manifest.json`\n : uiLocalUrl\n ? `${uiLocalUrl}/mf-manifest.json`\n : \"/mf-manifest.json\",\n localPath: uiSource === \"local\" ? (uiLocalPath ?? undefined) : undefined,\n port: uiSource === \"local\" && uiLocalUrl ? parsePort(uiLocalUrl) : undefined,\n ssrUrl: uiSource === \"remote\" ? uiConfig.ssr : undefined,\n ssrIntegrity: uiSource === \"remote\" ? uiConfig.ssrIntegrity : undefined,\n integrity: uiSource === \"remote\" ? uiConfig.integrity : undefined,\n source: uiSource === \"local\" ? (uiLocalPath ? \"local\" : \"remote\") : \"remote\",\n }\n : {\n name: \"ui\",\n url: \"\",\n entry: \"/mf-manifest.json\",\n source: uiSource,\n },\n api: apiConfig\n ? {\n name: apiConfig.name,\n url: apiSource === \"remote\" ? (apiConfig.production ?? \"\") : apiLocalUrl,\n entry:\n apiSource === \"remote\"\n ? `${apiConfig.production ?? \"\"}/mf-manifest.json`\n : apiLocalUrl\n ? `${apiLocalUrl}/mf-manifest.json`\n : \"/mf-manifest.json\",\n localPath: apiSource === \"local\" ? (apiLocalPath ?? undefined) : undefined,\n port: apiSource === \"local\" && apiLocalUrl ? parsePort(apiLocalUrl) : undefined,\n source: apiSource === \"local\" ? (apiLocalPath ? \"local\" : \"remote\") : \"remote\",\n proxy: options.proxy ?? apiConfig.proxy,\n variables: apiConfig.variables,\n secrets: apiConfig.secrets,\n integrity: apiSource === \"remote\" ? apiConfig.integrity : undefined,\n }\n : {\n name: \"api\",\n url: \"\",\n entry: \"/mf-manifest.json\",\n source: apiSource,\n },\n auth: authConfig\n ? {\n name: resolvePluginRuntimeName(\n undefined,\n authSource === \"local\" ? (authLocalPath ?? undefined) : undefined,\n authConfig.name,\n ),\n url: authSource === \"remote\" ? (authConfig.production ?? \"\") : authLocalUrl,\n entry:\n authSource === \"remote\"\n ? `${authConfig.production ?? \"\"}/mf-manifest.json`\n : authLocalUrl\n ? `${authLocalUrl}/mf-manifest.json`\n : \"/mf-manifest.json\",\n localPath: authSource === \"local\" ? (authLocalPath ?? undefined) : undefined,\n port: authSource === \"local\" && authLocalUrl ? parsePort(authLocalUrl) : undefined,\n source: authSource === \"local\" ? (authLocalPath ? \"local\" : \"remote\") : \"remote\",\n proxy: authConfig.proxy,\n variables: authConfig.variables,\n secrets: authConfig.secrets,\n integrity: authSource === \"remote\" ? authConfig.integrity : undefined,\n }\n : undefined,\n plugins: options.plugins,\n };\n}\n\nfunction probeTcpOpen(port: number, timeoutMs = 250): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = createConnection({ host: \"127.0.0.1\", port });\n const timer = setTimeout(() => {\n socket.destroy();\n resolve(false);\n }, timeoutMs);\n\n socket.once(\"connect\", () => {\n clearTimeout(timer);\n socket.destroy();\n resolve(true);\n });\n\n socket.once(\"error\", () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n}\n\nasync function pickAvailablePort(preferred: number, usedPorts: Set<number>): Promise<number> {\n let port = preferred;\n while (usedPorts.has(port) || (await probeTcpOpen(port))) {\n port += 1;\n }\n usedPorts.add(port);\n return port;\n}\n\nfunction withLocalRuntimeUrl<\n T extends { url: string; entry: string; port?: number; localPath?: string },\n>(entry: T, port: number): T {\n const url = `http://localhost:${port}`;\n return {\n ...entry,\n url,\n entry: `${url}/mf-manifest.json`,\n port,\n };\n}\n\nexport async function prepareDevelopmentRuntimeConfig(\n runtimeConfig: RuntimeConfig,\n options?: { hostPort?: number; ssr?: boolean },\n): Promise<RuntimeConfig> {\n const usedPorts = new Set<number>();\n const hostPort = await pickAvailablePort(\n options?.hostPort ??\n (runtimeConfig.hostUrl ? parsePort(runtimeConfig.hostUrl) : DEFAULT_HOST_PORT),\n usedPorts,\n );\n\n const next: RuntimeConfig = {\n ...runtimeConfig,\n hostUrl: `http://localhost:${hostPort}`,\n ui: { ...runtimeConfig.ui },\n api: { ...runtimeConfig.api },\n auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : undefined,\n plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : undefined,\n };\n\n if (next.ui.source === \"local\" && next.ui.localPath) {\n const uiPort = await pickAvailablePort(next.ui.port ?? DEFAULT_UI_PORT, usedPorts);\n next.ui = withLocalRuntimeUrl(next.ui, uiPort);\n if (options?.ssr) {\n const ssrPort = await pickAvailablePort(uiPort + 1, usedPorts);\n next.ui.ssrUrl = `http://localhost:${ssrPort}`;\n } else {\n next.ui.ssrUrl = undefined;\n }\n }\n\n if (next.api.source === \"local\" && next.api.localPath) {\n const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);\n next.api = withLocalRuntimeUrl(next.api, apiPort);\n }\n\n if (next.plugins) {\n const entries = Object.entries(next.plugins).sort(([a], [b]) => a.localeCompare(b));\n let pluginBasePort = DEFAULT_PLUGIN_PORT_START;\n\n for (const [pluginId, plugin] of entries) {\n if (plugin.source !== \"local\" || !plugin.localPath) {\n continue;\n }\n\n const pluginPort = await pickAvailablePort(plugin.port ?? pluginBasePort, usedPorts);\n next.plugins[pluginId] = withLocalRuntimeUrl(plugin, pluginPort);\n pluginBasePort = pluginPort + 1;\n }\n }\n\n if (next.auth?.source === \"local\" && next.auth.localPath) {\n const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);\n next.auth = withLocalRuntimeUrl(next.auth, authPort);\n }\n\n return next;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app.cjs","names":["getProjectRoot","resolveLocalDevelopmentPath","isLocalDevelopmentTarget","parsePort","getNetworkIdForAccount","resolvePluginRuntimeName"],"sources":["../src/app.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { createConnection } from \"node:net\";\nimport { join } from \"node:path\";\nimport {\n getProjectRoot,\n isLocalDevelopmentTarget,\n parsePort,\n resolveLocalDevelopmentPath,\n resolvePluginRuntimeName,\n} from \"./config\";\nimport { getNetworkIdForAccount } from \"./network\";\nimport type { AppOrchestrator } from \"./service-descriptor\";\nimport type { BosConfig, RuntimeConfig, RuntimePluginConfig } from \"./types\";\n\nexport type { AppOrchestrator };\n\nconst DEFAULT_HOST_PORT = 3000;\nconst DEFAULT_API_PORT = 3001;\nconst DEFAULT_AUTH_PORT = 3002;\nconst DEFAULT_UI_PORT = 3003;\nconst DEFAULT_PLUGIN_PORT_START = 3010;\n\nexport function detectLocalPackages(\n bosConfig?: BosConfig,\n runtimeConfig?: RuntimeConfig,\n): string[] {\n const packages: string[] = [];\n const configDir = getProjectRoot();\n\n const uiLocalPath =\n runtimeConfig?.ui.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.ui.development, configDir);\n if (uiLocalPath && existsSync(join(uiLocalPath, \"package.json\"))) {\n packages.push(\"ui\");\n }\n\n const apiLocalPath =\n runtimeConfig?.api.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.api.development, configDir);\n if (apiLocalPath && existsSync(join(apiLocalPath, \"package.json\"))) {\n packages.push(\"api\");\n }\n\n const hostLocalPath =\n runtimeConfig?.host?.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);\n if (hostLocalPath && existsSync(join(hostLocalPath, \"package.json\"))) {\n packages.push(\"host\");\n } else if (existsSync(join(configDir, \"host\", \"package.json\"))) {\n packages.push(\"host\");\n }\n\n for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig?.plugins ?? {})) {\n if (pluginConfig.localPath && existsSync(join(pluginConfig.localPath, \"package.json\"))) {\n packages.push(`plugin:${pluginId}`);\n }\n }\n\n const authLocalPath =\n runtimeConfig?.auth?.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.auth?.development, configDir);\n if (authLocalPath && existsSync(join(authLocalPath, \"package.json\"))) {\n packages.push(\"auth\");\n }\n\n return packages;\n}\n\nexport function buildRuntimeConfig(\n bosConfig: BosConfig,\n options: {\n hostSource?: \"local\" | \"remote\";\n uiSource?: \"local\" | \"remote\";\n apiSource?: \"local\" | \"remote\";\n authSource?: \"local\" | \"remote\";\n proxy?: string;\n env?: \"development\" | \"production\";\n plugins?: Record<string, RuntimePluginConfig>;\n },\n): RuntimeConfig {\n const configDir = getProjectRoot();\n const hostConfig = bosConfig.app.host;\n const uiConfig = bosConfig.app.ui;\n const apiConfig = bosConfig.app.api;\n const authConfig = bosConfig.app.auth;\n\n function resolveDevelopmentEntry(\n entry: { development?: string; production?: string },\n preferredSource: \"local\" | \"remote\",\n ): { source: \"local\" | \"remote\"; url: string; localPath?: string; port?: number } {\n if (preferredSource === \"remote\") {\n return { source: \"remote\", url: entry.production ?? \"\" };\n }\n\n const localPath = resolveLocalDevelopmentPath(entry.development, configDir);\n if (localPath && existsSync(localPath)) {\n return { source: \"local\", url: \"\", localPath };\n }\n\n const devUrl =\n entry.development && !isLocalDevelopmentTarget(entry.development)\n ? entry.development.replace(/\\/$/, \"\")\n : null;\n if (devUrl) {\n return { source: \"local\", url: devUrl, port: parsePort(devUrl) };\n }\n\n return { source: \"remote\", url: entry.production ?? \"\" };\n }\n\n const hostEntry = resolveDevelopmentEntry(hostConfig, options.hostSource ?? \"local\");\n const uiEntry = resolveDevelopmentEntry(uiConfig, options.uiSource ?? \"local\");\n const apiEntry = resolveDevelopmentEntry(apiConfig, options.apiSource ?? \"local\");\n const authEntry = authConfig\n ? resolveDevelopmentEntry(authConfig, options.authSource ?? \"local\")\n : undefined;\n\n const hostUrl = `http://localhost:${DEFAULT_HOST_PORT}`;\n\n return {\n env: options.env ?? \"development\",\n account: bosConfig.account,\n domain: bosConfig.domain,\n networkId: getNetworkIdForAccount(bosConfig.account),\n host: {\n name: \"host\",\n url: hostUrl,\n entry: `${hostUrl}/mf-manifest.json`,\n localPath: hostEntry.localPath,\n port: hostEntry.port ?? DEFAULT_HOST_PORT,\n secrets: hostConfig.secrets,\n integrity: hostEntry.source === \"remote\" ? hostConfig.integrity : undefined,\n source: hostEntry.source,\n remoteUrl: hostEntry.source === \"remote\" ? hostEntry.url : undefined,\n },\n shared: bosConfig.shared,\n ui: uiConfig\n ? {\n name: uiConfig.name,\n url: uiEntry.url,\n entry: uiEntry.url ? `${uiEntry.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: uiEntry.localPath,\n port: uiEntry.port,\n ssrUrl: uiEntry.source === \"remote\" ? uiConfig.ssr : undefined,\n ssrIntegrity: uiEntry.source === \"remote\" ? uiConfig.ssrIntegrity : undefined,\n integrity: uiEntry.source === \"remote\" ? uiConfig.integrity : undefined,\n source: uiEntry.source,\n }\n : {\n name: \"ui\",\n url: \"\",\n entry: \"/mf-manifest.json\",\n source: uiEntry.source,\n },\n api: apiConfig\n ? {\n name: apiConfig.name,\n url: apiEntry.url,\n entry: apiEntry.url ? `${apiEntry.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: apiEntry.localPath,\n port: apiEntry.port,\n source: apiEntry.source,\n proxy: options.proxy ?? apiConfig.proxy,\n variables: apiConfig.variables,\n secrets: apiConfig.secrets,\n integrity: apiEntry.source === \"remote\" ? apiConfig.integrity : undefined,\n }\n : {\n name: \"api\",\n url: \"\",\n entry: \"/mf-manifest.json\",\n source: apiEntry.source,\n },\n auth:\n authEntry && authConfig\n ? {\n name: resolvePluginRuntimeName(undefined, authEntry.localPath, authConfig.name),\n url: authEntry.url,\n entry: authEntry.url ? `${authEntry.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: authEntry.localPath,\n port: authEntry.port,\n source: authEntry.source,\n proxy: authConfig.proxy,\n variables: authConfig.variables,\n secrets: authConfig.secrets,\n integrity: authEntry.source === \"remote\" ? authConfig.integrity : undefined,\n }\n : undefined,\n plugins: options.plugins,\n };\n}\n\nfunction probeTcpOpen(port: number, timeoutMs = 250): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = createConnection({ host: \"127.0.0.1\", port });\n const timer = setTimeout(() => {\n socket.destroy();\n resolve(false);\n }, timeoutMs);\n\n socket.once(\"connect\", () => {\n clearTimeout(timer);\n socket.destroy();\n resolve(true);\n });\n\n socket.once(\"error\", () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n}\n\nasync function pickAvailablePort(preferred: number, usedPorts: Set<number>): Promise<number> {\n let port = preferred;\n while (usedPorts.has(port) || (await probeTcpOpen(port))) {\n port += 1;\n }\n usedPorts.add(port);\n return port;\n}\n\nfunction withLocalRuntimeUrl<\n T extends { url: string; entry: string; port?: number; localPath?: string },\n>(entry: T, port: number): T {\n const url = `http://localhost:${port}`;\n return {\n ...entry,\n url,\n entry: `${url}/mf-manifest.json`,\n port,\n };\n}\n\nexport async function prepareDevelopmentRuntimeConfig(\n runtimeConfig: RuntimeConfig,\n options?: { hostPort?: number; ssr?: boolean },\n): Promise<RuntimeConfig> {\n const usedPorts = new Set<number>();\n const hostPort = await pickAvailablePort(options?.hostPort ?? DEFAULT_HOST_PORT, usedPorts);\n\n const next: RuntimeConfig = {\n ...runtimeConfig,\n host: { ...runtimeConfig.host, url: `http://localhost:${hostPort}`, port: hostPort },\n ui: { ...runtimeConfig.ui },\n api: { ...runtimeConfig.api },\n auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : undefined,\n plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : undefined,\n };\n\n if (next.api.source === \"local\" && next.api.localPath) {\n const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);\n next.api = withLocalRuntimeUrl(next.api, apiPort);\n }\n\n if (next.auth?.source === \"local\" && next.auth.localPath) {\n const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);\n next.auth = withLocalRuntimeUrl(next.auth, authPort);\n }\n\n if (next.ui.source === \"local\" && next.ui.localPath) {\n const uiPort = await pickAvailablePort(next.ui.port ?? DEFAULT_UI_PORT, usedPorts);\n next.ui = withLocalRuntimeUrl(next.ui, uiPort);\n if (options?.ssr) {\n const ssrPort = await pickAvailablePort(uiPort + 1, usedPorts);\n next.ui.ssrUrl = `http://localhost:${ssrPort}`;\n } else {\n next.ui.ssrUrl = undefined;\n }\n }\n\n if (next.plugins) {\n const entries = Object.entries(next.plugins).sort(([a], [b]) => a.localeCompare(b));\n let pluginBasePort = DEFAULT_PLUGIN_PORT_START;\n\n for (const [pluginId, plugin] of entries) {\n if (plugin.source !== \"local\" || !plugin.localPath) {\n continue;\n }\n\n const pluginPort = await pickAvailablePort(plugin.port ?? pluginBasePort, usedPorts);\n next.plugins[pluginId] = withLocalRuntimeUrl(plugin, pluginPort);\n pluginBasePort = pluginPort + 1;\n }\n }\n\n return next;\n}\n"],"mappings":"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"}
|
package/dist/app.mjs
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { getNetworkIdForAccount } from "./network.mjs";
|
|
2
2
|
import { getProjectRoot, isLocalDevelopmentTarget, parsePort, resolveLocalDevelopmentPath, resolvePluginRuntimeName } from "./config.mjs";
|
|
3
|
-
import "./orchestrator.mjs";
|
|
4
3
|
import { existsSync } from "node:fs";
|
|
5
4
|
import { join } from "node:path";
|
|
6
|
-
import { Effect } from "effect";
|
|
7
5
|
import { createConnection } from "node:net";
|
|
8
6
|
|
|
9
7
|
//#region src/app.ts
|
|
10
8
|
const DEFAULT_HOST_PORT = 3e3;
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const DEFAULT_PLUGIN_PORT_START =
|
|
9
|
+
const DEFAULT_API_PORT = 3001;
|
|
10
|
+
const DEFAULT_AUTH_PORT = 3002;
|
|
11
|
+
const DEFAULT_UI_PORT = 3003;
|
|
12
|
+
const DEFAULT_PLUGIN_PORT_START = 3010;
|
|
15
13
|
function detectLocalPackages(bosConfig, runtimeConfig) {
|
|
16
14
|
const packages = [];
|
|
17
15
|
const configDir = getProjectRoot();
|
|
@@ -19,7 +17,7 @@ function detectLocalPackages(bosConfig, runtimeConfig) {
|
|
|
19
17
|
if (uiLocalPath && existsSync(join(uiLocalPath, "package.json"))) packages.push("ui");
|
|
20
18
|
const apiLocalPath = runtimeConfig?.api.localPath ?? resolveLocalDevelopmentPath(bosConfig?.app.api.development, configDir);
|
|
21
19
|
if (apiLocalPath && existsSync(join(apiLocalPath, "package.json"))) packages.push("api");
|
|
22
|
-
const hostLocalPath = resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);
|
|
20
|
+
const hostLocalPath = runtimeConfig?.host?.localPath ?? resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);
|
|
23
21
|
if (hostLocalPath && existsSync(join(hostLocalPath, "package.json"))) packages.push("host");
|
|
24
22
|
else if (existsSync(join(configDir, "host", "package.json"))) packages.push("host");
|
|
25
23
|
for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig?.plugins ?? {})) if (pluginConfig.localPath && existsSync(join(pluginConfig.localPath, "package.json"))) packages.push(`plugin:${pluginId}`);
|
|
@@ -29,69 +27,98 @@ function detectLocalPackages(bosConfig, runtimeConfig) {
|
|
|
29
27
|
}
|
|
30
28
|
function buildRuntimeConfig(bosConfig, options) {
|
|
31
29
|
const configDir = getProjectRoot();
|
|
30
|
+
const hostConfig = bosConfig.app.host;
|
|
32
31
|
const uiConfig = bosConfig.app.ui;
|
|
33
32
|
const apiConfig = bosConfig.app.api;
|
|
34
33
|
const authConfig = bosConfig.app.auth;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
function resolveDevelopmentEntry(entry, preferredSource) {
|
|
35
|
+
if (preferredSource === "remote") return {
|
|
36
|
+
source: "remote",
|
|
37
|
+
url: entry.production ?? ""
|
|
38
|
+
};
|
|
39
|
+
const localPath = resolveLocalDevelopmentPath(entry.development, configDir);
|
|
40
|
+
if (localPath && existsSync(localPath)) return {
|
|
41
|
+
source: "local",
|
|
42
|
+
url: "",
|
|
43
|
+
localPath
|
|
44
|
+
};
|
|
45
|
+
const devUrl = entry.development && !isLocalDevelopmentTarget(entry.development) ? entry.development.replace(/\/$/, "") : null;
|
|
46
|
+
if (devUrl) return {
|
|
47
|
+
source: "local",
|
|
48
|
+
url: devUrl,
|
|
49
|
+
port: parsePort(devUrl)
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
source: "remote",
|
|
53
|
+
url: entry.production ?? ""
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const hostEntry = resolveDevelopmentEntry(hostConfig, options.hostSource ?? "local");
|
|
57
|
+
const uiEntry = resolveDevelopmentEntry(uiConfig, options.uiSource ?? "local");
|
|
58
|
+
const apiEntry = resolveDevelopmentEntry(apiConfig, options.apiSource ?? "local");
|
|
59
|
+
const authEntry = authConfig ? resolveDevelopmentEntry(authConfig, options.authSource ?? "local") : void 0;
|
|
60
|
+
const hostUrl = `http://localhost:${DEFAULT_HOST_PORT}`;
|
|
44
61
|
return {
|
|
45
62
|
env: options.env ?? "development",
|
|
46
63
|
account: bosConfig.account,
|
|
47
64
|
domain: bosConfig.domain,
|
|
48
65
|
networkId: getNetworkIdForAccount(bosConfig.account),
|
|
49
|
-
|
|
66
|
+
host: {
|
|
67
|
+
name: "host",
|
|
68
|
+
url: hostUrl,
|
|
69
|
+
entry: `${hostUrl}/mf-manifest.json`,
|
|
70
|
+
localPath: hostEntry.localPath,
|
|
71
|
+
port: hostEntry.port ?? DEFAULT_HOST_PORT,
|
|
72
|
+
secrets: hostConfig.secrets,
|
|
73
|
+
integrity: hostEntry.source === "remote" ? hostConfig.integrity : void 0,
|
|
74
|
+
source: hostEntry.source,
|
|
75
|
+
remoteUrl: hostEntry.source === "remote" ? hostEntry.url : void 0
|
|
76
|
+
},
|
|
50
77
|
shared: bosConfig.shared,
|
|
51
78
|
ui: uiConfig ? {
|
|
52
79
|
name: uiConfig.name,
|
|
53
|
-
url:
|
|
54
|
-
entry:
|
|
55
|
-
localPath:
|
|
56
|
-
port:
|
|
57
|
-
ssrUrl:
|
|
58
|
-
ssrIntegrity:
|
|
59
|
-
integrity:
|
|
60
|
-
source:
|
|
80
|
+
url: uiEntry.url,
|
|
81
|
+
entry: uiEntry.url ? `${uiEntry.url}/mf-manifest.json` : "/mf-manifest.json",
|
|
82
|
+
localPath: uiEntry.localPath,
|
|
83
|
+
port: uiEntry.port,
|
|
84
|
+
ssrUrl: uiEntry.source === "remote" ? uiConfig.ssr : void 0,
|
|
85
|
+
ssrIntegrity: uiEntry.source === "remote" ? uiConfig.ssrIntegrity : void 0,
|
|
86
|
+
integrity: uiEntry.source === "remote" ? uiConfig.integrity : void 0,
|
|
87
|
+
source: uiEntry.source
|
|
61
88
|
} : {
|
|
62
89
|
name: "ui",
|
|
63
90
|
url: "",
|
|
64
91
|
entry: "/mf-manifest.json",
|
|
65
|
-
source:
|
|
92
|
+
source: uiEntry.source
|
|
66
93
|
},
|
|
67
94
|
api: apiConfig ? {
|
|
68
95
|
name: apiConfig.name,
|
|
69
|
-
url:
|
|
70
|
-
entry:
|
|
71
|
-
localPath:
|
|
72
|
-
port:
|
|
73
|
-
source:
|
|
96
|
+
url: apiEntry.url,
|
|
97
|
+
entry: apiEntry.url ? `${apiEntry.url}/mf-manifest.json` : "/mf-manifest.json",
|
|
98
|
+
localPath: apiEntry.localPath,
|
|
99
|
+
port: apiEntry.port,
|
|
100
|
+
source: apiEntry.source,
|
|
74
101
|
proxy: options.proxy ?? apiConfig.proxy,
|
|
75
102
|
variables: apiConfig.variables,
|
|
76
103
|
secrets: apiConfig.secrets,
|
|
77
|
-
integrity:
|
|
104
|
+
integrity: apiEntry.source === "remote" ? apiConfig.integrity : void 0
|
|
78
105
|
} : {
|
|
79
106
|
name: "api",
|
|
80
107
|
url: "",
|
|
81
108
|
entry: "/mf-manifest.json",
|
|
82
|
-
source:
|
|
109
|
+
source: apiEntry.source
|
|
83
110
|
},
|
|
84
|
-
auth: authConfig ? {
|
|
85
|
-
name: resolvePluginRuntimeName(void 0,
|
|
86
|
-
url:
|
|
87
|
-
entry:
|
|
88
|
-
localPath:
|
|
89
|
-
port:
|
|
90
|
-
source:
|
|
111
|
+
auth: authEntry && authConfig ? {
|
|
112
|
+
name: resolvePluginRuntimeName(void 0, authEntry.localPath, authConfig.name),
|
|
113
|
+
url: authEntry.url,
|
|
114
|
+
entry: authEntry.url ? `${authEntry.url}/mf-manifest.json` : "/mf-manifest.json",
|
|
115
|
+
localPath: authEntry.localPath,
|
|
116
|
+
port: authEntry.port,
|
|
117
|
+
source: authEntry.source,
|
|
91
118
|
proxy: authConfig.proxy,
|
|
92
119
|
variables: authConfig.variables,
|
|
93
120
|
secrets: authConfig.secrets,
|
|
94
|
-
integrity:
|
|
121
|
+
integrity: authEntry.source === "remote" ? authConfig.integrity : void 0
|
|
95
122
|
} : void 0,
|
|
96
123
|
plugins: options.plugins
|
|
97
124
|
};
|
|
@@ -134,15 +161,27 @@ function withLocalRuntimeUrl(entry, port) {
|
|
|
134
161
|
}
|
|
135
162
|
async function prepareDevelopmentRuntimeConfig(runtimeConfig, options) {
|
|
136
163
|
const usedPorts = /* @__PURE__ */ new Set();
|
|
137
|
-
const hostPort = await pickAvailablePort(options?.hostPort ??
|
|
164
|
+
const hostPort = await pickAvailablePort(options?.hostPort ?? DEFAULT_HOST_PORT, usedPorts);
|
|
138
165
|
const next = {
|
|
139
166
|
...runtimeConfig,
|
|
140
|
-
|
|
167
|
+
host: {
|
|
168
|
+
...runtimeConfig.host,
|
|
169
|
+
url: `http://localhost:${hostPort}`,
|
|
170
|
+
port: hostPort
|
|
171
|
+
},
|
|
141
172
|
ui: { ...runtimeConfig.ui },
|
|
142
173
|
api: { ...runtimeConfig.api },
|
|
143
174
|
auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : void 0,
|
|
144
175
|
plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : void 0
|
|
145
176
|
};
|
|
177
|
+
if (next.api.source === "local" && next.api.localPath) {
|
|
178
|
+
const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);
|
|
179
|
+
next.api = withLocalRuntimeUrl(next.api, apiPort);
|
|
180
|
+
}
|
|
181
|
+
if (next.auth?.source === "local" && next.auth.localPath) {
|
|
182
|
+
const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);
|
|
183
|
+
next.auth = withLocalRuntimeUrl(next.auth, authPort);
|
|
184
|
+
}
|
|
146
185
|
if (next.ui.source === "local" && next.ui.localPath) {
|
|
147
186
|
const uiPort = await pickAvailablePort(next.ui.port ?? DEFAULT_UI_PORT, usedPorts);
|
|
148
187
|
next.ui = withLocalRuntimeUrl(next.ui, uiPort);
|
|
@@ -151,10 +190,6 @@ async function prepareDevelopmentRuntimeConfig(runtimeConfig, options) {
|
|
|
151
190
|
next.ui.ssrUrl = `http://localhost:${ssrPort}`;
|
|
152
191
|
} else next.ui.ssrUrl = void 0;
|
|
153
192
|
}
|
|
154
|
-
if (next.api.source === "local" && next.api.localPath) {
|
|
155
|
-
const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);
|
|
156
|
-
next.api = withLocalRuntimeUrl(next.api, apiPort);
|
|
157
|
-
}
|
|
158
193
|
if (next.plugins) {
|
|
159
194
|
const entries = Object.entries(next.plugins).sort(([a], [b]) => a.localeCompare(b));
|
|
160
195
|
let pluginBasePort = DEFAULT_PLUGIN_PORT_START;
|
|
@@ -165,10 +200,6 @@ async function prepareDevelopmentRuntimeConfig(runtimeConfig, options) {
|
|
|
165
200
|
pluginBasePort = pluginPort + 1;
|
|
166
201
|
}
|
|
167
202
|
}
|
|
168
|
-
if (next.auth?.source === "local" && next.auth.localPath) {
|
|
169
|
-
const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);
|
|
170
|
-
next.auth = withLocalRuntimeUrl(next.auth, authPort);
|
|
171
|
-
}
|
|
172
203
|
return next;
|
|
173
204
|
}
|
|
174
205
|
|
package/dist/app.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.mjs","names":[],"sources":["../src/app.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { createConnection } from \"node:net\";\nimport { join } from \"node:path\";\nimport { Effect } from \"effect\";\nimport {\n getProjectRoot,\n isLocalDevelopmentTarget,\n parsePort,\n resolveLocalDevelopmentPath,\n resolvePluginRuntimeName,\n} from \"./config\";\nimport { getNetworkIdForAccount } from \"./network\";\nimport { makeDevProcess, type ProcessCallbacks, type ProcessHandle } from \"./orchestrator\";\nimport type { ProcessRegistry } from \"./process-registry\";\nimport type { BosConfig, RuntimeConfig, RuntimePluginConfig } from \"./types\";\n\nexport interface AppOrchestrator {\n packages: string[];\n env: Record<string, string>;\n description: string;\n bosConfig: BosConfig;\n runtimeConfig: RuntimeConfig;\n port?: number;\n interactive?: boolean;\n}\n\nconst STARTUP_ORDER = [\"ui-ssr\", \"ui\", \"auth\", \"api\", \"plugin\", \"host-build\", \"host\"];\nconst DEFAULT_HOST_PORT = 3000;\nconst DEFAULT_UI_PORT = 3002;\nconst DEFAULT_API_PORT = 3014;\nconst DEFAULT_AUTH_PORT = 3020;\nconst DEFAULT_PLUGIN_PORT_START = 3021;\n\nconst sortByOrder = (packages: string[]): string[] => {\n return [...packages].sort((a, b) => {\n const aIdx = a.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(a);\n const bIdx = b.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return 0;\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n};\n\n// Note: log filtering and persistence lives at the CLI layer.\n\nexport interface DevServersHandle {\n handles: ProcessHandle[];\n shutdown: Effect.Effect<void>;\n}\n\nexport const startDevServers = (\n orchestrator: AppOrchestrator,\n callbacks: ProcessCallbacks,\n registry?: ProcessRegistry,\n) => {\n const run = Effect.gen(function* () {\n const orderedPackages = sortByOrder(orchestrator.packages);\n const handles: ProcessHandle[] = [];\n\n const startProcess = (pkg: string) => {\n const portOverride = pkg === \"host\" ? orchestrator.port : undefined;\n return makeDevProcess(\n pkg,\n orchestrator.env,\n callbacks,\n portOverride,\n orchestrator.bosConfig,\n orchestrator.runtimeConfig,\n registry,\n );\n };\n\n const startGroup = (packages: string[]) =>\n Effect.forEach(packages, startProcess, { concurrency: \"unbounded\" });\n\n const awaitReady = (pkg: string, handle: ProcessHandle) =>\n Effect.race(\n handle.waitForReady,\n Effect.sleep(\"30 seconds\").pipe(\n Effect.andThen(\n Effect.sync(() => {\n callbacks.onLog(pkg, \"Timeout waiting for ready, continuing...\", true);\n }),\n ),\n ),\n );\n\n const nonHostPackages = orderedPackages.filter((pkg) => pkg !== \"host\");\n const hostPackages = orderedPackages.filter((pkg) => pkg === \"host\");\n\n const nonHostHandles = yield* startGroup(nonHostPackages);\n handles.push(...nonHostHandles);\n\n yield* Effect.forEach(\n nonHostHandles.map((handle, index) => ({\n handle,\n pkg: nonHostPackages[index] ?? handle.name,\n })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const hostHandles = yield* startGroup(hostPackages);\n handles.push(...hostHandles);\n\n yield* Effect.forEach(\n hostHandles.map((handle, index) => ({ handle, pkg: hostPackages[index] ?? handle.name })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const shutdown = Effect.gen(function* () {\n const reversed = [...handles].reverse();\n for (const handle of reversed) {\n yield* handle.kill.pipe(Effect.ignore);\n }\n });\n\n return { handles, shutdown } satisfies DevServersHandle;\n });\n\n return run;\n};\n\nexport function detectLocalPackages(\n bosConfig?: BosConfig,\n runtimeConfig?: RuntimeConfig,\n): string[] {\n const packages: string[] = [];\n const configDir = getProjectRoot();\n\n const uiLocalPath =\n runtimeConfig?.ui.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.ui.development, configDir);\n if (uiLocalPath && existsSync(join(uiLocalPath, \"package.json\"))) {\n packages.push(\"ui\");\n }\n\n const apiLocalPath =\n runtimeConfig?.api.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.api.development, configDir);\n if (apiLocalPath && existsSync(join(apiLocalPath, \"package.json\"))) {\n packages.push(\"api\");\n }\n\n const hostLocalPath = resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);\n if (hostLocalPath && existsSync(join(hostLocalPath, \"package.json\"))) {\n packages.push(\"host\");\n } else if (existsSync(join(configDir, \"host\", \"package.json\"))) {\n packages.push(\"host\");\n }\n\n for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig?.plugins ?? {})) {\n if (pluginConfig.localPath && existsSync(join(pluginConfig.localPath, \"package.json\"))) {\n packages.push(`plugin:${pluginId}`);\n }\n }\n\n const authLocalPath =\n runtimeConfig?.auth?.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.auth?.development, configDir);\n if (authLocalPath && existsSync(join(authLocalPath, \"package.json\"))) {\n packages.push(\"auth\");\n }\n\n return packages;\n}\n\nexport function buildRuntimeConfig(\n bosConfig: BosConfig,\n options: {\n uiSource?: \"local\" | \"remote\";\n apiSource?: \"local\" | \"remote\";\n authSource?: \"local\" | \"remote\";\n hostUrl: string;\n proxy?: string;\n env?: \"development\" | \"production\";\n plugins?: Record<string, RuntimePluginConfig>;\n },\n): RuntimeConfig {\n const configDir = getProjectRoot();\n const uiConfig = bosConfig.app.ui;\n const apiConfig = bosConfig.app.api;\n const authConfig = bosConfig.app.auth;\n const uiSource = options.uiSource ?? \"local\";\n const apiSource = options.apiSource ?? \"local\";\n const authSource = options.authSource ?? \"local\";\n const uiLocalPath = resolveLocalDevelopmentPath(uiConfig.development, configDir);\n const apiLocalPath = resolveLocalDevelopmentPath(apiConfig.development, configDir);\n const authLocalPath = authConfig\n ? resolveLocalDevelopmentPath(authConfig.development, configDir)\n : null;\n const uiLocalUrl =\n !uiLocalPath && uiConfig.development && !isLocalDevelopmentTarget(uiConfig.development)\n ? uiConfig.development\n : \"\";\n const apiLocalUrl =\n !apiLocalPath && apiConfig.development && !isLocalDevelopmentTarget(apiConfig.development)\n ? apiConfig.development\n : \"\";\n const authLocalUrl =\n authConfig &&\n !authLocalPath &&\n authConfig.development &&\n !isLocalDevelopmentTarget(authConfig.development)\n ? authConfig.development\n : \"\";\n\n return {\n env: options.env ?? \"development\",\n account: bosConfig.account,\n domain: bosConfig.domain,\n networkId: getNetworkIdForAccount(bosConfig.account),\n hostUrl: options.hostUrl,\n shared: bosConfig.shared,\n ui: uiConfig\n ? {\n name: uiConfig.name,\n url: uiSource === \"remote\" ? (uiConfig.production ?? \"\") : uiLocalUrl,\n entry:\n uiSource === \"remote\"\n ? `${uiConfig.production ?? \"\"}/mf-manifest.json`\n : uiLocalUrl\n ? `${uiLocalUrl}/mf-manifest.json`\n : \"/mf-manifest.json\",\n localPath: uiSource === \"local\" ? (uiLocalPath ?? undefined) : undefined,\n port: uiSource === \"local\" && uiLocalUrl ? parsePort(uiLocalUrl) : undefined,\n ssrUrl: uiSource === \"remote\" ? uiConfig.ssr : undefined,\n ssrIntegrity: uiSource === \"remote\" ? uiConfig.ssrIntegrity : undefined,\n integrity: uiSource === \"remote\" ? uiConfig.integrity : undefined,\n source: uiSource === \"local\" ? (uiLocalPath ? \"local\" : \"remote\") : \"remote\",\n }\n : {\n name: \"ui\",\n url: \"\",\n entry: \"/mf-manifest.json\",\n source: uiSource,\n },\n api: apiConfig\n ? {\n name: apiConfig.name,\n url: apiSource === \"remote\" ? (apiConfig.production ?? \"\") : apiLocalUrl,\n entry:\n apiSource === \"remote\"\n ? `${apiConfig.production ?? \"\"}/mf-manifest.json`\n : apiLocalUrl\n ? `${apiLocalUrl}/mf-manifest.json`\n : \"/mf-manifest.json\",\n localPath: apiSource === \"local\" ? (apiLocalPath ?? undefined) : undefined,\n port: apiSource === \"local\" && apiLocalUrl ? parsePort(apiLocalUrl) : undefined,\n source: apiSource === \"local\" ? (apiLocalPath ? \"local\" : \"remote\") : \"remote\",\n proxy: options.proxy ?? apiConfig.proxy,\n variables: apiConfig.variables,\n secrets: apiConfig.secrets,\n integrity: apiSource === \"remote\" ? apiConfig.integrity : undefined,\n }\n : {\n name: \"api\",\n url: \"\",\n entry: \"/mf-manifest.json\",\n source: apiSource,\n },\n auth: authConfig\n ? {\n name: resolvePluginRuntimeName(\n undefined,\n authSource === \"local\" ? (authLocalPath ?? undefined) : undefined,\n authConfig.name,\n ),\n url: authSource === \"remote\" ? (authConfig.production ?? \"\") : authLocalUrl,\n entry:\n authSource === \"remote\"\n ? `${authConfig.production ?? \"\"}/mf-manifest.json`\n : authLocalUrl\n ? `${authLocalUrl}/mf-manifest.json`\n : \"/mf-manifest.json\",\n localPath: authSource === \"local\" ? (authLocalPath ?? undefined) : undefined,\n port: authSource === \"local\" && authLocalUrl ? parsePort(authLocalUrl) : undefined,\n source: authSource === \"local\" ? (authLocalPath ? \"local\" : \"remote\") : \"remote\",\n proxy: authConfig.proxy,\n variables: authConfig.variables,\n secrets: authConfig.secrets,\n integrity: authSource === \"remote\" ? authConfig.integrity : undefined,\n }\n : undefined,\n plugins: options.plugins,\n };\n}\n\nfunction probeTcpOpen(port: number, timeoutMs = 250): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = createConnection({ host: \"127.0.0.1\", port });\n const timer = setTimeout(() => {\n socket.destroy();\n resolve(false);\n }, timeoutMs);\n\n socket.once(\"connect\", () => {\n clearTimeout(timer);\n socket.destroy();\n resolve(true);\n });\n\n socket.once(\"error\", () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n}\n\nasync function pickAvailablePort(preferred: number, usedPorts: Set<number>): Promise<number> {\n let port = preferred;\n while (usedPorts.has(port) || (await probeTcpOpen(port))) {\n port += 1;\n }\n usedPorts.add(port);\n return port;\n}\n\nfunction withLocalRuntimeUrl<\n T extends { url: string; entry: string; port?: number; localPath?: string },\n>(entry: T, port: number): T {\n const url = `http://localhost:${port}`;\n return {\n ...entry,\n url,\n entry: `${url}/mf-manifest.json`,\n port,\n };\n}\n\nexport async function prepareDevelopmentRuntimeConfig(\n runtimeConfig: RuntimeConfig,\n options?: { hostPort?: number; ssr?: boolean },\n): Promise<RuntimeConfig> {\n const usedPorts = new Set<number>();\n const hostPort = await pickAvailablePort(\n options?.hostPort ??\n (runtimeConfig.hostUrl ? parsePort(runtimeConfig.hostUrl) : DEFAULT_HOST_PORT),\n usedPorts,\n );\n\n const next: RuntimeConfig = {\n ...runtimeConfig,\n hostUrl: `http://localhost:${hostPort}`,\n ui: { ...runtimeConfig.ui },\n api: { ...runtimeConfig.api },\n auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : undefined,\n plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : undefined,\n };\n\n if (next.ui.source === \"local\" && next.ui.localPath) {\n const uiPort = await pickAvailablePort(next.ui.port ?? DEFAULT_UI_PORT, usedPorts);\n next.ui = withLocalRuntimeUrl(next.ui, uiPort);\n if (options?.ssr) {\n const ssrPort = await pickAvailablePort(uiPort + 1, usedPorts);\n next.ui.ssrUrl = `http://localhost:${ssrPort}`;\n } else {\n next.ui.ssrUrl = undefined;\n }\n }\n\n if (next.api.source === \"local\" && next.api.localPath) {\n const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);\n next.api = withLocalRuntimeUrl(next.api, apiPort);\n }\n\n if (next.plugins) {\n const entries = Object.entries(next.plugins).sort(([a], [b]) => a.localeCompare(b));\n let pluginBasePort = DEFAULT_PLUGIN_PORT_START;\n\n for (const [pluginId, plugin] of entries) {\n if (plugin.source !== \"local\" || !plugin.localPath) {\n continue;\n }\n\n const pluginPort = await pickAvailablePort(plugin.port ?? pluginBasePort, usedPorts);\n next.plugins[pluginId] = withLocalRuntimeUrl(plugin, pluginPort);\n pluginBasePort = pluginPort + 1;\n }\n }\n\n if (next.auth?.source === \"local\" && next.auth.localPath) {\n const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);\n next.auth = withLocalRuntimeUrl(next.auth, authPort);\n }\n\n return next;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app.mjs","names":[],"sources":["../src/app.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { createConnection } from \"node:net\";\nimport { join } from \"node:path\";\nimport {\n getProjectRoot,\n isLocalDevelopmentTarget,\n parsePort,\n resolveLocalDevelopmentPath,\n resolvePluginRuntimeName,\n} from \"./config\";\nimport { getNetworkIdForAccount } from \"./network\";\nimport type { AppOrchestrator } from \"./service-descriptor\";\nimport type { BosConfig, RuntimeConfig, RuntimePluginConfig } from \"./types\";\n\nexport type { AppOrchestrator };\n\nconst DEFAULT_HOST_PORT = 3000;\nconst DEFAULT_API_PORT = 3001;\nconst DEFAULT_AUTH_PORT = 3002;\nconst DEFAULT_UI_PORT = 3003;\nconst DEFAULT_PLUGIN_PORT_START = 3010;\n\nexport function detectLocalPackages(\n bosConfig?: BosConfig,\n runtimeConfig?: RuntimeConfig,\n): string[] {\n const packages: string[] = [];\n const configDir = getProjectRoot();\n\n const uiLocalPath =\n runtimeConfig?.ui.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.ui.development, configDir);\n if (uiLocalPath && existsSync(join(uiLocalPath, \"package.json\"))) {\n packages.push(\"ui\");\n }\n\n const apiLocalPath =\n runtimeConfig?.api.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.api.development, configDir);\n if (apiLocalPath && existsSync(join(apiLocalPath, \"package.json\"))) {\n packages.push(\"api\");\n }\n\n const hostLocalPath =\n runtimeConfig?.host?.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);\n if (hostLocalPath && existsSync(join(hostLocalPath, \"package.json\"))) {\n packages.push(\"host\");\n } else if (existsSync(join(configDir, \"host\", \"package.json\"))) {\n packages.push(\"host\");\n }\n\n for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig?.plugins ?? {})) {\n if (pluginConfig.localPath && existsSync(join(pluginConfig.localPath, \"package.json\"))) {\n packages.push(`plugin:${pluginId}`);\n }\n }\n\n const authLocalPath =\n runtimeConfig?.auth?.localPath ??\n resolveLocalDevelopmentPath(bosConfig?.app.auth?.development, configDir);\n if (authLocalPath && existsSync(join(authLocalPath, \"package.json\"))) {\n packages.push(\"auth\");\n }\n\n return packages;\n}\n\nexport function buildRuntimeConfig(\n bosConfig: BosConfig,\n options: {\n hostSource?: \"local\" | \"remote\";\n uiSource?: \"local\" | \"remote\";\n apiSource?: \"local\" | \"remote\";\n authSource?: \"local\" | \"remote\";\n proxy?: string;\n env?: \"development\" | \"production\";\n plugins?: Record<string, RuntimePluginConfig>;\n },\n): RuntimeConfig {\n const configDir = getProjectRoot();\n const hostConfig = bosConfig.app.host;\n const uiConfig = bosConfig.app.ui;\n const apiConfig = bosConfig.app.api;\n const authConfig = bosConfig.app.auth;\n\n function resolveDevelopmentEntry(\n entry: { development?: string; production?: string },\n preferredSource: \"local\" | \"remote\",\n ): { source: \"local\" | \"remote\"; url: string; localPath?: string; port?: number } {\n if (preferredSource === \"remote\") {\n return { source: \"remote\", url: entry.production ?? \"\" };\n }\n\n const localPath = resolveLocalDevelopmentPath(entry.development, configDir);\n if (localPath && existsSync(localPath)) {\n return { source: \"local\", url: \"\", localPath };\n }\n\n const devUrl =\n entry.development && !isLocalDevelopmentTarget(entry.development)\n ? entry.development.replace(/\\/$/, \"\")\n : null;\n if (devUrl) {\n return { source: \"local\", url: devUrl, port: parsePort(devUrl) };\n }\n\n return { source: \"remote\", url: entry.production ?? \"\" };\n }\n\n const hostEntry = resolveDevelopmentEntry(hostConfig, options.hostSource ?? \"local\");\n const uiEntry = resolveDevelopmentEntry(uiConfig, options.uiSource ?? \"local\");\n const apiEntry = resolveDevelopmentEntry(apiConfig, options.apiSource ?? \"local\");\n const authEntry = authConfig\n ? resolveDevelopmentEntry(authConfig, options.authSource ?? \"local\")\n : undefined;\n\n const hostUrl = `http://localhost:${DEFAULT_HOST_PORT}`;\n\n return {\n env: options.env ?? \"development\",\n account: bosConfig.account,\n domain: bosConfig.domain,\n networkId: getNetworkIdForAccount(bosConfig.account),\n host: {\n name: \"host\",\n url: hostUrl,\n entry: `${hostUrl}/mf-manifest.json`,\n localPath: hostEntry.localPath,\n port: hostEntry.port ?? DEFAULT_HOST_PORT,\n secrets: hostConfig.secrets,\n integrity: hostEntry.source === \"remote\" ? hostConfig.integrity : undefined,\n source: hostEntry.source,\n remoteUrl: hostEntry.source === \"remote\" ? hostEntry.url : undefined,\n },\n shared: bosConfig.shared,\n ui: uiConfig\n ? {\n name: uiConfig.name,\n url: uiEntry.url,\n entry: uiEntry.url ? `${uiEntry.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: uiEntry.localPath,\n port: uiEntry.port,\n ssrUrl: uiEntry.source === \"remote\" ? uiConfig.ssr : undefined,\n ssrIntegrity: uiEntry.source === \"remote\" ? uiConfig.ssrIntegrity : undefined,\n integrity: uiEntry.source === \"remote\" ? uiConfig.integrity : undefined,\n source: uiEntry.source,\n }\n : {\n name: \"ui\",\n url: \"\",\n entry: \"/mf-manifest.json\",\n source: uiEntry.source,\n },\n api: apiConfig\n ? {\n name: apiConfig.name,\n url: apiEntry.url,\n entry: apiEntry.url ? `${apiEntry.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: apiEntry.localPath,\n port: apiEntry.port,\n source: apiEntry.source,\n proxy: options.proxy ?? apiConfig.proxy,\n variables: apiConfig.variables,\n secrets: apiConfig.secrets,\n integrity: apiEntry.source === \"remote\" ? apiConfig.integrity : undefined,\n }\n : {\n name: \"api\",\n url: \"\",\n entry: \"/mf-manifest.json\",\n source: apiEntry.source,\n },\n auth:\n authEntry && authConfig\n ? {\n name: resolvePluginRuntimeName(undefined, authEntry.localPath, authConfig.name),\n url: authEntry.url,\n entry: authEntry.url ? `${authEntry.url}/mf-manifest.json` : \"/mf-manifest.json\",\n localPath: authEntry.localPath,\n port: authEntry.port,\n source: authEntry.source,\n proxy: authConfig.proxy,\n variables: authConfig.variables,\n secrets: authConfig.secrets,\n integrity: authEntry.source === \"remote\" ? authConfig.integrity : undefined,\n }\n : undefined,\n plugins: options.plugins,\n };\n}\n\nfunction probeTcpOpen(port: number, timeoutMs = 250): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = createConnection({ host: \"127.0.0.1\", port });\n const timer = setTimeout(() => {\n socket.destroy();\n resolve(false);\n }, timeoutMs);\n\n socket.once(\"connect\", () => {\n clearTimeout(timer);\n socket.destroy();\n resolve(true);\n });\n\n socket.once(\"error\", () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n}\n\nasync function pickAvailablePort(preferred: number, usedPorts: Set<number>): Promise<number> {\n let port = preferred;\n while (usedPorts.has(port) || (await probeTcpOpen(port))) {\n port += 1;\n }\n usedPorts.add(port);\n return port;\n}\n\nfunction withLocalRuntimeUrl<\n T extends { url: string; entry: string; port?: number; localPath?: string },\n>(entry: T, port: number): T {\n const url = `http://localhost:${port}`;\n return {\n ...entry,\n url,\n entry: `${url}/mf-manifest.json`,\n port,\n };\n}\n\nexport async function prepareDevelopmentRuntimeConfig(\n runtimeConfig: RuntimeConfig,\n options?: { hostPort?: number; ssr?: boolean },\n): Promise<RuntimeConfig> {\n const usedPorts = new Set<number>();\n const hostPort = await pickAvailablePort(options?.hostPort ?? DEFAULT_HOST_PORT, usedPorts);\n\n const next: RuntimeConfig = {\n ...runtimeConfig,\n host: { ...runtimeConfig.host, url: `http://localhost:${hostPort}`, port: hostPort },\n ui: { ...runtimeConfig.ui },\n api: { ...runtimeConfig.api },\n auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : undefined,\n plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : undefined,\n };\n\n if (next.api.source === \"local\" && next.api.localPath) {\n const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);\n next.api = withLocalRuntimeUrl(next.api, apiPort);\n }\n\n if (next.auth?.source === \"local\" && next.auth.localPath) {\n const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);\n next.auth = withLocalRuntimeUrl(next.auth, authPort);\n }\n\n if (next.ui.source === \"local\" && next.ui.localPath) {\n const uiPort = await pickAvailablePort(next.ui.port ?? DEFAULT_UI_PORT, usedPorts);\n next.ui = withLocalRuntimeUrl(next.ui, uiPort);\n if (options?.ssr) {\n const ssrPort = await pickAvailablePort(uiPort + 1, usedPorts);\n next.ui.ssrUrl = `http://localhost:${ssrPort}`;\n } else {\n next.ui.ssrUrl = undefined;\n }\n }\n\n if (next.plugins) {\n const entries = Object.entries(next.plugins).sort(([a], [b]) => a.localeCompare(b));\n let pluginBasePort = DEFAULT_PLUGIN_PORT_START;\n\n for (const [pluginId, plugin] of entries) {\n if (plugin.source !== \"local\" || !plugin.localPath) {\n continue;\n }\n\n const pluginPort = await pickAvailablePort(plugin.port ?? pluginBasePort, usedPorts);\n next.plugins[pluginId] = withLocalRuntimeUrl(plugin, pluginPort);\n pluginBasePort = pluginPort + 1;\n }\n }\n\n return next;\n}\n"],"mappings":"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"}
|