@guanjinke/artifact-client 1.14.0 → 1.14.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/README.md CHANGED
@@ -1,219 +1,222 @@
1
- # @guanjinke/artifact-client
2
-
3
- Upload, browse and download build artifacts on **Azure Blob Storage** and **Aliyun OSS**, and build and manage local **Wyn environments** from those artifacts.
4
-
5
- Requires Node.js >= 20. `az` commands talk to Azure, `oss` commands to Aliyun OSS; below they are interchangeable unless noted.
6
-
7
- ## Install
8
-
9
- ```bash
10
- npm install -g @guanjinke/artifact-client
11
- afm --version
12
- ```
13
-
14
- ## Credentials
15
-
16
- ```bash
17
- afm az login --sasurl "https://<account>.blob.core.windows.net/<container>?<SAS>"
18
- afm oss login --keyid <id> --key <secret> --bucket <bucket> [--region oss-cn-hangzhou]
19
-
20
- # or pass them inline on any command: --sasurl, --keyid/--key/--bucket/--region
21
- afm az list-plugins --sasurl "https://..."
22
-
23
- afm az config show # print the saved credentials
24
- afm az config clear # remove them
25
- ```
26
-
27
- Saved settings live in `~/.afm/config.json`; set `AFM_CONFIG_DIR` to use another directory.
28
-
29
- ## Browse artifacts
30
-
31
- ```bash
32
- afm az list-plugins [--size]
33
- afm az list-majors <plugin> [--size] [--sort asc|desc]
34
- afm az get-latest <plugin> <major> [--size] [--no-verify]
35
- afm az list-minors <plugin> <major> [--size] [--sort asc|desc]
36
- afm az list-artifacts <plugin> <version> [--size]
37
- ```
38
-
39
- A **major** (`9.1`, `9.0`, `9.1-hotfix1`, `9.1-oem`, `dev`, ...) is a product label, not an artifact version. Each major owns a version file (`version9.1.txt`, `versiondev.txt`) that records the version it currently points at; `get-latest` reads it and warns on stderr when that version no longer holds artifacts (`--no-verify` skips the check).
40
-
41
- ## Upload
42
-
43
- ```bash
44
- # Write the file into the version directory (major pointers untouched)
45
- afm az upload <plugin> <version> <artifact-name> <local-file>
46
-
47
- # ... and record it as the latest of a major in the same step
48
- afm az upload <plugin> <version> <artifact-name> <local-file> --set-latest --major 9.1
49
-
50
- # Or move a major separately
51
- afm az set-latest <plugin> <major> <version> [--no-verify]
52
- ```
53
-
54
- Uploading and moving a major are deliberately separate: a hotfix upload cannot accidentally move `version9.1.txt`.
55
-
56
- ## Download
57
-
58
- ```bash
59
- afm az download --path "<full/storage/path>" [--out ./dir]
60
- afm az download --plugin <plugin> --ver <version> --file <name> [--out ./dir]
61
- afm az download --plugin <plugin> --ver <version> --all [--out ./dir]
62
- afm az download --plugin <plugin> --major <major> [--file <name>] [--out ./dir]
63
- ```
64
-
65
- `--major` resolves that major's latest version first, so `--all` is implied; `--major` and `--ver` are mutually exclusive. Artifacts keep their sub-directory: `extras/X.dll` is written to `<out>/extras/X.dll`.
66
-
67
- ## Local Wyn environments (Windows)
68
-
69
- The artifacts and the tool are cross-platform: runtime packages ship the RID assets for every platform they support (`runtimes/{linux*, osx, unix, win*}`, with `libSkiaSharp.so`/`.dylib`/`.dll` per platform), and an assembled environment is configured for the host it is built on — `Wyn.conf` uses that platform's path separators, and `Monitor/conf` is a junction on Windows or a directory symlink elsewhere. Which `runtimes/<rid>/native` variant is loaded is decided by the .NET runtime from the whole copied directory; the tool never selects a CPU architecture and never targets 32-bit Windows (`win32` is Node's name for Windows on x64, x86 and arm64 alike — the architecture is `process.arch`). `oss`/`az` only decide where the artifacts come from.
70
-
71
- ```bash
72
- # Optionally pick one directory for every environment (stored in config.json)
73
- afm env root D:\wyn-envs # validate, create if missing, remember
74
- afm env root # print it
75
- afm env root --json # { configured, root, exists, configPath }
76
- afm env root --unset
77
-
78
- # Assemble a fresh embedded environment (nothing is started or registered as a Windows service)
79
- afm oss create-env D:\wyn-envs\demo --name demo --major 9.1 \
80
- [--modules dashboard reporting] [--edition en] [--port 51980] [--dry-run]
81
-
82
- # With a configured environment root the path can be omitted
83
- afm oss create-env --name demo --major 9.1
84
- ```
85
-
86
- Server, Monitor, Account, Dataset, AnalysisModel and CotWorker are always included. `--modules` is edition-scoped: **CN** offers `dashboard`, `reporting` and `data-monitoring`, **EN** additionally offers `sheets` and `documents` (smart documents, which pulls in the collaboration service it needs). Without `--port` the first free port in `51900`-`51980` is used; an explicit `--port` is used as given and fails on a conflict. `--dry-run` resolves everything and writes nothing. The result warns when the Server package ships no XSD for the detected configuration schema.
87
-
88
- ```bash
89
- afm env list [--json] # state, port, edition, major, root, local overrides, PID
90
- afm env start <name> [--foreground|--background]
91
- afm env stop <name>
92
- afm env restart <name> [--foreground|--background]
93
- afm env delete <name> [--yes]
94
- ```
95
-
96
- * Background output is appended to `<root>\logs\server.stdout.log` and `server.stderr.log`.
97
- * `running` means the monitor process is alive — not that Wyn finished starting or that the port answers.
98
- * A stopped environment keeps its reserved port and name; nothing is reassigned automatically.
99
- * `delete` stops the environment, then removes its directory and its registry record; `--yes` is required when stdin is not a terminal.
100
- * Environments are listed from `~/.afm/environments.json` (`AFM_CONFIG_DIR` for another profile).
101
-
102
- ## Update the modules of an environment
103
-
104
- ```bash
105
- afm oss update-env <name> --modules dashboard # latest for the recorded major
106
- afm oss update-env <name> --modules dashboard:0.1.12345 # pinned version
107
- afm oss update-env <name> --modules dashboard=D:\build\Wyn.Dashboards.Plugin.dll
108
- afm oss update-env <name> --modules all # every installed module except local ones
109
- afm oss update-env <name> --modules dashboard --dry-run
110
- ```
111
-
112
- Remote updates download, verify (SHA256 + archive checks) and replace the deployed files; the environment must be observed `ready` or `stopped` (`running`/`unknown` is refused — stop it first). A **local source copies nothing** for plugins: the deployed `Plugins\<module>` directory is removed and `conf\Wyn.conf` is pointed straight at your build, so the Server loads it; restart the environment to load the change. Modules that were never installed are installed. `--modules` is required — name `all` or one or more modules.
113
-
114
- The **Server** is the exception: `--modules server=<build directory>` records a local Server build output, and `env start`/`env restart` copy it over the environment's `Server\` directory on every start (the environment's own `Server\appsettings.json` is kept). After the copy, the built-in payloads that live inside `Server\` are re-applied **from a local cache** — a start never downloads, and a missing cache entry is refused with the command that refreshes it. Because the copied build decides the runtime file versions, run `afm oss|az update-env <name> --modules all` once after a build whose dependencies changed: it refreshes the installed payloads from the recorded build directory and stores them in that cache. A remote `update-env <name> --modules server` deploys the published package again and clears the local source.
115
-
116
- **Every module can be refreshed, the core components included** — `server`, `monitoring`, `common`, `analysis`, `dashboard`, `reporting`, `data-monitoring`, `sheets`, `documents` and `collaboration` all go through the same path, and `all` covers them together (skipping the ones that have a local source). Refreshing `server` or `monitoring` is checked like a create: the package must ship the runtime assemblies and settings its service needs (the Server's required runtime files, and `Wyn.Configuration.dll` plus `appsettings.json` for the Monitor) and the `xsd/<schema>/Wyn.conf.xsd` for the configuration schema the environment already declares — a Monitor package without it is refused, a Server package without it only warns, because Wyn's configuration reader falls back to ordinary XML deserialization. Refresh the two in the same call when you can: they ship the schema assets for the same configuration, and a single-sided refresh is reported as a warning. The environment's own `Server\appsettings.json` is kept across the replacement (the Server package never deploys one), the Monitor's `conf` assets are merged into `conf\` and the `Monitor/conf` junction is recreated. A local source is refused for `monitoring` and `collaboration`: they are whole services, refreshed from artifacts only. `sheets` and `documents` still require an EN edition environment.
117
-
118
- A module can own several assemblies (`gces-common` = two plugins + one worker; `dashboard`/`reporting` = plugin + worker), so local sources resolve per assembly:
119
-
120
- | Spec | Selects |
121
- |---|---|
122
- | `dashboard=D:\build\Wyn.Dashboards.Plugin.dll` | the target whose file name matches |
123
- | `dashboard=D:\build\out` | every assembly of that module found in the directory |
124
- | `dashboard#Wyn.Dashboards.Worker.dll=D:\build\worker.dll` | that target explicitly |
125
- | repeated `common=` specs | one target each, as long as no target is selected twice |
126
-
127
- ```bash
128
- afm oss update-env demo --modules \
129
- common=D:\gces-common\src\Wyn.Dataset.Plugin\bin\release\net8.0\Wyn.Dataset.Plugin.dll \
130
- common=D:\gces-common\src\Wyn.Account.Plugin\bin\release\net8.0\Wyn.Account.Plugin.dll \
131
- common=D:\gces-common\src\Wyn.CotWorker\bin\release\net8.0\Wyn.CotWorker.dll
132
- ```
133
-
134
- The override is recorded in the environment manifest (`moduleSources`) and shown by `env list` in a `local` column; switching the module back to a remote spec deletes the override and restores the deployed files.
135
-
136
- ## Apply a local build while starting
137
-
138
- ```bash
139
- afm env start demo --background --modules dashboard=D:\build\Wyn.Dashboards.Plugin.dll
140
- afm env restart demo --modules common=D:\build\common,common#Wyn.CotWorker.dll=D:\build\Wyn.CotWorker.dll
141
- ```
142
-
143
- Same specs as `update-env`, but only local sources are accepted here (`env` has no cloud provider — use `update-env` for artifacts). `start` applies the override and then starts; `restart` stops, applies and starts again, which is the usual "rebuild, then reload" loop.
144
-
145
- ## Local web interface
146
-
147
- ```bash
148
- afm web # 127.0.0.1, OS-assigned port, opens your browser
149
- afm web --port 4599 # fixed port
150
- afm web --token <secret> # reuse your own token instead of a generated one (>= 16 characters)
151
- afm web --no-open # print the URL only
152
- ```
153
-
154
- The page lists the registered environments — one row each, with its site link (`http://localhost:<port>`), a **复制** button for that address and a **打开目录** button that reveals the environment root in Explorer (Windows), Finder (macOS) or `xdg-open` (Linux) — and can create, start, stop, restart and delete them and update their modules. The create form and the update panel default to the **`oss`** provider, falling back to `az` only when OSS has no stored credentials, and the optional-module list follows the selected edition (CN: `dashboard`, `reporting`; EN: those plus `sheets` and `documents`). Creating and updating use the same code paths as `create-env`/`update-env`, including `--dry-run`. The 设置 dialog writes the same local profile the CLI uses, so a machine without a terminal session can still be prepared: the **environment root** (like `afm env root <path>`) and the **az/oss credentials** (like `afm az login` / `afm oss login`). Credentials are send-only — the page shows whether a provider is configured, never the SAS URL or the key.
155
-
156
- ```json
157
- {
158
- "host": "127.0.0.1",
159
- "port": 4599,
160
- "url": "http://127.0.0.1:4599/",
161
- "tokenUrl": "http://127.0.0.1:4599/#token=<token>",
162
- "token": "<token>"
163
- }
164
- ```
165
-
166
- * **Loopback only.** The listener binds `127.0.0.1`; there is no option to expose it.
167
- * **Token on every request.** The page reads the token from the URL fragment (which browsers never send to the server), keeps it in `sessionStorage` and sends it as `X-AFM-Token`. `Authorization: Bearer <token>` also works. Comparisons are constant-time.
168
- * **Host and origin checks.** A request whose `Host` header is not `127.0.0.1:<port>` or `localhost:<port>` is refused (DNS rebinding), and no CORS header is ever sent, so another page cannot read a reply or send the token header. The page is served with a strict `Content-Security-Policy`.
169
- * **Long operations are jobs.** Create/update/delete/start/stop/restart answer `202` with a job id; the page polls `GET /api/jobs/<id>`. Mutations of one environment are serialized (a second request waits as `queued`), and the first `Ctrl+C` waits for running jobs before stopping so an interrupted `create-env` does not leave a reservation behind.
170
- * **Start always uses background mode** from the page — a foreground monitor would own the terminal the web server runs in. Use the CLI when you want foreground output.
171
- * Deleting from the page requires typing the environment name; it stops the verified monitor and removes the directory and the registry record, exactly like `env delete`.
172
-
173
- ## Library
174
-
175
-
176
- ```ts
177
- import { ArtifactClient, buildEnvironmentPlan, executeEnvironmentPlan } from '@guanjinke/artifact-client';
178
-
179
- const client = new ArtifactClient('oss', { keyId: 'id', key: 'secret', bucket: 'my-bucket' });
180
-
181
- await client.listPlugins({ includeSize: true });
182
- await client.listMajorVersions('myPlugin', { sortOrder: 'asc' });
183
- await client.getLatestVersion('gces-server', '9.1');
184
- await client.listArtifacts('gces-server', '9.1.21042', { includeSize: true });
185
- await client.uploadArtifact('myPlugin', '1.0.6', 'bundle.zip', './dist/bundle.zip');
186
- await client.updateLatestVersion('myPlugin', '9.1-hotfix1', '1.0.6');
187
- await client.downloadArtifact('myPlugin', '1.0.5', 'bundle.zip', './downloads');
188
- await client.downloadArtifactByPath('plugin_artifacts/myPlugin/1.0.5/bundle.zip', './downloads');
189
- const files = await client.downloadVersion('myPlugin', '1.0.5', './downloads');
190
-
191
- // Plan resolutely (no downloads or writes), then assemble and register an environment
192
- const plan = await buildEnvironmentPlan({ root: 'D:/wyn/demo', major: '9.1', modules: ['dashboard'] }, client);
193
- const result = await executeEnvironmentPlan(plan, { client });
194
- ```
195
-
196
- | Method | Description |
197
- |---|---|
198
- | `listPlugins(opts?)` | List plugins (optionally with total size) |
199
- | `listMajorVersions(plugin, opts?)` | Majors with the version each one points at |
200
- | `getLatestVersion(plugin, major, opts?)` | Version a major currently points at |
201
- | `listMinorVersions(plugin, major, opts?)` | Versions under a major |
202
- | `listArtifacts(plugin, version, opts?)` | Files of a version (optionally with sizes) |
203
- | `uploadArtifact(plugin, version, name, localPath)` | Upload one file into a version directory |
204
- | `updateLatestVersion(plugin, major, version)` | Move a major's latest pointer |
205
- | `downloadArtifactByPath(fullPath, localDir)` | Download by full storage path |
206
- | `downloadArtifact(plugin, version, fileName, localDir)` | Download by name |
207
- | `downloadVersion(plugin, version, localDir)` | Download every file of a version |
208
-
209
- `client` is a small typed interface, so tests can inject a stub. Assembly, planning, listing and lifecycle all work on Windows, Linux and macOS: lifecycle uses the Windows backend on Windows and a POSIX backend (`/proc` on Linux, `ps` on macOS) elsewhere. Running an environment never needs administrator rights; only the process-identity check touches privileges, because Windows withholds the command line and executable path of a process owned by another account (a SYSTEM `WynService`, for instance). Such a process is attributed to an environment only when it carries that environment's recorded monitor PID, and it is reported in `afm env list` instead of blocking a start.
210
-
211
- ## Notes
212
-
213
- * Stopping is a forced process-tree termination, not a graceful HTTP shutdown.
214
- * A missing or unknown process identity blocks start/stop/delete instead of guessing.
215
- * Version resolution never selects a different archive by size: only the exact expected file name is used.
216
-
217
- Design details, safety semantics and development notes live in the repository.
218
-
219
- MIT
1
+ # @guanjinke/artifact-client
2
+
3
+ Upload, browse and download build artifacts on **Azure Blob Storage** and **Aliyun OSS**, and build and manage local **Wyn environments** from those artifacts.
4
+
5
+ Requires Node.js >= 20. `az` commands talk to Azure, `oss` commands to Aliyun OSS; below they are interchangeable unless noted.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g @guanjinke/artifact-client
11
+ afm --version
12
+ ```
13
+
14
+ ## Credentials
15
+
16
+ ```bash
17
+ afm az login --sasurl "https://<account>.blob.core.windows.net/<container>?<SAS>"
18
+ afm oss login --keyid <id> --key <secret> [--bucket <bucket>] [--region oss-cn-hangzhou]
19
+
20
+ # `--bucket` and `--region` are optional: a blank value is stored as the CLI's
21
+ # built-in default, so the AccessKey pair alone is a complete OSS profile.
22
+
23
+ # or pass them inline on any command: --sasurl, --keyid/--key/--bucket/--region
24
+ afm az list-plugins --sasurl "https://..."
25
+
26
+ afm az config show # print the saved credentials
27
+ afm az config clear # remove them
28
+ ```
29
+
30
+ Saved settings live in `~/.afm/config.json`; set `AFM_CONFIG_DIR` to use another directory.
31
+
32
+ ## Browse artifacts
33
+
34
+ ```bash
35
+ afm az list-plugins [--size]
36
+ afm az list-majors <plugin> [--size] [--sort asc|desc]
37
+ afm az get-latest <plugin> <major> [--size] [--no-verify]
38
+ afm az list-minors <plugin> <major> [--size] [--sort asc|desc]
39
+ afm az list-artifacts <plugin> <version> [--size]
40
+ ```
41
+
42
+ A **major** (`9.1`, `9.0`, `9.1-hotfix1`, `9.1-oem`, `dev`, ...) is a product label, not an artifact version. Each major owns a version file (`version9.1.txt`, `versiondev.txt`) that records the version it currently points at; `get-latest` reads it and warns on stderr when that version no longer holds artifacts (`--no-verify` skips the check).
43
+
44
+ ## Upload
45
+
46
+ ```bash
47
+ # Write the file into the version directory (major pointers untouched)
48
+ afm az upload <plugin> <version> <artifact-name> <local-file>
49
+
50
+ # ... and record it as the latest of a major in the same step
51
+ afm az upload <plugin> <version> <artifact-name> <local-file> --set-latest --major 9.1
52
+
53
+ # Or move a major separately
54
+ afm az set-latest <plugin> <major> <version> [--no-verify]
55
+ ```
56
+
57
+ Uploading and moving a major are deliberately separate: a hotfix upload cannot accidentally move `version9.1.txt`.
58
+
59
+ ## Download
60
+
61
+ ```bash
62
+ afm az download --path "<full/storage/path>" [--out ./dir]
63
+ afm az download --plugin <plugin> --ver <version> --file <name> [--out ./dir]
64
+ afm az download --plugin <plugin> --ver <version> --all [--out ./dir]
65
+ afm az download --plugin <plugin> --major <major> [--file <name>] [--out ./dir]
66
+ ```
67
+
68
+ `--major` resolves that major's latest version first, so `--all` is implied; `--major` and `--ver` are mutually exclusive. Artifacts keep their sub-directory: `extras/X.dll` is written to `<out>/extras/X.dll`.
69
+
70
+ ## Local Wyn environments (Windows)
71
+
72
+ The artifacts and the tool are cross-platform: runtime packages ship the RID assets for every platform they support (`runtimes/{linux*, osx, unix, win*}`, with `libSkiaSharp.so`/`.dylib`/`.dll` per platform), and an assembled environment is configured for the host it is built on — `Wyn.conf` uses that platform's path separators, and `Monitor/conf` is a junction on Windows or a directory symlink elsewhere. Which `runtimes/<rid>/native` variant is loaded is decided by the .NET runtime from the whole copied directory; the tool never selects a CPU architecture and never targets 32-bit Windows (`win32` is Node's name for Windows on x64, x86 and arm64 alike — the architecture is `process.arch`). `oss`/`az` only decide where the artifacts come from.
73
+
74
+ ```bash
75
+ # Optionally pick one directory for every environment (stored in config.json)
76
+ afm env root D:\wyn-envs # validate, create if missing, remember
77
+ afm env root # print it
78
+ afm env root --json # { configured, root, exists, configPath }
79
+ afm env root --unset
80
+
81
+ # Assemble a fresh embedded environment (nothing is started or registered as a Windows service)
82
+ afm oss create-env D:\wyn-envs\demo --name demo --major 9.1 \
83
+ [--modules dashboard reporting] [--edition en] [--port 51980] [--dry-run]
84
+
85
+ # With a configured environment root the path can be omitted
86
+ afm oss create-env --name demo --major 9.1
87
+ ```
88
+
89
+ Server, Monitor, Account, Dataset, AnalysisModel and CotWorker are always included. `--modules` is edition-scoped: **CN** offers `dashboard`, `reporting` and `data-monitoring`, **EN** additionally offers `sheets` and `documents` (smart documents, which pulls in the collaboration service it needs). Without `--port` the first free port in `51900`-`51980` is used; an explicit `--port` is used as given and fails on a conflict. `--dry-run` resolves everything and writes nothing. The result warns when the Server package ships no XSD for the detected configuration schema.
90
+
91
+ ```bash
92
+ afm env list [--json] # state, port, edition, major, root, local overrides, PID
93
+ afm env start <name> [--foreground|--background]
94
+ afm env stop <name>
95
+ afm env restart <name> [--foreground|--background]
96
+ afm env delete <name> [--yes]
97
+ ```
98
+
99
+ * Background output is appended to `<root>\logs\server.stdout.log` and `server.stderr.log`.
100
+ * `running` means the monitor process is alive — not that Wyn finished starting or that the port answers.
101
+ * A stopped environment keeps its reserved port and name; nothing is reassigned automatically.
102
+ * `delete` stops the environment, then removes its directory and its registry record; `--yes` is required when stdin is not a terminal.
103
+ * Environments are listed from `~/.afm/environments.json` (`AFM_CONFIG_DIR` for another profile).
104
+
105
+ ## Update the modules of an environment
106
+
107
+ ```bash
108
+ afm oss update-env <name> --modules dashboard # latest for the recorded major
109
+ afm oss update-env <name> --modules dashboard:0.1.12345 # pinned version
110
+ afm oss update-env <name> --modules dashboard=D:\build\Wyn.Dashboards.Plugin.dll
111
+ afm oss update-env <name> --modules all # every installed module except local ones
112
+ afm oss update-env <name> --modules dashboard --dry-run
113
+ ```
114
+
115
+ Remote updates download, verify (SHA256 + archive checks) and replace the deployed files; the environment must be observed `ready` or `stopped` (`running`/`unknown` is refused — stop it first). A **local source copies nothing** for plugins: the deployed `Plugins\<module>` directory is removed and `conf\Wyn.conf` is pointed straight at your build, so the Server loads it; restart the environment to load the change. Modules that were never installed are installed. `--modules` is required — name `all` or one or more modules.
116
+
117
+ The **Server** is the exception: `--modules server=<build directory>` records a local Server build output, and `env start`/`env restart` copy it over the environment's `Server\` directory on every start (the environment's own `Server\appsettings.json` is kept). After the copy, the built-in payloads that live inside `Server\` are re-applied **from a local cache** — a start never downloads, and a missing cache entry is refused with the command that refreshes it. Because the copied build decides the runtime file versions, run `afm oss|az update-env <name> --modules all` once after a build whose dependencies changed: it refreshes the installed payloads from the recorded build directory and stores them in that cache. A remote `update-env <name> --modules server` deploys the published package again and clears the local source.
118
+
119
+ **Every module can be refreshed, the core components included** — `server`, `monitoring`, `common`, `analysis`, `dashboard`, `reporting`, `data-monitoring`, `sheets`, `documents` and `collaboration` all go through the same path, and `all` covers them together (skipping the ones that have a local source). Refreshing `server` or `monitoring` is checked like a create: the package must ship the runtime assemblies and settings its service needs (the Server's required runtime files, and `Wyn.Configuration.dll` plus `appsettings.json` for the Monitor) and the `xsd/<schema>/Wyn.conf.xsd` for the configuration schema the environment already declares — a Monitor package without it is refused, a Server package without it only warns, because Wyn's configuration reader falls back to ordinary XML deserialization. Refresh the two in the same call when you can: they ship the schema assets for the same configuration, and a single-sided refresh is reported as a warning. The environment's own `Server\appsettings.json` is kept across the replacement (the Server package never deploys one), the Monitor's `conf` assets are merged into `conf\` and the `Monitor/conf` junction is recreated. A local source is refused for `monitoring` and `collaboration`: they are whole services, refreshed from artifacts only. `sheets` and `documents` still require an EN edition environment.
120
+
121
+ A module can own several assemblies (`gces-common` = two plugins + one worker; `dashboard`/`reporting` = plugin + worker), so local sources resolve per assembly:
122
+
123
+ | Spec | Selects |
124
+ |---|---|
125
+ | `dashboard=D:\build\Wyn.Dashboards.Plugin.dll` | the target whose file name matches |
126
+ | `dashboard=D:\build\out` | every assembly of that module found in the directory |
127
+ | `dashboard#Wyn.Dashboards.Worker.dll=D:\build\worker.dll` | that target explicitly |
128
+ | repeated `common=` specs | one target each, as long as no target is selected twice |
129
+
130
+ ```bash
131
+ afm oss update-env demo --modules \
132
+ common=D:\gces-common\src\Wyn.Dataset.Plugin\bin\release\net8.0\Wyn.Dataset.Plugin.dll \
133
+ common=D:\gces-common\src\Wyn.Account.Plugin\bin\release\net8.0\Wyn.Account.Plugin.dll \
134
+ common=D:\gces-common\src\Wyn.CotWorker\bin\release\net8.0\Wyn.CotWorker.dll
135
+ ```
136
+
137
+ The override is recorded in the environment manifest (`moduleSources`) and shown by `env list` in a `local` column; switching the module back to a remote spec deletes the override and restores the deployed files.
138
+
139
+ ## Apply a local build while starting
140
+
141
+ ```bash
142
+ afm env start demo --background --modules dashboard=D:\build\Wyn.Dashboards.Plugin.dll
143
+ afm env restart demo --modules common=D:\build\common,common#Wyn.CotWorker.dll=D:\build\Wyn.CotWorker.dll
144
+ ```
145
+
146
+ Same specs as `update-env`, but only local sources are accepted here (`env` has no cloud provider — use `update-env` for artifacts). `start` applies the override and then starts; `restart` stops, applies and starts again, which is the usual "rebuild, then reload" loop.
147
+
148
+ ## Local web interface
149
+
150
+ ```bash
151
+ afm web # 127.0.0.1, OS-assigned port, opens your browser
152
+ afm web --port 4599 # fixed port
153
+ afm web --token <secret> # reuse your own token instead of a generated one (>= 16 characters)
154
+ afm web --no-open # print the URL only
155
+ ```
156
+
157
+ The page lists the registered environments — one row each, with its site link (`http://localhost:<port>`), a **复制** button for that address and a **打开目录** button that reveals the environment root in Explorer (Windows), Finder (macOS) or `xdg-open` (Linux) — and can create, start, stop, restart and delete them and update their modules. The create form and the update panel default to the **`oss`** provider, falling back to `az` only when OSS has no stored credentials, and the optional-module list follows the selected edition (CN: `dashboard`, `reporting`; EN: those plus `sheets` and `documents`). Creating and updating use the same code paths as `create-env`/`update-env`, including `--dry-run`. The 设置 dialog writes the same local profile the CLI uses, so a machine without a terminal session can still be prepared: the **environment root** (like `afm env root <path>`) and the **az/oss credentials** (like `afm az login` / `afm oss login`). Credentials are send-only — the page shows whether a provider is configured, never the SAS URL or the key.
158
+
159
+ ```json
160
+ {
161
+ "host": "127.0.0.1",
162
+ "port": 4599,
163
+ "url": "http://127.0.0.1:4599/",
164
+ "tokenUrl": "http://127.0.0.1:4599/#token=<token>",
165
+ "token": "<token>"
166
+ }
167
+ ```
168
+
169
+ * **Loopback only.** The listener binds `127.0.0.1`; there is no option to expose it.
170
+ * **Token on every request.** The page reads the token from the URL fragment (which browsers never send to the server), keeps it in `sessionStorage` and sends it as `X-AFM-Token`. `Authorization: Bearer <token>` also works. Comparisons are constant-time.
171
+ * **Host and origin checks.** A request whose `Host` header is not `127.0.0.1:<port>` or `localhost:<port>` is refused (DNS rebinding), and no CORS header is ever sent, so another page cannot read a reply or send the token header. The page is served with a strict `Content-Security-Policy`.
172
+ * **Long operations are jobs.** Create/update/delete/start/stop/restart answer `202` with a job id; the page polls `GET /api/jobs/<id>`. Mutations of one environment are serialized (a second request waits as `queued`), and the first `Ctrl+C` waits for running jobs before stopping so an interrupted `create-env` does not leave a reservation behind.
173
+ * **Start always uses background mode** from the page — a foreground monitor would own the terminal the web server runs in. Use the CLI when you want foreground output.
174
+ * Deleting from the page requires typing the environment name; it stops the verified monitor and removes the directory and the registry record, exactly like `env delete`.
175
+
176
+ ## Library
177
+
178
+
179
+ ```ts
180
+ import { ArtifactClient, buildEnvironmentPlan, executeEnvironmentPlan } from '@guanjinke/artifact-client';
181
+
182
+ const client = new ArtifactClient('oss', { keyId: 'id', key: 'secret', bucket: 'my-bucket' });
183
+
184
+ await client.listPlugins({ includeSize: true });
185
+ await client.listMajorVersions('myPlugin', { sortOrder: 'asc' });
186
+ await client.getLatestVersion('gces-server', '9.1');
187
+ await client.listArtifacts('gces-server', '9.1.21042', { includeSize: true });
188
+ await client.uploadArtifact('myPlugin', '1.0.6', 'bundle.zip', './dist/bundle.zip');
189
+ await client.updateLatestVersion('myPlugin', '9.1-hotfix1', '1.0.6');
190
+ await client.downloadArtifact('myPlugin', '1.0.5', 'bundle.zip', './downloads');
191
+ await client.downloadArtifactByPath('plugin_artifacts/myPlugin/1.0.5/bundle.zip', './downloads');
192
+ const files = await client.downloadVersion('myPlugin', '1.0.5', './downloads');
193
+
194
+ // Plan resolutely (no downloads or writes), then assemble and register an environment
195
+ const plan = await buildEnvironmentPlan({ root: 'D:/wyn/demo', major: '9.1', modules: ['dashboard'] }, client);
196
+ const result = await executeEnvironmentPlan(plan, { client });
197
+ ```
198
+
199
+ | Method | Description |
200
+ |---|---|
201
+ | `listPlugins(opts?)` | List plugins (optionally with total size) |
202
+ | `listMajorVersions(plugin, opts?)` | Majors with the version each one points at |
203
+ | `getLatestVersion(plugin, major, opts?)` | Version a major currently points at |
204
+ | `listMinorVersions(plugin, major, opts?)` | Versions under a major |
205
+ | `listArtifacts(plugin, version, opts?)` | Files of a version (optionally with sizes) |
206
+ | `uploadArtifact(plugin, version, name, localPath)` | Upload one file into a version directory |
207
+ | `updateLatestVersion(plugin, major, version)` | Move a major's latest pointer |
208
+ | `downloadArtifactByPath(fullPath, localDir)` | Download by full storage path |
209
+ | `downloadArtifact(plugin, version, fileName, localDir)` | Download by name |
210
+ | `downloadVersion(plugin, version, localDir)` | Download every file of a version |
211
+
212
+ `client` is a small typed interface, so tests can inject a stub. Assembly, planning, listing and lifecycle all work on Windows, Linux and macOS: lifecycle uses the Windows backend on Windows and a POSIX backend (`/proc` on Linux, `ps` on macOS) elsewhere. Running an environment never needs administrator rights; only the process-identity check touches privileges, because Windows withholds the command line and executable path of a process owned by another account (a SYSTEM `WynService`, for instance). Such a process is attributed to an environment only when it carries that environment's recorded monitor PID, and it is reported in `afm env list` instead of blocking a start.
213
+
214
+ ## Notes
215
+
216
+ * Stopping is a forced process-tree termination, not a graceful HTTP shutdown.
217
+ * A missing or unknown process identity blocks start/stop/delete instead of guessing.
218
+ * Version resolution never selects a different archive by size: only the exact expected file name is used.
219
+
220
+ Design details, safety semantics and development notes live in the repository.
221
+
222
+ MIT
@@ -26,6 +26,9 @@ export declare function writeConfig(config: CLIConfig): void;
26
26
  export declare function saveAzureConfig(config: AzureConfig): void;
27
27
  /**
28
28
  * Save OSS authentication config.
29
+ *
30
+ * A blank bucket or region stores the configured default instead, so the profile
31
+ * can never end up with credentials but no bucket to use them against.
29
32
  */
30
33
  export declare function saveOSSConfig(config: OSSConfig): void;
31
34
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAK7D;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAYD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,SAAS,CAWtC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAGnD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAIzD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAIrD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAGvD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAK1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAI3C"}
1
+ {"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAM7D;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAYD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,SAAS,CAWtC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAGnD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAIzD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAQrD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAGvD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAK1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAI3C"}
@@ -46,6 +46,7 @@ exports.clearEnvironmentRoot = clearEnvironmentRoot;
46
46
  const fs = __importStar(require("fs"));
47
47
  const path = __importStar(require("path"));
48
48
  const os = __importStar(require("os"));
49
+ const defaults_1 = require("../defaults");
49
50
  const CONFIG_DIR_NAME = '.afm';
50
51
  const CONFIG_FILE_NAME = 'config.json';
51
52
  /**
@@ -108,10 +109,17 @@ function saveAzureConfig(config) {
108
109
  }
109
110
  /**
110
111
  * Save OSS authentication config.
112
+ *
113
+ * A blank bucket or region stores the configured default instead, so the profile
114
+ * can never end up with credentials but no bucket to use them against.
111
115
  */
112
116
  function saveOSSConfig(config) {
113
117
  const current = readConfig();
114
- current.oss = config;
118
+ current.oss = {
119
+ ...config,
120
+ bucket: config.bucket?.trim() || defaults_1.DEFAULT_OSS_BUCKET,
121
+ region: config.region?.trim() || defaults_1.DEFAULT_OSS_REGION,
122
+ };
115
123
  writeConfig(current);
116
124
  }
117
125
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAkCvC"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAkCvC"}
package/dist/cli/setup.js CHANGED
@@ -42,6 +42,7 @@ const stored_client_1 = require("./stored-client");
42
42
  const web_1 = require("./web");
43
43
  const version_1 = require("./version");
44
44
  const semver_1 = require("../utils/semver");
45
+ const defaults_1 = require("../defaults");
45
46
  const plan_1 = require("../environment/plan");
46
47
  const manager_1 = require("../environment/manager");
47
48
  const update_1 = require("../environment/update");
@@ -197,8 +198,8 @@ function addSharedCommands(program, type) {
197
198
  .option('--sasurl <url>', 'Azure SAS URL (az only)')
198
199
  .option('--keyid <id>', 'OSS Key ID (oss only)')
199
200
  .option('--key <key>', 'OSS Key Secret (oss only)')
200
- .option('--bucket <bucket>', 'OSS bucket name (oss only)')
201
- .option('--region <region>', 'OSS region (oss only)')
201
+ .option('--bucket <bucket>', `OSS bucket name (oss only; default: ${defaults_1.DEFAULT_OSS_BUCKET})`)
202
+ .option('--region <region>', `OSS region (oss only; default: ${defaults_1.DEFAULT_OSS_REGION})`)
202
203
  .action((options) => {
203
204
  if (type === 'az') {
204
205
  if (!options.sasurl) {
@@ -580,11 +581,13 @@ function createClient(type, cliOptions, environment = false) {
580
581
  console.error('Error: OSS key ID and key are required. Provide --keyid and --key or run "afm oss login".');
581
582
  process.exit(1);
582
583
  }
584
+ // Bucket and region are optional in the profile and fall back to the
585
+ // configured defaults, so credentials alone are enough to use OSS.
583
586
  return new artifact_client_1.ArtifactClient('oss', {
584
587
  keyId,
585
588
  key,
586
- bucket: cliOptions.bucket || ossStored?.bucket,
587
- region: cliOptions.region || ossStored?.region,
589
+ bucket: cliOptions.bucket || ossStored?.bucket || defaults_1.DEFAULT_OSS_BUCKET,
590
+ region: cliOptions.region || ossStored?.region || defaults_1.DEFAULT_OSS_REGION,
588
591
  ...(basePrefix !== undefined ? { basePrefix } : {}),
589
592
  });
590
593
  }