everything-dev 1.7.2 → 1.8.0

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 (134) hide show
  1. package/dist/api.cjs +1 -1
  2. package/dist/api.mjs +1 -1
  3. package/dist/app.cjs +82 -51
  4. package/dist/app.cjs.map +1 -1
  5. package/dist/app.mjs +82 -51
  6. package/dist/app.mjs.map +1 -1
  7. package/dist/cli/upgrade.cjs.map +1 -1
  8. package/dist/cli/upgrade.mjs.map +1 -1
  9. package/dist/components/dev-view.cjs +6 -3
  10. package/dist/components/dev-view.cjs.map +1 -1
  11. package/dist/components/dev-view.mjs +6 -3
  12. package/dist/components/dev-view.mjs.map +1 -1
  13. package/dist/components/streaming-view.cjs +5 -2
  14. package/dist/components/streaming-view.cjs.map +1 -1
  15. package/dist/components/streaming-view.mjs +5 -2
  16. package/dist/components/streaming-view.mjs.map +1 -1
  17. package/dist/config.cjs +28 -5
  18. package/dist/config.cjs.map +1 -1
  19. package/dist/config.d.cts.map +1 -1
  20. package/dist/config.d.mts.map +1 -1
  21. package/dist/config.mjs +28 -5
  22. package/dist/config.mjs.map +1 -1
  23. package/dist/contract.cjs +1 -0
  24. package/dist/contract.cjs.map +1 -1
  25. package/dist/contract.d.cts +14 -6
  26. package/dist/contract.d.cts.map +1 -1
  27. package/dist/contract.d.mts +14 -6
  28. package/dist/contract.d.mts.map +1 -1
  29. package/dist/contract.mjs +1 -0
  30. package/dist/contract.mjs.map +1 -1
  31. package/dist/dev-logs.cjs +6 -2
  32. package/dist/dev-logs.cjs.map +1 -1
  33. package/dist/dev-logs.mjs +7 -2
  34. package/dist/dev-logs.mjs.map +1 -1
  35. package/dist/dev-session.cjs +27 -23
  36. package/dist/dev-session.cjs.map +1 -1
  37. package/dist/dev-session.mjs +27 -24
  38. package/dist/dev-session.mjs.map +1 -1
  39. package/dist/federation.server.cjs +1 -1
  40. package/dist/federation.server.mjs +1 -1
  41. package/dist/host.cjs +4 -3
  42. package/dist/host.cjs.map +1 -1
  43. package/dist/host.d.cts.map +1 -1
  44. package/dist/host.d.mts.map +1 -1
  45. package/dist/host.mjs +4 -3
  46. package/dist/host.mjs.map +1 -1
  47. package/dist/integrity.cjs +68 -2
  48. package/dist/integrity.cjs.map +1 -1
  49. package/dist/integrity.d.cts +14 -1
  50. package/dist/integrity.d.cts.map +1 -1
  51. package/dist/integrity.d.mts +14 -1
  52. package/dist/integrity.d.mts.map +1 -1
  53. package/dist/integrity.mjs +66 -3
  54. package/dist/integrity.mjs.map +1 -1
  55. package/dist/mf.cjs +32 -0
  56. package/dist/mf.cjs.map +1 -1
  57. package/dist/mf.d.cts +3 -1
  58. package/dist/mf.d.cts.map +1 -1
  59. package/dist/mf.d.mts +3 -1
  60. package/dist/mf.d.mts.map +1 -1
  61. package/dist/mf.mjs +32 -1
  62. package/dist/mf.mjs.map +1 -1
  63. package/dist/orchestrator.cjs +167 -317
  64. package/dist/orchestrator.cjs.map +1 -1
  65. package/dist/orchestrator.d.cts +24 -21
  66. package/dist/orchestrator.d.cts.map +1 -1
  67. package/dist/orchestrator.d.mts +24 -21
  68. package/dist/orchestrator.d.mts.map +1 -1
  69. package/dist/orchestrator.mjs +168 -316
  70. package/dist/orchestrator.mjs.map +1 -1
  71. package/dist/plugin.cjs +38 -107
  72. package/dist/plugin.cjs.map +1 -1
  73. package/dist/plugin.d.cts +19 -5
  74. package/dist/plugin.d.cts.map +1 -1
  75. package/dist/plugin.d.mts +19 -5
  76. package/dist/plugin.d.mts.map +1 -1
  77. package/dist/plugin.mjs +39 -108
  78. package/dist/plugin.mjs.map +1 -1
  79. package/dist/service-descriptor.cjs +188 -0
  80. package/dist/service-descriptor.cjs.map +1 -0
  81. package/dist/service-descriptor.d.cts +107 -0
  82. package/dist/service-descriptor.d.cts.map +1 -0
  83. package/dist/service-descriptor.d.mts +107 -0
  84. package/dist/service-descriptor.d.mts.map +1 -0
  85. package/dist/service-descriptor.mjs +182 -0
  86. package/dist/service-descriptor.mjs.map +1 -0
  87. package/dist/types.cjs +8 -1
  88. package/dist/types.cjs.map +1 -1
  89. package/dist/types.d.cts +18 -3
  90. package/dist/types.d.cts.map +1 -1
  91. package/dist/types.d.mts +18 -3
  92. package/dist/types.d.mts.map +1 -1
  93. package/dist/types.mjs +8 -1
  94. package/dist/types.mjs.map +1 -1
  95. package/dist/ui/index.cjs +1 -0
  96. package/dist/ui/index.d.cts +2 -2
  97. package/dist/ui/index.d.mts +2 -2
  98. package/dist/ui/index.mjs +2 -2
  99. package/dist/ui/runtime.cjs +4 -0
  100. package/dist/ui/runtime.cjs.map +1 -1
  101. package/dist/ui/runtime.d.cts +2 -1
  102. package/dist/ui/runtime.d.cts.map +1 -1
  103. package/dist/ui/runtime.d.mts +2 -1
  104. package/dist/ui/runtime.d.mts.map +1 -1
  105. package/dist/ui/runtime.mjs +4 -1
  106. package/dist/ui/runtime.mjs.map +1 -1
  107. package/package.json +12 -4
  108. package/skills/dev-workflow/SKILL.md +105 -0
  109. package/skills/publish-sync/SKILL.md +130 -0
  110. package/src/app.ts +98 -204
  111. package/src/cli/upgrade.ts +20 -4
  112. package/src/components/dev-view.tsx +8 -3
  113. package/src/components/streaming-view.ts +7 -2
  114. package/src/config.ts +40 -8
  115. package/src/contract.ts +1 -0
  116. package/src/dev-logs.ts +8 -1
  117. package/src/dev-session.ts +56 -79
  118. package/src/host.ts +4 -3
  119. package/src/integrity.ts +96 -10
  120. package/src/mf.ts +42 -0
  121. package/src/orchestrator.ts +232 -411
  122. package/src/plugin.ts +48 -136
  123. package/src/service-descriptor.ts +258 -0
  124. package/src/types.ts +8 -1
  125. package/src/ui/runtime.ts +5 -0
  126. package/dist/process-registry.cjs +0 -120
  127. package/dist/process-registry.cjs.map +0 -1
  128. package/dist/process-registry.d.cts +0 -25
  129. package/dist/process-registry.d.cts.map +0 -1
  130. package/dist/process-registry.d.mts +0 -25
  131. package/dist/process-registry.d.mts.map +0 -1
  132. package/dist/process-registry.mjs +0 -119
  133. package/dist/process-registry.mjs.map +0 -1
  134. package/src/process-registry.ts +0 -154
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: publish-sync
3
+ description: Publish bos.config.json to the FastKV registry, sync from upstream, and upgrade workspace packages. Use when deploying, syncing, or managing runtime configuration across projects.
4
+ metadata:
5
+ sources: "src/plugin.ts,src/cli/sync.ts,src/cli/upgrade.ts,src/fastkv.ts,src/integrity.ts"
6
+ ---
7
+
8
+ # everything-dev Publish & Sync
9
+
10
+ ## Core Workflow
11
+
12
+ ```
13
+ Build → Deploy → Publish → Sync
14
+ ↓ ↓ ↓ ↓
15
+ rspack Zephyr FastKV bos sync
16
+ CDN registry
17
+ ```
18
+
19
+ ## Publish
20
+
21
+ Publish `bos.config.json` to the temporary `dev.everything.near` FastKV registry:
22
+
23
+ ```bash
24
+ bos publish # Publish config only
25
+ bos publish --deploy # Build/deploy all workspaces first, then publish
26
+ bos publish --dry-run # Preview without sending
27
+ bos publish --network testnet
28
+ bos publish --packages ui,api
29
+ ```
30
+
31
+ After `bos publish --deploy`:
32
+ 1. Each workspace builds and deploys to Zephyr CDN
33
+ 2. `bos.config.json` is auto-updated with production URLs + integrity hashes
34
+ 3. Config is published to the FastKV registry at `{account}/bos/gateways/{gateway}/bos.config.json`
35
+
36
+ ## Sync
37
+
38
+ Pull updates from a published config:
39
+
40
+ ```bash
41
+ bos sync # From every.near/everything.dev (default)
42
+ bos sync --account foo.near --gateway bar.com
43
+ bos sync --network testnet
44
+ bos sync --force
45
+ bos sync --files # Also sync template files (rsbuild.config.ts, etc.)
46
+ ```
47
+
48
+ What gets synced from remote:
49
+ - `app.*.production` — Zephyr URLs
50
+ - `app.*.ssr` — SSR URLs
51
+ - `app.*.template`, `app.*.files`, `app.*.sync` — scaffolding config
52
+ - `shared` — shared dependency versions
53
+ - `gateway` — gateway URLs
54
+
55
+ What stays local:
56
+ - `account`, `testnet` — your NEAR accounts
57
+ - `app.*.development` — local dev URLs
58
+
59
+ What gets merged:
60
+ - `app.*.secrets` — union of remote + local
61
+ - `app.*.variables` — merged (local overrides remote)
62
+
63
+ ## Upgrade
64
+
65
+ Bump `every-plugin` and `everything-dev` across all workspaces:
66
+
67
+ ```bash
68
+ bos upgrade # Check for new versions, update, then sync
69
+ bos upgrade --dry-run # Preview without making changes
70
+ ```
71
+
72
+ `bos upgrade` updates **all workspace `package.json`s**, not just root. Also updates `peerDependencies` and `workspaces.catalog`. Correctly skips `workspace:*` and `catalog:` references.
73
+
74
+ ## Build
75
+
76
+ ```bash
77
+ bos build # Build all packages (skips missing)
78
+ bos build ui # Build specific package
79
+ bos build ui,api # Build multiple
80
+ bos build --force # Force rebuild
81
+ ```
82
+
83
+ ## Config Integrity
84
+
85
+ `bos.config.json` entries can include `integrity` fields with SRI hashes:
86
+
87
+ ```json
88
+ {
89
+ "app": {
90
+ "ui": {
91
+ "production": "https://cdn.example.com/ui/remoteEntry.js",
92
+ "integrity": "sha384-abc123..."
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ These are auto-generated during `bos publish --deploy` and verified at runtime by the host.
99
+
100
+ ## Project Creation
101
+
102
+ ```bash
103
+ bos create project my-app # Interactive
104
+ bos create project my-app -a my.near --testnet my.testnet # Skip prompts
105
+ ```
106
+
107
+ ## Configuration
108
+
109
+ All runtime config lives in `bos.config.json`. Key sections:
110
+ - `account` — NEAR mainnet account
111
+ - `testnet` — NEAR testnet account
112
+ - `staging.domain` — Staging domain
113
+ - `app.host`, `app.ui`, `app.api`, `app.auth` — Module configs with development/production URLs
114
+ - `plugins.{key}` — Plugin configs with variables, secrets, routes
115
+ - `shared.ui`, `shared.api` — Module Federation shared dependency versions
116
+
117
+ ## Troubleshooting
118
+
119
+ ```bash
120
+ bos info # Show current configuration
121
+ bos status # Check remote health
122
+ bos clean # Clean build artifacts
123
+ ```
124
+
125
+ Process issues:
126
+ ```bash
127
+ bos kill # Kill all tracked processes
128
+ bun install # Reinstall deps
129
+ bos dev --host remote # Restart
130
+ ```
package/src/app.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { createConnection } from "node:net";
3
3
  import { join } from "node:path";
4
- import { Effect } from "effect";
5
4
  import {
6
5
  getProjectRoot,
7
6
  isLocalDevelopmentTarget,
@@ -10,122 +9,16 @@ import {
10
9
  resolvePluginRuntimeName,
11
10
  } from "./config";
12
11
  import { getNetworkIdForAccount } from "./network";
13
- import { makeDevProcess, type ProcessCallbacks, type ProcessHandle } from "./orchestrator";
14
- import type { ProcessRegistry } from "./process-registry";
12
+ import type { AppOrchestrator } from "./service-descriptor";
15
13
  import type { BosConfig, RuntimeConfig, RuntimePluginConfig } from "./types";
16
14
 
17
- export interface AppOrchestrator {
18
- packages: string[];
19
- env: Record<string, string>;
20
- description: string;
21
- bosConfig: BosConfig;
22
- runtimeConfig: RuntimeConfig;
23
- port?: number;
24
- interactive?: boolean;
25
- }
15
+ export type { AppOrchestrator };
26
16
 
27
- const STARTUP_ORDER = ["ui-ssr", "ui", "auth", "api", "plugin", "host-build", "host"];
28
17
  const DEFAULT_HOST_PORT = 3000;
29
- const DEFAULT_UI_PORT = 3002;
30
- const DEFAULT_API_PORT = 3014;
31
- const DEFAULT_AUTH_PORT = 3020;
32
- const DEFAULT_PLUGIN_PORT_START = 3021;
33
-
34
- const sortByOrder = (packages: string[]): string[] => {
35
- return [...packages].sort((a, b) => {
36
- const aIdx = a.startsWith("plugin:")
37
- ? STARTUP_ORDER.indexOf("plugin")
38
- : STARTUP_ORDER.indexOf(a);
39
- const bIdx = b.startsWith("plugin:")
40
- ? STARTUP_ORDER.indexOf("plugin")
41
- : STARTUP_ORDER.indexOf(b);
42
- if (aIdx === -1 && bIdx === -1) return 0;
43
- if (aIdx === -1) return 1;
44
- if (bIdx === -1) return -1;
45
- return aIdx - bIdx;
46
- });
47
- };
48
-
49
- // Note: log filtering and persistence lives at the CLI layer.
50
-
51
- export interface DevServersHandle {
52
- handles: ProcessHandle[];
53
- shutdown: Effect.Effect<void>;
54
- }
55
-
56
- export const startDevServers = (
57
- orchestrator: AppOrchestrator,
58
- callbacks: ProcessCallbacks,
59
- registry?: ProcessRegistry,
60
- ) => {
61
- const run = Effect.gen(function* () {
62
- const orderedPackages = sortByOrder(orchestrator.packages);
63
- const handles: ProcessHandle[] = [];
64
-
65
- const startProcess = (pkg: string) => {
66
- const portOverride = pkg === "host" ? orchestrator.port : undefined;
67
- return makeDevProcess(
68
- pkg,
69
- orchestrator.env,
70
- callbacks,
71
- portOverride,
72
- orchestrator.bosConfig,
73
- orchestrator.runtimeConfig,
74
- registry,
75
- );
76
- };
77
-
78
- const startGroup = (packages: string[]) =>
79
- Effect.forEach(packages, startProcess, { concurrency: "unbounded" });
80
-
81
- const awaitReady = (pkg: string, handle: ProcessHandle) =>
82
- Effect.race(
83
- handle.waitForReady,
84
- Effect.sleep("30 seconds").pipe(
85
- Effect.andThen(
86
- Effect.sync(() => {
87
- callbacks.onLog(pkg, "Timeout waiting for ready, continuing...", true);
88
- }),
89
- ),
90
- ),
91
- );
92
-
93
- const nonHostPackages = orderedPackages.filter((pkg) => pkg !== "host");
94
- const hostPackages = orderedPackages.filter((pkg) => pkg === "host");
95
-
96
- const nonHostHandles = yield* startGroup(nonHostPackages);
97
- handles.push(...nonHostHandles);
98
-
99
- yield* Effect.forEach(
100
- nonHostHandles.map((handle, index) => ({
101
- handle,
102
- pkg: nonHostPackages[index] ?? handle.name,
103
- })),
104
- ({ handle, pkg }) => awaitReady(pkg, handle),
105
- { concurrency: "unbounded" },
106
- );
107
-
108
- const hostHandles = yield* startGroup(hostPackages);
109
- handles.push(...hostHandles);
110
-
111
- yield* Effect.forEach(
112
- hostHandles.map((handle, index) => ({ handle, pkg: hostPackages[index] ?? handle.name })),
113
- ({ handle, pkg }) => awaitReady(pkg, handle),
114
- { concurrency: "unbounded" },
115
- );
116
-
117
- const shutdown = Effect.gen(function* () {
118
- const reversed = [...handles].reverse();
119
- for (const handle of reversed) {
120
- yield* handle.kill.pipe(Effect.ignore);
121
- }
122
- });
123
-
124
- return { handles, shutdown } satisfies DevServersHandle;
125
- });
126
-
127
- return run;
128
- };
18
+ const DEFAULT_API_PORT = 3001;
19
+ const DEFAULT_AUTH_PORT = 3002;
20
+ const DEFAULT_UI_PORT = 3003;
21
+ const DEFAULT_PLUGIN_PORT_START = 3010;
129
22
 
130
23
  export function detectLocalPackages(
131
24
  bosConfig?: BosConfig,
@@ -148,7 +41,9 @@ export function detectLocalPackages(
148
41
  packages.push("api");
149
42
  }
150
43
 
151
- const hostLocalPath = resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);
44
+ const hostLocalPath =
45
+ runtimeConfig?.host?.localPath ??
46
+ resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);
152
47
  if (hostLocalPath && existsSync(join(hostLocalPath, "package.json"))) {
153
48
  packages.push("host");
154
49
  } else if (existsSync(join(configDir, "host", "package.json"))) {
@@ -174,120 +69,123 @@ export function detectLocalPackages(
174
69
  export function buildRuntimeConfig(
175
70
  bosConfig: BosConfig,
176
71
  options: {
72
+ hostSource?: "local" | "remote";
177
73
  uiSource?: "local" | "remote";
178
74
  apiSource?: "local" | "remote";
179
75
  authSource?: "local" | "remote";
180
- hostUrl: string;
181
76
  proxy?: string;
182
77
  env?: "development" | "production";
183
78
  plugins?: Record<string, RuntimePluginConfig>;
184
79
  },
185
80
  ): RuntimeConfig {
186
81
  const configDir = getProjectRoot();
82
+ const hostConfig = bosConfig.app.host;
187
83
  const uiConfig = bosConfig.app.ui;
188
84
  const apiConfig = bosConfig.app.api;
189
85
  const authConfig = bosConfig.app.auth;
190
- const uiSource = options.uiSource ?? "local";
191
- const apiSource = options.apiSource ?? "local";
192
- const authSource = options.authSource ?? "local";
193
- const uiLocalPath = resolveLocalDevelopmentPath(uiConfig.development, configDir);
194
- const apiLocalPath = resolveLocalDevelopmentPath(apiConfig.development, configDir);
195
- const authLocalPath = authConfig
196
- ? resolveLocalDevelopmentPath(authConfig.development, configDir)
197
- : null;
198
- const uiLocalUrl =
199
- !uiLocalPath && uiConfig.development && !isLocalDevelopmentTarget(uiConfig.development)
200
- ? uiConfig.development
201
- : "";
202
- const apiLocalUrl =
203
- !apiLocalPath && apiConfig.development && !isLocalDevelopmentTarget(apiConfig.development)
204
- ? apiConfig.development
205
- : "";
206
- const authLocalUrl =
207
- authConfig &&
208
- !authLocalPath &&
209
- authConfig.development &&
210
- !isLocalDevelopmentTarget(authConfig.development)
211
- ? authConfig.development
212
- : "";
86
+
87
+ function resolveDevelopmentEntry(
88
+ entry: { development?: string; production?: string },
89
+ preferredSource: "local" | "remote",
90
+ ): { source: "local" | "remote"; url: string; localPath?: string; port?: number } {
91
+ if (preferredSource === "remote") {
92
+ return { source: "remote", url: entry.production ?? "" };
93
+ }
94
+
95
+ const localPath = resolveLocalDevelopmentPath(entry.development, configDir);
96
+ if (localPath && existsSync(localPath)) {
97
+ return { source: "local", url: "", localPath };
98
+ }
99
+
100
+ const devUrl =
101
+ entry.development && !isLocalDevelopmentTarget(entry.development)
102
+ ? entry.development.replace(/\/$/, "")
103
+ : null;
104
+ if (devUrl) {
105
+ return { source: "local", url: devUrl, port: parsePort(devUrl) };
106
+ }
107
+
108
+ return { source: "remote", url: entry.production ?? "" };
109
+ }
110
+
111
+ const hostEntry = resolveDevelopmentEntry(hostConfig, options.hostSource ?? "local");
112
+ const uiEntry = resolveDevelopmentEntry(uiConfig, options.uiSource ?? "local");
113
+ const apiEntry = resolveDevelopmentEntry(apiConfig, options.apiSource ?? "local");
114
+ const authEntry = authConfig
115
+ ? resolveDevelopmentEntry(authConfig, options.authSource ?? "local")
116
+ : undefined;
117
+
118
+ const hostUrl = `http://localhost:${DEFAULT_HOST_PORT}`;
213
119
 
214
120
  return {
215
121
  env: options.env ?? "development",
216
122
  account: bosConfig.account,
217
123
  domain: bosConfig.domain,
218
124
  networkId: getNetworkIdForAccount(bosConfig.account),
219
- hostUrl: options.hostUrl,
125
+ host: {
126
+ name: "host",
127
+ url: hostUrl,
128
+ entry: `${hostUrl}/mf-manifest.json`,
129
+ localPath: hostEntry.localPath,
130
+ port: hostEntry.port ?? DEFAULT_HOST_PORT,
131
+ secrets: hostConfig.secrets,
132
+ integrity: hostEntry.source === "remote" ? hostConfig.integrity : undefined,
133
+ source: hostEntry.source,
134
+ remoteUrl: hostEntry.source === "remote" ? hostEntry.url : undefined,
135
+ },
220
136
  shared: bosConfig.shared,
221
137
  ui: uiConfig
222
138
  ? {
223
139
  name: uiConfig.name,
224
- url: uiSource === "remote" ? (uiConfig.production ?? "") : uiLocalUrl,
225
- entry:
226
- uiSource === "remote"
227
- ? `${uiConfig.production ?? ""}/mf-manifest.json`
228
- : uiLocalUrl
229
- ? `${uiLocalUrl}/mf-manifest.json`
230
- : "/mf-manifest.json",
231
- localPath: uiSource === "local" ? (uiLocalPath ?? undefined) : undefined,
232
- port: uiSource === "local" && uiLocalUrl ? parsePort(uiLocalUrl) : undefined,
233
- ssrUrl: uiSource === "remote" ? uiConfig.ssr : undefined,
234
- ssrIntegrity: uiSource === "remote" ? uiConfig.ssrIntegrity : undefined,
235
- integrity: uiSource === "remote" ? uiConfig.integrity : undefined,
236
- source: uiSource === "local" ? (uiLocalPath ? "local" : "remote") : "remote",
140
+ url: uiEntry.url,
141
+ entry: uiEntry.url ? `${uiEntry.url}/mf-manifest.json` : "/mf-manifest.json",
142
+ localPath: uiEntry.localPath,
143
+ port: uiEntry.port,
144
+ ssrUrl: uiEntry.source === "remote" ? uiConfig.ssr : undefined,
145
+ ssrIntegrity: uiEntry.source === "remote" ? uiConfig.ssrIntegrity : undefined,
146
+ integrity: uiEntry.source === "remote" ? uiConfig.integrity : undefined,
147
+ source: uiEntry.source,
237
148
  }
238
149
  : {
239
150
  name: "ui",
240
151
  url: "",
241
152
  entry: "/mf-manifest.json",
242
- source: uiSource,
153
+ source: uiEntry.source,
243
154
  },
244
155
  api: apiConfig
245
156
  ? {
246
157
  name: apiConfig.name,
247
- url: apiSource === "remote" ? (apiConfig.production ?? "") : apiLocalUrl,
248
- entry:
249
- apiSource === "remote"
250
- ? `${apiConfig.production ?? ""}/mf-manifest.json`
251
- : apiLocalUrl
252
- ? `${apiLocalUrl}/mf-manifest.json`
253
- : "/mf-manifest.json",
254
- localPath: apiSource === "local" ? (apiLocalPath ?? undefined) : undefined,
255
- port: apiSource === "local" && apiLocalUrl ? parsePort(apiLocalUrl) : undefined,
256
- source: apiSource === "local" ? (apiLocalPath ? "local" : "remote") : "remote",
158
+ url: apiEntry.url,
159
+ entry: apiEntry.url ? `${apiEntry.url}/mf-manifest.json` : "/mf-manifest.json",
160
+ localPath: apiEntry.localPath,
161
+ port: apiEntry.port,
162
+ source: apiEntry.source,
257
163
  proxy: options.proxy ?? apiConfig.proxy,
258
164
  variables: apiConfig.variables,
259
165
  secrets: apiConfig.secrets,
260
- integrity: apiSource === "remote" ? apiConfig.integrity : undefined,
166
+ integrity: apiEntry.source === "remote" ? apiConfig.integrity : undefined,
261
167
  }
262
168
  : {
263
169
  name: "api",
264
170
  url: "",
265
171
  entry: "/mf-manifest.json",
266
- source: apiSource,
172
+ source: apiEntry.source,
267
173
  },
268
- auth: authConfig
269
- ? {
270
- name: resolvePluginRuntimeName(
271
- undefined,
272
- authSource === "local" ? (authLocalPath ?? undefined) : undefined,
273
- authConfig.name,
274
- ),
275
- url: authSource === "remote" ? (authConfig.production ?? "") : authLocalUrl,
276
- entry:
277
- authSource === "remote"
278
- ? `${authConfig.production ?? ""}/mf-manifest.json`
279
- : authLocalUrl
280
- ? `${authLocalUrl}/mf-manifest.json`
281
- : "/mf-manifest.json",
282
- localPath: authSource === "local" ? (authLocalPath ?? undefined) : undefined,
283
- port: authSource === "local" && authLocalUrl ? parsePort(authLocalUrl) : undefined,
284
- source: authSource === "local" ? (authLocalPath ? "local" : "remote") : "remote",
285
- proxy: authConfig.proxy,
286
- variables: authConfig.variables,
287
- secrets: authConfig.secrets,
288
- integrity: authSource === "remote" ? authConfig.integrity : undefined,
289
- }
290
- : undefined,
174
+ auth:
175
+ authEntry && authConfig
176
+ ? {
177
+ name: resolvePluginRuntimeName(undefined, authEntry.localPath, authConfig.name),
178
+ url: authEntry.url,
179
+ entry: authEntry.url ? `${authEntry.url}/mf-manifest.json` : "/mf-manifest.json",
180
+ localPath: authEntry.localPath,
181
+ port: authEntry.port,
182
+ source: authEntry.source,
183
+ proxy: authConfig.proxy,
184
+ variables: authConfig.variables,
185
+ secrets: authConfig.secrets,
186
+ integrity: authEntry.source === "remote" ? authConfig.integrity : undefined,
187
+ }
188
+ : undefined,
291
189
  plugins: options.plugins,
292
190
  };
293
191
  }
@@ -339,21 +237,27 @@ export async function prepareDevelopmentRuntimeConfig(
339
237
  options?: { hostPort?: number; ssr?: boolean },
340
238
  ): Promise<RuntimeConfig> {
341
239
  const usedPorts = new Set<number>();
342
- const hostPort = await pickAvailablePort(
343
- options?.hostPort ??
344
- (runtimeConfig.hostUrl ? parsePort(runtimeConfig.hostUrl) : DEFAULT_HOST_PORT),
345
- usedPorts,
346
- );
240
+ const hostPort = await pickAvailablePort(options?.hostPort ?? DEFAULT_HOST_PORT, usedPorts);
347
241
 
348
242
  const next: RuntimeConfig = {
349
243
  ...runtimeConfig,
350
- hostUrl: `http://localhost:${hostPort}`,
244
+ host: { ...runtimeConfig.host, url: `http://localhost:${hostPort}`, port: hostPort },
351
245
  ui: { ...runtimeConfig.ui },
352
246
  api: { ...runtimeConfig.api },
353
247
  auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : undefined,
354
248
  plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : undefined,
355
249
  };
356
250
 
251
+ if (next.api.source === "local" && next.api.localPath) {
252
+ const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);
253
+ next.api = withLocalRuntimeUrl(next.api, apiPort);
254
+ }
255
+
256
+ if (next.auth?.source === "local" && next.auth.localPath) {
257
+ const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);
258
+ next.auth = withLocalRuntimeUrl(next.auth, authPort);
259
+ }
260
+
357
261
  if (next.ui.source === "local" && next.ui.localPath) {
358
262
  const uiPort = await pickAvailablePort(next.ui.port ?? DEFAULT_UI_PORT, usedPorts);
359
263
  next.ui = withLocalRuntimeUrl(next.ui, uiPort);
@@ -365,11 +269,6 @@ export async function prepareDevelopmentRuntimeConfig(
365
269
  }
366
270
  }
367
271
 
368
- if (next.api.source === "local" && next.api.localPath) {
369
- const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);
370
- next.api = withLocalRuntimeUrl(next.api, apiPort);
371
- }
372
-
373
272
  if (next.plugins) {
374
273
  const entries = Object.entries(next.plugins).sort(([a], [b]) => a.localeCompare(b));
375
274
  let pluginBasePort = DEFAULT_PLUGIN_PORT_START;
@@ -385,10 +284,5 @@ export async function prepareDevelopmentRuntimeConfig(
385
284
  }
386
285
  }
387
286
 
388
- if (next.auth?.source === "local" && next.auth.localPath) {
389
- const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);
390
- next.auth = withLocalRuntimeUrl(next.auth, authPort);
391
- }
392
-
393
287
  return next;
394
288
  }
@@ -56,7 +56,11 @@ function bumpDepField(
56
56
  return true;
57
57
  }
58
58
 
59
- function bumpCatalog(catalog: Record<string, string> | undefined, packageName: string, newVersion: string): boolean {
59
+ function bumpCatalog(
60
+ catalog: Record<string, string> | undefined,
61
+ packageName: string,
62
+ newVersion: string,
63
+ ): boolean {
60
64
  if (!catalog) return false;
61
65
  if (!(packageName in catalog)) return false;
62
66
  const current = catalog[packageName];
@@ -70,7 +74,11 @@ interface BumpResult {
70
74
  fields: string[];
71
75
  }
72
76
 
73
- function bumpPackageJson(pkg: Record<string, unknown>, packageName: string, newVersion: string): BumpResult {
77
+ function bumpPackageJson(
78
+ pkg: Record<string, unknown>,
79
+ packageName: string,
80
+ newVersion: string,
81
+ ): BumpResult {
74
82
  const fields: string[] = [];
75
83
 
76
84
  for (const fieldName of ["dependencies", "devDependencies", "peerDependencies"] as const) {
@@ -88,7 +96,11 @@ function bumpPackageJson(pkg: Record<string, unknown>, packageName: string, newV
88
96
  return { modified: fields.length > 0, fields };
89
97
  }
90
98
 
91
- function updatePackageVersionInFile(filePath: string, packageName: string, newVersion: string): boolean {
99
+ function updatePackageVersionInFile(
100
+ filePath: string,
101
+ packageName: string,
102
+ newVersion: string,
103
+ ): boolean {
92
104
  const pkg = JSON.parse(readFileSync(filePath, "utf-8")) as Record<string, unknown>;
93
105
  const result = bumpPackageJson(pkg, packageName, newVersion);
94
106
  if (result.modified) {
@@ -97,7 +109,11 @@ function updatePackageVersionInFile(filePath: string, packageName: string, newVe
97
109
  return result.modified;
98
110
  }
99
111
 
100
- function updatePackageVersion(projectDir: string, packageName: string, newVersion: string): boolean {
112
+ function updatePackageVersion(
113
+ projectDir: string,
114
+ packageName: string,
115
+ newVersion: string,
116
+ ): boolean {
101
117
  return updatePackageVersionInFile(join(projectDir, "package.json"), packageName, newVersion);
102
118
  }
103
119
 
@@ -91,7 +91,10 @@ function ProcessRow({
91
91
  sourceWidth: number;
92
92
  }) {
93
93
  const color = getServiceColor(proc.name);
94
- const portStr = proc.port > 0 ? `:${proc.port}` : "";
94
+ const isRemote = proc.source === "remote";
95
+ const isHost = proc.name === "host";
96
+ const showPort = proc.port > 0 && (isHost || !isRemote);
97
+ const portStr = showPort ? `:${proc.port}` : "";
95
98
  const sourceLabel = proc.source ? ` (${proc.source})` : "";
96
99
 
97
100
  const statusText =
@@ -100,7 +103,9 @@ function ProcessRow({
100
103
  : proc.status === "starting"
101
104
  ? "starting"
102
105
  : proc.status === "ready"
103
- ? "running"
106
+ ? isRemote && !isHost
107
+ ? "loaded"
108
+ : "running"
104
109
  : "failed";
105
110
 
106
111
  return (
@@ -113,7 +118,7 @@ function ProcessRow({
113
118
  </Text>
114
119
  <Text color="gray">{sourceLabel.padEnd(sourceWidth)}</Text>
115
120
  <Text color={proc.status === "ready" ? "#00ff41" : "gray"}>{statusText}</Text>
116
- {proc.port > 0 && <Text color="#00ffff"> {portStr}</Text>}
121
+ {showPort && <Text color="#00ffff"> {portStr}</Text>}
117
122
  </Box>
118
123
  );
119
124
  }
@@ -131,15 +131,20 @@ export function renderStreamingView(
131
131
  const icon = getStatusIcon(status);
132
132
  const displayName = getDisplayName(name).padEnd(columnWidths.name);
133
133
  const sourceLabel = proc?.source ? ` (${proc.source})` : "";
134
+ const isRemote = proc?.source === "remote";
135
+ const isHost = name === "host";
136
+ const showPort = proc.port > 0 && (isHost || !isRemote) && status === "ready";
134
137
  const statusText =
135
138
  status === "ready"
136
- ? "ready"
139
+ ? isRemote && !isHost
140
+ ? "loaded"
141
+ : "running"
137
142
  : status === "starting"
138
143
  ? "starting"
139
144
  : status === "error"
140
145
  ? "failed"
141
146
  : "waiting";
142
- const portStr = proc.port > 0 && status === "ready" ? ` :${proc.port}` : "";
147
+ const portStr = showPort ? ` :${proc.port}` : "";
143
148
 
144
149
  write(
145
150
  `${colors.dim(`[${getTimestamp()}]`)} ${color(`[${displayName}]`)} ${status === "ready" ? colors.green(icon) : status === "error" ? colors.error(icon) : icon} ${statusText}${sourceLabel.padEnd(columnWidths.source)}${portStr}`,