everything-dev 1.7.1 → 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.
- 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 +70 -10
- package/dist/cli/upgrade.cjs.map +1 -1
- package/dist/cli/upgrade.mjs +71 -11
- 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 +14 -6
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +14 -6
- 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 +19 -5
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +19 -5
- 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 +18 -3
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +18 -3
- 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 +113 -13
- 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
|
@@ -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
|
|
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
|
|
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
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const DEFAULT_PLUGIN_PORT_START =
|
|
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 =
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
: "";
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
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:
|
|
225
|
-
entry:
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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:
|
|
153
|
+
source: uiEntry.source,
|
|
243
154
|
},
|
|
244
155
|
api: apiConfig
|
|
245
156
|
? {
|
|
246
157
|
name: apiConfig.name,
|
|
247
|
-
url:
|
|
248
|
-
entry:
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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:
|
|
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:
|
|
172
|
+
source: apiEntry.source,
|
|
267
173
|
},
|
|
268
|
-
auth:
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
undefined,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
-
|
|
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
|
}
|
package/src/cli/upgrade.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { glob } from "glob";
|
|
3
4
|
import type { UpgradeOptions, UpgradeResult } from "../contract";
|
|
4
5
|
import { runBunInstall } from "./init";
|
|
5
6
|
import { syncTemplate } from "./sync";
|
|
@@ -35,25 +36,115 @@ function readInstalledVersion(projectDir: string, packageName: string): string |
|
|
|
35
36
|
return version.replace(/^[\^~>=]+/, "");
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
function isBumpedableVersion(value: string | undefined): boolean {
|
|
40
|
+
if (!value) return false;
|
|
41
|
+
if (value === "workspace:*") return false;
|
|
42
|
+
if (value.startsWith("catalog:")) return false;
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function bumpDepField(
|
|
47
|
+
field: Record<string, string> | undefined,
|
|
48
|
+
packageName: string,
|
|
49
|
+
newVersion: string,
|
|
50
|
+
): boolean {
|
|
51
|
+
if (!field) return false;
|
|
52
|
+
if (!(packageName in field)) return false;
|
|
53
|
+
const current = field[packageName];
|
|
54
|
+
if (!isBumpedableVersion(current)) return false;
|
|
55
|
+
field[packageName] = `^${newVersion}`;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function bumpCatalog(
|
|
60
|
+
catalog: Record<string, string> | undefined,
|
|
61
|
+
packageName: string,
|
|
62
|
+
newVersion: string,
|
|
63
|
+
): boolean {
|
|
64
|
+
if (!catalog) return false;
|
|
65
|
+
if (!(packageName in catalog)) return false;
|
|
66
|
+
const current = catalog[packageName];
|
|
67
|
+
if (!isBumpedableVersion(current)) return false;
|
|
68
|
+
catalog[packageName] = `^${newVersion}`;
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
41
71
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
72
|
+
interface BumpResult {
|
|
73
|
+
modified: boolean;
|
|
74
|
+
fields: string[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function bumpPackageJson(
|
|
78
|
+
pkg: Record<string, unknown>,
|
|
79
|
+
packageName: string,
|
|
80
|
+
newVersion: string,
|
|
81
|
+
): BumpResult {
|
|
82
|
+
const fields: string[] = [];
|
|
83
|
+
|
|
84
|
+
for (const fieldName of ["dependencies", "devDependencies", "peerDependencies"] as const) {
|
|
85
|
+
const field = pkg[fieldName] as Record<string, string> | undefined;
|
|
86
|
+
if (bumpDepField(field, packageName, newVersion)) {
|
|
87
|
+
fields.push(fieldName);
|
|
46
88
|
}
|
|
47
89
|
}
|
|
48
90
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
91
|
+
const workspaces = pkg.workspaces as { catalog?: Record<string, string> } | undefined;
|
|
92
|
+
if (workspaces?.catalog && bumpCatalog(workspaces.catalog, packageName, newVersion)) {
|
|
93
|
+
fields.push("workspaces.catalog");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { modified: fields.length > 0, fields };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function updatePackageVersionInFile(
|
|
100
|
+
filePath: string,
|
|
101
|
+
packageName: string,
|
|
102
|
+
newVersion: string,
|
|
103
|
+
): boolean {
|
|
104
|
+
const pkg = JSON.parse(readFileSync(filePath, "utf-8")) as Record<string, unknown>;
|
|
105
|
+
const result = bumpPackageJson(pkg, packageName, newVersion);
|
|
106
|
+
if (result.modified) {
|
|
107
|
+
writeFileSync(filePath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
108
|
+
}
|
|
109
|
+
return result.modified;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function updatePackageVersion(
|
|
113
|
+
projectDir: string,
|
|
114
|
+
packageName: string,
|
|
115
|
+
newVersion: string,
|
|
116
|
+
): boolean {
|
|
117
|
+
return updatePackageVersionInFile(join(projectDir, "package.json"), packageName, newVersion);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function findWorkspacePackageJsons(projectDir: string): Promise<string[]> {
|
|
121
|
+
const rootPkgPath = join(projectDir, "package.json");
|
|
122
|
+
if (!existsSync(rootPkgPath)) return [];
|
|
123
|
+
|
|
124
|
+
const rootPkg = JSON.parse(readFileSync(rootPkgPath, "utf-8")) as Record<string, unknown>;
|
|
125
|
+
const workspaceConfig = rootPkg.workspaces as { packages?: string[] } | string[] | undefined;
|
|
126
|
+
|
|
127
|
+
const patterns: string[] = [];
|
|
128
|
+
if (Array.isArray(workspaceConfig)) {
|
|
129
|
+
patterns.push(...workspaceConfig);
|
|
130
|
+
} else if (workspaceConfig?.packages && Array.isArray(workspaceConfig.packages)) {
|
|
131
|
+
patterns.push(...workspaceConfig.packages);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (patterns.length === 0) return [];
|
|
135
|
+
|
|
136
|
+
const pkgPaths: string[] = [];
|
|
137
|
+
for (const pattern of patterns) {
|
|
138
|
+
const matches = await glob(pattern, { cwd: projectDir, dot: false, absolute: false });
|
|
139
|
+
for (const match of matches) {
|
|
140
|
+
const pkgPath = join(projectDir, match, "package.json");
|
|
141
|
+
if (existsSync(pkgPath) && statSync(pkgPath).isFile()) {
|
|
142
|
+
pkgPaths.push(pkgPath);
|
|
143
|
+
}
|
|
53
144
|
}
|
|
54
145
|
}
|
|
55
146
|
|
|
56
|
-
|
|
147
|
+
return [...new Set(pkgPaths)];
|
|
57
148
|
}
|
|
58
149
|
|
|
59
150
|
function buildChangelogUrl(
|
|
@@ -130,6 +221,15 @@ export async function upgradeTemplate(
|
|
|
130
221
|
}
|
|
131
222
|
}
|
|
132
223
|
|
|
224
|
+
const workspacePkgPaths = await findWorkspacePackageJsons(projectDir);
|
|
225
|
+
for (const pkgPath of workspacePkgPaths) {
|
|
226
|
+
for (const pkg of packages) {
|
|
227
|
+
if (pkg.from !== undefined && pkg.from !== pkg.to) {
|
|
228
|
+
updatePackageVersionInFile(pkgPath, pkg.name, pkg.to);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
133
233
|
if (hasUpdates && !options.noInstall) {
|
|
134
234
|
await runBunInstall(projectDir);
|
|
135
235
|
}
|