@guanjinke/artifact-client 1.13.0 → 1.14.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/README.md +219 -217
- package/dist/cli.js +0 -0
- package/dist/environment/artifact-cache.d.ts +36 -0
- package/dist/environment/artifact-cache.d.ts.map +1 -0
- package/dist/environment/artifact-cache.js +131 -0
- package/dist/environment/artifact-cache.js.map +1 -0
- package/dist/environment/builder.d.ts.map +1 -1
- package/dist/environment/builder.js +10 -3
- package/dist/environment/builder.js.map +1 -1
- package/dist/environment/local-server.d.ts +12 -0
- package/dist/environment/local-server.d.ts.map +1 -0
- package/dist/environment/local-server.js +201 -0
- package/dist/environment/local-server.js.map +1 -0
- package/dist/environment/manager.d.ts.map +1 -1
- package/dist/environment/manager.js +7 -0
- package/dist/environment/manager.js.map +1 -1
- package/dist/environment/manifest.d.ts +56 -0
- package/dist/environment/manifest.d.ts.map +1 -0
- package/dist/environment/manifest.js +81 -0
- package/dist/environment/manifest.js.map +1 -0
- package/dist/environment/update.d.ts +1 -1
- package/dist/environment/update.d.ts.map +1 -1
- package/dist/environment/update.js +79 -42
- package/dist/environment/update.js.map +1 -1
- package/dist/providers/oss-provider.d.ts.map +1 -1
- package/dist/providers/oss-provider.js +28 -2
- package/dist/providers/oss-provider.js.map +1 -1
- package/dist/web/static/styles.css +1619 -1619
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,217 +1,219 @@
|
|
|
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
|
|
113
|
-
|
|
114
|
-
**
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
|
121
|
-
|
|
122
|
-
| `dashboard
|
|
123
|
-
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
common=D:\gces-common\src\Wyn.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
afm web
|
|
149
|
-
afm web --
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
* **
|
|
167
|
-
* **
|
|
168
|
-
* **
|
|
169
|
-
*
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
await client.
|
|
182
|
-
await client.
|
|
183
|
-
await client.
|
|
184
|
-
await client.
|
|
185
|
-
await client.
|
|
186
|
-
await client.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
|
197
|
-
|
|
198
|
-
| `
|
|
199
|
-
| `
|
|
200
|
-
| `
|
|
201
|
-
| `
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `
|
|
206
|
-
|
|
207
|
-
`
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
*
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
package/dist/cli.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local cache of downloaded artifacts.
|
|
3
|
+
*
|
|
4
|
+
* A local Server build replaces `Server/` on every start, which throws away the
|
|
5
|
+
* built-in resource tree and the patched file. Re-applying them must not touch the
|
|
6
|
+
* network: the `env` command group has no cloud provider, and a start should not
|
|
7
|
+
* depend on the cloud being reachable. Create and update therefore store every
|
|
8
|
+
* artifact they download here, keyed by the provider-side identity, and the start
|
|
9
|
+
* path reads only from this cache.
|
|
10
|
+
*
|
|
11
|
+
* Layout: `<config directory>/cache/artifacts/<plugin>/<version>/<object name>`
|
|
12
|
+
* (object names may contain sub-directories, e.g. `patched/X.dll`), where the
|
|
13
|
+
* config directory is `AFM_CONFIG_DIR` or `~/.afm`. The provider and version are
|
|
14
|
+
* internal: nothing here is echoed to the user.
|
|
15
|
+
*/
|
|
16
|
+
export declare function artifactCacheDirectory(): string;
|
|
17
|
+
/** Where one cached object lives; exported for tests and diagnostics. */
|
|
18
|
+
export declare function cachedArtifactPath(plugin: string, version: string, name: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* A cached object, or `undefined` when it is absent, not a regular file, or does
|
|
21
|
+
* not match the recorded SHA256. A mismatching file is treated as absent: the next
|
|
22
|
+
* create or update overwrites it, and a start refuses instead of deploying bytes
|
|
23
|
+
* nobody verified.
|
|
24
|
+
*/
|
|
25
|
+
export declare function cachedArtifact(plugin: string, version: string, name: string, sha256?: string): Promise<string | undefined>;
|
|
26
|
+
/**
|
|
27
|
+
* Store one downloaded artifact under its provider-side identity.
|
|
28
|
+
*
|
|
29
|
+
* Copies through a uniquely named `.afm-tmp` sibling and an atomic rename, so a
|
|
30
|
+
* concurrent reader never sees a partial object and a failed write leaves no
|
|
31
|
+
* temporary file behind. An existing object with the same hash is kept as it is.
|
|
32
|
+
*/
|
|
33
|
+
export declare function storeArtifact(plugin: string, version: string, name: string, sourceFile: string, sha256: string): Promise<void>;
|
|
34
|
+
/** Best-effort variant: caching must never fail a create or an update. */
|
|
35
|
+
export declare function rememberArtifact(plugin: string, version: string, name: string, sourceFile: string, sha256: string): Promise<void>;
|
|
36
|
+
//# sourceMappingURL=artifact-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-cache.d.ts","sourceRoot":"","sources":["../../src/environment/artifact-cache.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAqBD,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAExF;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAMhI;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYpI;AAED,0EAA0E;AAC1E,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvI"}
|