@synopackageland/cli 0.7.0 → 0.7.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/CHANGELOG.md +234 -1
- package/dist/add.d.ts +4 -1
- package/dist/add.js +14 -9
- package/dist/build-spk/dsm-platforms.json +4 -1
- package/dist/build-spk/gateway.d.ts +1 -1
- package/dist/build-spk/gateway.js +8 -4
- package/dist/build-spk/go-toolchain.d.ts +20 -0
- package/dist/build-spk/go-toolchain.js +44 -0
- package/dist/cli.js +13 -7
- package/dist/deploy/native-install-values.d.ts +17 -0
- package/dist/deploy/native-install-values.js +32 -0
- package/dist/deploy/plan.d.ts +6 -2
- package/dist/deploy/plan.js +57 -6
- package/dist/error-registry.js +12 -6
- package/dist/host/dsm-client.js +53 -17
- package/dist/host/dsm-http.js +24 -2
- package/dist/host/types.d.ts +1 -0
- package/dist/info.js +28 -9
- package/dist/init.js +1 -1
- package/dist/runtime/dsm-version.d.ts +6 -0
- package/dist/runtime/dsm-version.js +8 -0
- package/dist/runtime/executor-build.d.ts +1 -1
- package/dist/runtime/executor-build.js +8 -5
- package/dist/standalone/daemon.d.ts +2 -1
- package/dist/standalone/daemon.js +10 -6
- package/dist/standalone/dsm-window.js +6 -34
- package/dist/standalone/inspect-spk.js +5 -1
- package/dist/standalone/native-authorization-window.d.ts +1 -1
- package/dist/standalone/native-authorization-window.js +7 -1
- package/dist/standalone/native-root-window.d.ts +4 -2
- package/dist/standalone/native-root-window.js +33 -18
- package/dist/standalone/root-window.d.ts +4 -1
- package/dist/standalone/root-window.js +143 -33
- package/dist/templates/_daemon/go.mod +1 -1
- package/dist/templates/_daemon/main.go +6 -3
- package/dist/templates/_daemon/main_test.go +21 -1
- package/dist/templates/_daemon/testdata/child.go +3 -0
- package/dist/templates/_executor/README.md +4 -1
- package/dist/templates/_executor/anchor.go +10 -0
- package/dist/templates/_executor/anchor_test.go +40 -5
- package/dist/templates/_executor/digest_review_test.go +2 -2
- package/dist/templates/_executor/dsm.go +40 -3
- package/dist/templates/_executor/go.mod +2 -0
- package/dist/templates/_executor/main.go +11 -5
- package/dist/templates/_executor/managed.go +3 -3
- package/dist/templates/_executor/managed_test.go +3 -3
- package/dist/templates/_executor/path_test.go +18 -0
- package/dist/templates/_executor/pid.go +37 -0
- package/dist/templates/_executor/pid_test.go +113 -0
- package/dist/templates/_executor/platform_other.go +8 -0
- package/dist/templates/_executor/purge_log.go +18 -0
- package/dist/templates/_executor/tasks.go +45 -7
- package/dist/templates/_executor/tasks_dsm71_test.go +114 -0
- package/dist/templates/_executor/tasks_test.go +58 -1
- package/dist/templates/_executor/upgrade_watch_test.go +13 -5
- package/dist/templates/_gateway/go.mod +2 -0
- package/dist/templates/native-go/backend/go.mod +1 -1
- package/dist/templates/native-go/backend/internal/filestation/client.go +39 -3
- package/dist/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
- package/dist/templates/native-go/backend/internal/identity/README.md +5 -1
- package/dist/templates/native-go/backend/internal/identity/dsm.go +24 -5
- package/dist/templates/native-go/backend/internal/identity/http.go +1 -1
- package/dist/templates/native-go/backend/internal/identity/identity_test.go +48 -1
- package/dist/templates/native-go/backend/internal/identity/service.go +1 -1
- package/dist/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
- package/dist/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
- package/dist/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +3 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +5 -1
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +1 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +1 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +1 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +1 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +1 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +1 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +1 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +1 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +1 -0
- package/package.json +1 -1
- package/templates/_daemon/go.mod +1 -1
- package/templates/_daemon/main.go +6 -3
- package/templates/_daemon/main_test.go +21 -1
- package/templates/_daemon/testdata/child.go +3 -0
- package/templates/_executor/README.md +4 -1
- package/templates/_executor/anchor.go +10 -0
- package/templates/_executor/anchor_test.go +40 -5
- package/templates/_executor/digest_review_test.go +2 -2
- package/templates/_executor/dsm.go +40 -3
- package/templates/_executor/go.mod +2 -0
- package/templates/_executor/main.go +11 -5
- package/templates/_executor/managed.go +3 -3
- package/templates/_executor/managed_test.go +3 -3
- package/templates/_executor/path_test.go +18 -0
- package/templates/_executor/pid.go +37 -0
- package/templates/_executor/pid_test.go +113 -0
- package/templates/_executor/platform_other.go +8 -0
- package/templates/_executor/purge_log.go +18 -0
- package/templates/_executor/tasks.go +45 -7
- package/templates/_executor/tasks_dsm71_test.go +114 -0
- package/templates/_executor/tasks_test.go +58 -1
- package/templates/_executor/upgrade_watch_test.go +13 -5
- package/templates/_gateway/go.mod +2 -0
- package/templates/native-go/backend/go.mod +1 -1
- package/templates/native-go/backend/internal/filestation/client.go +39 -3
- package/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
- package/templates/native-go/backend/internal/identity/README.md +5 -1
- package/templates/native-go/backend/internal/identity/dsm.go +24 -5
- package/templates/native-go/backend/internal/identity/http.go +1 -1
- package/templates/native-go/backend/internal/identity/identity_test.go +48 -1
- package/templates/native-go/backend/internal/identity/service.go +1 -1
- package/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
- package/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
- package/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
- package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +3 -2
- package/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
- package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +5 -1
- package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +1 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +1 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +1 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +1 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +1 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +1 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +1 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +1 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,239 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.7.1 (2026-10-10)
|
|
4
|
+
|
|
5
|
+
Rebuild packages to pick up template, hook and executor changes. The executor
|
|
6
|
+
digest changed. A package built with CLI 0.7.0 needs one administrator approval
|
|
7
|
+
after upgrading to a 0.7.1 build: the 0.7.0 executor opened the package
|
|
8
|
+
`target` link without following it, so it cannot install the anchored executor
|
|
9
|
+
itself. Executor-only upgrades between 0.7.1 or later builds need no approval.
|
|
10
|
+
|
|
11
|
+
### Executor upgrade and daemon timeouts
|
|
12
|
+
|
|
13
|
+
- During an INFO-anchored executor-only upgrade the executor log said
|
|
14
|
+
`executor paused: package pins require administrator approval` about two
|
|
15
|
+
seconds before the new executor was ready. That line now appears only when
|
|
16
|
+
the pins differ; an anchored handover logs only `executor upgrade:
|
|
17
|
+
INFO-anchored executor installed under the approved policy`. The executor
|
|
18
|
+
digest changes.
|
|
19
|
+
|
|
20
|
+
- `executor_status_mismatch` in the app window and the app's settings names
|
|
21
|
+
its cause: `the approved executor is not answering (<reason>)`, `the running
|
|
22
|
+
executor reports other digests than this package pins`, or `the executor
|
|
23
|
+
status request failed` with the request's own code, instead of `scheduler
|
|
24
|
+
readback or operation failed` for all three. The Data and removal
|
|
25
|
+
troubleshooting table explains each.
|
|
26
|
+
|
|
27
|
+
- After approval or control start the window asked `executor.status` every
|
|
28
|
+
500 ms for up to 10 s. The wait now doubles from 500 ms to 2 s within the
|
|
29
|
+
same 10 s budget: at most 7 requests instead of 20.
|
|
30
|
+
|
|
31
|
+
- For live upgrade tests, the repository's `scripts/test/executor-bump.py`
|
|
32
|
+
makes an executor-only build+1 SPK and now rewrites the window script's
|
|
33
|
+
embedded pins with the INFO anchor and `executor/setup.json`. The earlier
|
|
34
|
+
out-of-tree copy left the window pins behind, so the panel reported
|
|
35
|
+
`executor_status_mismatch` after every such upgrade while CGI and CLI
|
|
36
|
+
status were ready.
|
|
37
|
+
|
|
38
|
+
- On kernel 3.10 (DSM 7.1, for example DS416 armv7) an executor-only
|
|
39
|
+
upgrade, and approving again while the executor runs, no longer fail
|
|
40
|
+
with "pid executable mismatch". That kernel names a running executor
|
|
41
|
+
replaced by a rename after the rename source (`runtime/.executor
|
|
42
|
+
(deleted)`), and root control accepted only `runtime/executor`. Root
|
|
43
|
+
control now identifies the monitor by inode: the current
|
|
44
|
+
`runtime/executor`, or an unlinked root-owned inode on the runtime's
|
|
45
|
+
device whose last name was `executor` or `.executor*` in the runtime.
|
|
46
|
+
The fix runs in the new executor, which the installed one starts: an
|
|
47
|
+
upgrade from a package built with the target-link fix below needs no
|
|
48
|
+
approval; from 0.7.0 it still needs the one approval described there.
|
|
49
|
+
The executor digest changes.
|
|
50
|
+
|
|
51
|
+
- When the approved tasks are ready but the executor does not answer
|
|
52
|
+
(`executor_status_mismatch`), the app window offers Approve background
|
|
53
|
+
access again. With the tasks approved, it restarts the executor without
|
|
54
|
+
a password.
|
|
55
|
+
|
|
56
|
+
- `executor.status` (root-ops) names approval, not "Start the package", as
|
|
57
|
+
the next step when the package's last lifecycle request was start.
|
|
58
|
+
Regenerate or copy `backend/internal/app/executor.go`.
|
|
59
|
+
|
|
60
|
+
- An executor-only upgrade (same policy, new executor matching the INFO
|
|
61
|
+
`synopkgland_executor_sha256` anchor) no longer fails with "executor
|
|
62
|
+
upgrade refused: INFO-anchored executor could not be installed". The
|
|
63
|
+
installer opened `/var/packages/<pkg>/target/executor` without following
|
|
64
|
+
the DSM `target` link, which the executor refuses, so every such upgrade
|
|
65
|
+
stayed paused. The fix runs in the executor that is already installed:
|
|
66
|
+
an upgrade from a package built with an earlier SDK still needs one
|
|
67
|
+
administrator approval. The executor digest changes.
|
|
68
|
+
|
|
69
|
+
- `executor.status` (root-ops and delegate projects) no longer answers
|
|
70
|
+
`internal` while the executor is paused (package stopped, or pins waiting
|
|
71
|
+
for approval). It answers `{ready: false, state: "paused", reason:
|
|
72
|
+
"executor_not_listening", next}`, and `synopkgland status` shows the
|
|
73
|
+
reason and next step. Regenerate or copy
|
|
74
|
+
`backend/internal/app/executor.go` into existing projects.
|
|
75
|
+
|
|
76
|
+
- `daemon.timeouts` defaults are now `{start: 30, stop: 30, status: 5,
|
|
77
|
+
uninstall: 60}` (were `start: 5, stop: 10, status: 2`). On vt-nas under
|
|
78
|
+
IO load a boot start took more than 5 s and a Connect revoke more than
|
|
79
|
+
9 s. The new `timeouts.uninstall` (2–120) bounds `uninstall_args`
|
|
80
|
+
separately; it used to get `stop - 1`, so an app had to raise the SIGKILL
|
|
81
|
+
wait to give its revoke time. DSM's package unit allows 3600 s for start
|
|
82
|
+
and stop. `inspect` still accepts SPKs built before `timeouts.uninstall`.
|
|
83
|
+
The manifest reference explains how to pick values from a loaded NAS.
|
|
84
|
+
|
|
85
|
+
### Approval, identity and uninstall fixes
|
|
86
|
+
|
|
87
|
+
- `identity: standalone`: "Continue with DSM" and every live revalidation
|
|
88
|
+
failed with `session_required` after a DSM web login, because DSM web
|
|
89
|
+
sessions enable SynoToken and DSM answers the `id` cookie alone with 119.
|
|
90
|
+
The backend now forwards the request's single `X-SYNO-TOKEN` header, which
|
|
91
|
+
the DSM window's `ctx.call` already sends, when it checks the DSM session.
|
|
92
|
+
Sessions without SynoToken still verify with the cookie alone. The token is
|
|
93
|
+
never put in a URL, logged or stored. This also unblocks root-ops approval
|
|
94
|
+
in an `identity: standalone` package, which stopped at `executor.control`.
|
|
95
|
+
Existing projects need the updated `internal/identity` files.
|
|
96
|
+
- When approval created and read back both tasks but the executor then did
|
|
97
|
+
not start or report healthy, the window left the tasks behind, and with no
|
|
98
|
+
running executor there was no task inventory for uninstall to delete them.
|
|
99
|
+
The window now withdraws the tasks that approval created; tasks from an
|
|
100
|
+
earlier approval stay.
|
|
101
|
+
- After a wrong password or a withdrawn approval, the window panel showed
|
|
102
|
+
only "Check status". It and the app's settings now keep the approve action.
|
|
103
|
+
- Uninstall no longer logs `task cleanup unconfirmed` for every successful
|
|
104
|
+
delete: EventScheduler `delete` v1 and TaskScheduler `delete` v2 answer
|
|
105
|
+
`{"success":true}` without data, which now counts as confirmed. The task
|
|
106
|
+
definitions are unchanged, so no new approval is needed; the executor
|
|
107
|
+
digest changes.
|
|
108
|
+
- The native root window (`@synopackageland/cli/authorization-sdk`) gave up
|
|
109
|
+
after about 30 s with `root_timeout`, while a loaded NAS ran the bootstrap
|
|
110
|
+
task for up to 4.5 minutes. It now keeps waiting while the task is queued or
|
|
111
|
+
running, up to 10 minutes, reports `{op, state, elapsedMs}` through
|
|
112
|
+
`options.progress`, and the authorization flow accepts the backend's ready
|
|
113
|
+
grant after `root_timeout` or `root_task_failed`.
|
|
114
|
+
- A DSM certificate that Node does not trust failed with only
|
|
115
|
+
`fetch failed`. The CLI now reports `DSM_TLS_UNTRUSTED` with the origin and
|
|
116
|
+
certificate error and points to `NODE_EXTRA_CA_CERTS`; certificate checks
|
|
117
|
+
stay on.
|
|
118
|
+
- Docs: on DSM 7.1 the purge timing lines are only in the journal
|
|
119
|
+
(`journalctl -t synopkgland-executor`); `init -t native-go` does not include
|
|
120
|
+
`armv7` in `arches`, so add it for an armv7 NAS.
|
|
121
|
+
|
|
122
|
+
### Deploy and status fixes
|
|
123
|
+
|
|
124
|
+
- `status` no longer reports `blocked` for every `identity: standalone`
|
|
125
|
+
project. It opens a short-lived App session from the administrator's DSM
|
|
126
|
+
session, reads `executor.status`, then logs out. That needs an `https://`
|
|
127
|
+
host; over `http://` the capability stays `blocked` and the reason says so.
|
|
128
|
+
- `deploy` accepts the install wizard values of an `install-selected`
|
|
129
|
+
delegate: `--param delegate_share=<Shared Folder>` or
|
|
130
|
+
`--param delegate_home=true`. A first install without one now fails with
|
|
131
|
+
`DEPLOY_PARAM_REQUIRED` and a usage line before anything is built, instead
|
|
132
|
+
of failing inside DSM. Invalid values fail with `DEPLOY_PARAM_TYPE_INVALID`.
|
|
133
|
+
- `deploy` and `status` work on a native layout (existing native product).
|
|
134
|
+
`deploy` builds the NAS architecture only; an `aarch64` NAS uses a declared
|
|
135
|
+
`armv8`.
|
|
136
|
+
- The deploy note no longer says every upgrade needs approval: an
|
|
137
|
+
executor-only upgrade stays ready; a policy digest change needs approval.
|
|
138
|
+
- Uninstall logs per-phase purge timing with the package name to the system
|
|
139
|
+
log (`synopkgland-executor`): `task cleanup timing` per task and
|
|
140
|
+
`purge timing` for the task and file phases. The executor digest changes.
|
|
141
|
+
- `add root-ops` and `add portal` print a notice on stderr when they raise
|
|
142
|
+
`os_min_ver`.
|
|
143
|
+
- `inspect` on an executor SPK describes the root boot and control tasks
|
|
144
|
+
instead of saying the package needs no root privileges.
|
|
145
|
+
|
|
146
|
+
### DSM 7.1: root-ops and delegate approval work
|
|
147
|
+
|
|
148
|
+
- DSM 7.1.1 has no `SYNO.Core.TaskScheduler.Root` or
|
|
149
|
+
`SYNO.Core.EventScheduler.Root`, TaskScheduler stops at v3 and
|
|
150
|
+
PasswordConfirm at v1, so approval failed with "Background file access is
|
|
151
|
+
unavailable" and `status`/`deploy` showed `rootOps: unsupported — DSM 103`
|
|
152
|
+
or `DSM 104`. DSM 7.1.1 answers a version above the API's maximum with 104
|
|
153
|
+
(PasswordConfirm v2, TaskScheduler `get` v4) and a method missing at an
|
|
154
|
+
existing version with 103 (TaskScheduler `list` v3). When DSM answers a
|
|
155
|
+
scheduler read or the password check with 103 or 104, the app now uses
|
|
156
|
+
PasswordConfirm v1, TaskScheduler `list` v2/`get` v3 and creates
|
|
157
|
+
the tasks with EventScheduler `create` v1 and TaskScheduler `create` v3.
|
|
158
|
+
The password is still confirmed first and both tasks are still read back
|
|
159
|
+
exactly before anything runs. Other errors (such as 105, 119, 102 or a
|
|
160
|
+
wrong password, 3121) never fall back, and a create is never retried. DSM
|
|
161
|
+
7.1 does not bind task creation to the password check; see the root-ops
|
|
162
|
+
guide.
|
|
163
|
+
- `status` and `deploy` read the control task the same way.
|
|
164
|
+
- Uninstall on DSM 7.1 now removes the boot and control tasks. The executor
|
|
165
|
+
looked the control task up with TaskScheduler `get` v4, which DSM 7.1.1
|
|
166
|
+
refuses with 104, so it wrote no task inventory and left both tasks behind.
|
|
167
|
+
- If approval stops after it created a task (for example, the boot task was
|
|
168
|
+
created and the control task was not), the app deletes the tasks it created
|
|
169
|
+
in that attempt instead of leaving an enabled root boot task that nothing
|
|
170
|
+
owns. Tasks from an earlier approval stay.
|
|
171
|
+
- A failed approval shows its reason and DSM error code in the app's settings
|
|
172
|
+
instead of only "Background file access is unavailable", and a refused
|
|
173
|
+
password reads as a password failure, not a scheduler failure.
|
|
174
|
+
- After the app's settings approve, the window's status line no longer shows
|
|
175
|
+
"needs-admin-approval: Task is missing" until a reload; the window panel and
|
|
176
|
+
the settings now follow each other's results.
|
|
177
|
+
|
|
178
|
+
### DSM 7.1: jobs import and file downloads
|
|
179
|
+
|
|
180
|
+
- DSM 7.1.1 sends `SYNO.FileStation.Download` v2 replies without
|
|
181
|
+
`Content-Disposition`, so `bg.jobs.submit` and downloads failed with
|
|
182
|
+
`unavailable`. With no such header, a body of at most 4 KiB that decodes
|
|
183
|
+
as a DSM reply is still refused as that reply; any other body is the file.
|
|
184
|
+
|
|
185
|
+
### Docs: build your own armv7 Go code with Go 1.26.9
|
|
186
|
+
|
|
187
|
+
- On armv7 DSM 7.1.1 (kernel 3.10), a program built with Go 1.26.0 crashed
|
|
188
|
+
at start (`futexwakeup returned -22`, SIGSEGV) and Go 1.26.9 ran. Other
|
|
189
|
+
1.26 releases were not tested.
|
|
190
|
+
|
|
191
|
+
### init: next steps install frontend dependencies
|
|
192
|
+
|
|
193
|
+
- `init -t native-go` with a Vue frontend now lists `(cd frontend && npm ci)`
|
|
194
|
+
before `synopkgland build`; without it the build fails with
|
|
195
|
+
`STANDALONE_UI_BUILD_FAILED`. `build` still does not install dependencies.
|
|
196
|
+
|
|
197
|
+
### Executor, daemon and gateway build with exactly Go 1.26.9
|
|
198
|
+
|
|
199
|
+
- The CLI builds the executor, lifecycle helper, daemon controller and gateway
|
|
200
|
+
with `GOTOOLCHAIN=go1.26.9`, ignoring your `GOTOOLCHAIN`, `GOFLAGS`,
|
|
201
|
+
`GOEXPERIMENT`, `GOWORK` and `GOAMD64`/`GOARM64`, so every builder produces
|
|
202
|
+
the same executor digest. Go 1.21 or later downloads go1.26.9 when needed;
|
|
203
|
+
offline without it the build fails and names go1.26.9. A binary whose Go
|
|
204
|
+
build info names another release is refused.
|
|
205
|
+
- Template go.mod files now say `toolchain go1.26.9`. The executor digest
|
|
206
|
+
changes; it is anchored in INFO, so an upgrade with an unchanged policy needs
|
|
207
|
+
no new approval.
|
|
208
|
+
|
|
209
|
+
### INFO arch: four more DSM platforms
|
|
210
|
+
|
|
211
|
+
- x86_64 SPKs now also list `broadwellntb`, `coffeelake` and `skylaked`, and
|
|
212
|
+
aarch64 SPKs list `rtd1619` (DSM Developer Guide Appendix A family members).
|
|
213
|
+
INFO `arch` now matches the platforms the package source maps to each family.
|
|
214
|
+
|
|
215
|
+
### 繁體中文摘要
|
|
216
|
+
|
|
217
|
+
- 升級後重新建置套件;executor digest 改變。**從 0.7.0 建的套件升級需管理員再核准一次**(0.7.0 的
|
|
218
|
+
executor 開啟套件 `target` symlink 時未跟隨連結,無法自行安裝錨定的 executor);之後 0.7.1 起的
|
|
219
|
+
executor-only 升級不需核准。
|
|
220
|
+
- executor:kernel 3.10(DSM 7.1,如 DS416 armv7)上 executor-only 升級與執行中再核准不再出現
|
|
221
|
+
`pid executable mismatch`;INFO 錨定升級不再誤報 `executor upgrade refused`,也不再先印
|
|
222
|
+
「paused: 需管理員核准」;`executor.status` 暫停時回 `paused`/`executor_not_listening` 與下一步。
|
|
223
|
+
- 面板:executor 不回應時可再按一次「Approve background access」免密碼重啟;
|
|
224
|
+
`executor_status_mismatch` 會寫出原因(不回應/digest 不同/status 請求失敗);
|
|
225
|
+
啟動後的 `executor.status` 等待改為 500 ms→2 s 退避,10 s 預算不變。
|
|
226
|
+
- `daemon.timeouts` 預設改為 `{start: 30, stop: 30, status: 5, uninstall: 60}`,新增 `timeouts.uninstall`。
|
|
227
|
+
- `identity: standalone`:DSM 網頁 session(SynoToken)下「Continue with DSM」與 root-ops 核准修正;
|
|
228
|
+
核准建立 task 後 executor 未啟動時自動撤回本次建立的 task;卸載不再誤記 `task cleanup unconfirmed`。
|
|
229
|
+
- 原生 root window 等待上限改為 10 分鐘並回報進度;`DSM_TLS_UNTRUSTED` 指向 `NODE_EXTRA_CA_CERTS`。
|
|
230
|
+
- `status`/`deploy`:standalone 專案的 status 改用短期 App session;`deploy` 接受
|
|
231
|
+
install-selected delegate 的精靈參數;支援 native layout;卸載記錄 purge timing。
|
|
232
|
+
- DSM 7.1:無 Root API 時改走 PasswordConfirm v1/TaskScheduler v2–v3/EventScheduler create v1,
|
|
233
|
+
卸載會移除 boot/control task;`SYNO.FileStation.Download` v2 無 `Content-Disposition` 的下載修正。
|
|
234
|
+
- 建置:executor、lifecycle、daemon、gateway 一律以 Go 1.26.9 建置(armv7 kernel 3.10 上 1.26.0 會當機);
|
|
235
|
+
INFO `arch` 新增 `broadwellntb`、`coffeelake`、`skylaked`、`rtd1619`。
|
|
236
|
+
- 測試工具:`scripts/test/executor-bump.py` 收進 repo,會一併改寫視窗腳本內嵌的 executor pin。
|
|
4
237
|
|
|
5
238
|
## 0.7.0 (2026-10-10)
|
|
6
239
|
|
package/dist/add.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type AddResult = {
|
|
2
2
|
added: string[];
|
|
3
3
|
unchanged: string[];
|
|
4
|
+
notes?: string[];
|
|
4
5
|
};
|
|
6
|
+
export declare function addCapabilities(root: string, requested: string[]): AddResult;
|
|
7
|
+
export {};
|
package/dist/add.js
CHANGED
|
@@ -46,11 +46,17 @@ function safePath(root, file) {
|
|
|
46
46
|
}
|
|
47
47
|
return true;
|
|
48
48
|
}
|
|
49
|
-
/** Raise a lower os_min_ver to the floor a capability needs; a higher one stays. */
|
|
50
|
-
function raiseOsMinVer(doc, current, floor) {
|
|
49
|
+
/** Raise a lower os_min_ver to the floor a capability needs; a higher one stays. Returns the notice. */
|
|
50
|
+
function raiseOsMinVer(doc, current, floor, capability) {
|
|
51
51
|
const osMinVer = doc.get('os_min_ver', true);
|
|
52
|
-
if (isScalar(osMinVer)
|
|
53
|
-
|
|
52
|
+
if (!isScalar(osMinVer) || isDsmAtLeast(current, floor))
|
|
53
|
+
return [];
|
|
54
|
+
osMinVer.value = floor;
|
|
55
|
+
return [`os_min_ver raised from ${current} to ${floor}: ${capability} needs DSM ${floor} or later.`];
|
|
56
|
+
}
|
|
57
|
+
function withNotes(result, notes) {
|
|
58
|
+
const all = [...(result.notes ?? []), ...notes];
|
|
59
|
+
return all.length ? { ...result, notes: all } : result;
|
|
54
60
|
}
|
|
55
61
|
/**
|
|
56
62
|
* `portal: {}` in dsm-package.yaml; the Go and binary starters already carry the UI and backend side.
|
|
@@ -67,9 +73,9 @@ function addPortal(root, result) {
|
|
|
67
73
|
const manifestPath = join(root, 'dsm-package.yaml');
|
|
68
74
|
const doc = parseDocument(readFileSync(manifestPath, 'utf8'));
|
|
69
75
|
doc.set('portal', doc.createNode({}, { flow: true }));
|
|
70
|
-
raiseOsMinVer(doc, loaded.manifest.os_min_ver, PORTAL_MIN_DSM);
|
|
76
|
+
const notes = raiseOsMinVer(doc, loaded.manifest.os_min_ver, PORTAL_MIN_DSM, 'portal');
|
|
71
77
|
writeFileSync(manifestPath, String(doc));
|
|
72
|
-
return { ...result, added: [...result.added, 'portal'] };
|
|
78
|
+
return withNotes({ ...result, added: [...result.added, 'portal'] }, notes);
|
|
73
79
|
}
|
|
74
80
|
export function addCapabilities(root, requested) {
|
|
75
81
|
const wanted = [...new Set(requested.flatMap(value => value.split(',')).map(value => value.trim()))];
|
|
@@ -129,8 +135,7 @@ export function addCapabilities(root, requested) {
|
|
|
129
135
|
for (const [key, value] of Object.entries(nativeCapabilitySettings(added)))
|
|
130
136
|
doc.setIn(['capabilities', key], value);
|
|
131
137
|
// rootOps needs DSM 7.1-42661 or later.
|
|
132
|
-
|
|
133
|
-
raiseOsMinVer(doc, m.os_min_ver, DEFAULT_MIN_DSM);
|
|
138
|
+
const notes = added.includes('root-ops') ? raiseOsMinVer(doc, m.os_min_ver, DEFAULT_MIN_DSM, 'root-ops') : [];
|
|
134
139
|
for (const file of destinations) {
|
|
135
140
|
const path = join(root, file);
|
|
136
141
|
mkdirSync(dirname(path), { recursive: true });
|
|
@@ -139,7 +144,7 @@ export function addCapabilities(root, requested) {
|
|
|
139
144
|
for (const file of deletions)
|
|
140
145
|
rmSync(join(root, file), { force: true });
|
|
141
146
|
writeFileSync(manifestPath, String(doc));
|
|
142
|
-
return { added, unchanged };
|
|
147
|
+
return withNotes({ added, unchanged }, notes);
|
|
143
148
|
}
|
|
144
149
|
finally {
|
|
145
150
|
rmSync(work, { recursive: true, force: true });
|
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
"broadwell",
|
|
8
8
|
"broadwellnk",
|
|
9
9
|
"broadwellnkv2",
|
|
10
|
+
"broadwellntb",
|
|
10
11
|
"broadwellntbap",
|
|
11
12
|
"bromolow",
|
|
12
13
|
"cedarview",
|
|
14
|
+
"coffeelake",
|
|
13
15
|
"denverton",
|
|
14
16
|
"epyc7002",
|
|
15
17
|
"epyc7003",
|
|
@@ -23,13 +25,14 @@
|
|
|
23
25
|
"purley",
|
|
24
26
|
"r1000",
|
|
25
27
|
"r1000nk",
|
|
28
|
+
"skylaked",
|
|
26
29
|
"v1000",
|
|
27
30
|
"v1000nk"
|
|
28
31
|
],
|
|
29
32
|
"platformOnly": []
|
|
30
33
|
},
|
|
31
34
|
"aarch64": {
|
|
32
|
-
"members": ["armada37xx", "rtd1296", "rtd1619b"],
|
|
35
|
+
"members": ["armada37xx", "rtd1296", "rtd1619", "rtd1619b"],
|
|
33
36
|
"platformOnly": []
|
|
34
37
|
},
|
|
35
38
|
"armv7": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type CommandRunner } from "../standalone/build.js";
|
|
2
2
|
import type { AppContract } from "../types.js";
|
|
3
|
-
import {
|
|
3
|
+
import type { NativeArchFamily } from "./dsm-arch.js";
|
|
4
4
|
export { gatewayEntryPath } from "../contract/web-launch.js";
|
|
5
5
|
/** Where the gateway CGI sits in the package payload; DSM serves `ui/` under /webman/3rdparty/<package>/. */
|
|
6
6
|
export declare const GATEWAY_CGI_PAYLOAD = "ui/cgi/gateway.cgi";
|
|
@@ -4,7 +4,7 @@ import { checkCgiBinary } from "../standalone/binary.js";
|
|
|
4
4
|
import { runCommand } from "../standalone/build.js";
|
|
5
5
|
import { resolvedWebAccess } from "../contract/web-launch.js";
|
|
6
6
|
import { templatesRoot } from "../template-paths.js";
|
|
7
|
-
import {
|
|
7
|
+
import { PINNED_GO_HINT, pinnedGoBuildEnv, pinnedGoProblem } from "./go-toolchain.js";
|
|
8
8
|
export { gatewayEntryPath } from "../contract/web-launch.js";
|
|
9
9
|
/** Where the gateway CGI sits in the package payload; DSM serves `ui/` under /webman/3rdparty/<package>/. */
|
|
10
10
|
export const GATEWAY_CGI_PAYLOAD = "ui/cgi/gateway.cgi";
|
|
@@ -29,18 +29,22 @@ export function buildGatewayBinary(input) {
|
|
|
29
29
|
const ldflags = ["-s", "-w", "-buildid=", `-X main.packageID=${input.packageId}`, `-X 'main.configJSON=${JSON.stringify(input.config)}'`].join(" ");
|
|
30
30
|
const result = (input.run ?? runCommand)("go", ["build", "-trimpath", "-buildvcs=false", "-ldflags", ldflags, "-o", out, "."], {
|
|
31
31
|
cwd: join(templatesRoot(), "_gateway"),
|
|
32
|
-
env: { ...process.env, ...
|
|
32
|
+
env: { ...process.env, ...pinnedGoBuildEnv(input.arch) },
|
|
33
33
|
});
|
|
34
34
|
if (result.missing) {
|
|
35
|
-
return { error: "GATEWAY_GO_MISSING", detail:
|
|
35
|
+
return { error: "GATEWAY_GO_MISSING", detail: `找不到 go 指令。DSM 驗證閘道需要 Go 1.21 以上版本(https://go.dev/dl/)才能建置。${PINNED_GO_HINT}` };
|
|
36
36
|
}
|
|
37
37
|
if (result.status !== 0) {
|
|
38
|
-
return { error: "GATEWAY_BUILD_FAILED", detail: `go build(${input.arch}
|
|
38
|
+
return { error: "GATEWAY_BUILD_FAILED", detail: `go build(${input.arch})失敗。${PINNED_GO_HINT}\n${result.stderr}` };
|
|
39
39
|
}
|
|
40
40
|
const problem = checkCgiBinary(input.work, out, input.arch);
|
|
41
41
|
if (problem) {
|
|
42
42
|
return { error: "GATEWAY_BUILD_FAILED", detail: problem.message };
|
|
43
43
|
}
|
|
44
|
+
const toolchainProblem = pinnedGoProblem(out);
|
|
45
|
+
if (toolchainProblem) {
|
|
46
|
+
return { error: "GATEWAY_BUILD_FAILED", detail: toolchainProblem };
|
|
47
|
+
}
|
|
44
48
|
return { binary: out };
|
|
45
49
|
}
|
|
46
50
|
/** Puts the CGI (mode 0755) and its readable configuration into the package payload. */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type NativeArchFamily } from "./dsm-arch.js";
|
|
2
|
+
/**
|
|
3
|
+
* The Go release that compiles every binary the CLI ships from its own
|
|
4
|
+
* templates, so their digests do not depend on the builder's Go. Each
|
|
5
|
+
* template go.mod names it in its `toolchain` line.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PINNED_GO_TOOLCHAIN = "go1.26.9";
|
|
8
|
+
/**
|
|
9
|
+
* The `go build` environment for a binary the CLI ships from its own templates
|
|
10
|
+
* (executor, lifecycle helper, daemon controller, gateway). GOTOOLCHAIN names
|
|
11
|
+
* the exact release, overriding `local` or `auto`: Go 1.21+ runs it from PATH
|
|
12
|
+
* or the module cache, or downloads it, and fails when it cannot.
|
|
13
|
+
*/
|
|
14
|
+
export declare function pinnedGoBuildEnv(family: NativeArchFamily): Record<string, string>;
|
|
15
|
+
/** The Go release recorded in a binary's build info (Go 1.18+ layout), or undefined. */
|
|
16
|
+
export declare function goBinaryVersion(file: string): string | undefined;
|
|
17
|
+
/** Why a CLI-owned binary cannot ship: it was not built by the pinned Go release. */
|
|
18
|
+
export declare function pinnedGoProblem(file: string): string | undefined;
|
|
19
|
+
/** Appended to a failed CLI-owned `go build`: what the build needs. */
|
|
20
|
+
export declare const PINNED_GO_HINT = "These binaries need go1.26.9: Go 1.21 or later downloads it automatically; offline, install go1.26.9 on PATH or allow GOPROXY to serve golang.org/toolchain.";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { goBuildEnv } from "./dsm-arch.js";
|
|
3
|
+
/**
|
|
4
|
+
* The Go release that compiles every binary the CLI ships from its own
|
|
5
|
+
* templates, so their digests do not depend on the builder's Go. Each
|
|
6
|
+
* template go.mod names it in its `toolchain` line.
|
|
7
|
+
*/
|
|
8
|
+
export const PINNED_GO_TOOLCHAIN = "go1.26.9";
|
|
9
|
+
/**
|
|
10
|
+
* The `go build` environment for a binary the CLI ships from its own templates
|
|
11
|
+
* (executor, lifecycle helper, daemon controller, gateway). GOTOOLCHAIN names
|
|
12
|
+
* the exact release, overriding `local` or `auto`: Go 1.21+ runs it from PATH
|
|
13
|
+
* or the module cache, or downloads it, and fails when it cannot.
|
|
14
|
+
*/
|
|
15
|
+
export function pinnedGoBuildEnv(family) {
|
|
16
|
+
return { ...goBuildEnv(family), GOTOOLCHAIN: PINNED_GO_TOOLCHAIN, GOFLAGS: "", GOEXPERIMENT: "", GOWORK: "off", GOAMD64: "v1", GOARM64: "v8.0" };
|
|
17
|
+
}
|
|
18
|
+
const BUILD_INFO_MAGIC = Buffer.from("\xff Go buildinf:", "latin1");
|
|
19
|
+
const BUILD_INFO_INLINE_STRINGS = 0x2;
|
|
20
|
+
/** The Go release recorded in a binary's build info (Go 1.18+ layout), or undefined. */
|
|
21
|
+
export function goBinaryVersion(file) {
|
|
22
|
+
const bytes = readFileSync(file);
|
|
23
|
+
const start = bytes.indexOf(BUILD_INFO_MAGIC);
|
|
24
|
+
if (start < 0 || !(bytes[start + 15] & BUILD_INFO_INLINE_STRINGS))
|
|
25
|
+
return undefined;
|
|
26
|
+
let length = 0, shift = 0, at = start + 32;
|
|
27
|
+
for (;;) {
|
|
28
|
+
const byte = bytes[at++];
|
|
29
|
+
if (byte === undefined || shift > 28)
|
|
30
|
+
return undefined;
|
|
31
|
+
length |= (byte & 0x7f) << shift;
|
|
32
|
+
shift += 7;
|
|
33
|
+
if (byte < 0x80)
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
return bytes.subarray(at, at + length).toString("latin1") || undefined;
|
|
37
|
+
}
|
|
38
|
+
/** Why a CLI-owned binary cannot ship: it was not built by the pinned Go release. */
|
|
39
|
+
export function pinnedGoProblem(file) {
|
|
40
|
+
const version = goBinaryVersion(file);
|
|
41
|
+
return version === PINNED_GO_TOOLCHAIN ? undefined : `${file} was built by ${version ?? "an unknown Go release"}, not ${PINNED_GO_TOOLCHAIN}.`;
|
|
42
|
+
}
|
|
43
|
+
/** Appended to a failed CLI-owned `go build`: what the build needs. */
|
|
44
|
+
export const PINNED_GO_HINT = `These binaries need ${PINNED_GO_TOOLCHAIN}: Go 1.21 or later downloads it automatically; offline, install ${PINNED_GO_TOOLCHAIN} on PATH or allow GOPROXY to serve golang.org/toolchain.`;
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, CommanderError } from "commander";
|
|
2
|
-
import { readFileSync, renameSync } from "node:fs";
|
|
2
|
+
import { existsSync, readFileSync, renameSync } from "node:fs";
|
|
3
3
|
import { resolve, dirname, join } from "node:path";
|
|
4
4
|
import { findProjectRoot } from "./discovery.js";
|
|
5
5
|
import { loadContract } from "./contract/load.js";
|
|
@@ -62,7 +62,11 @@ function formatSpkInspection(spk, report) {
|
|
|
62
62
|
"payload:",
|
|
63
63
|
...(report.uninstallCleanup ?? []).map(item => `Uninstall cleanup (if needed):${item.target} — ${item.condition} ${item.action}`),
|
|
64
64
|
...report.payload.map((e) => ` ${e.mode} ${e.path}`),
|
|
65
|
-
report.findings.length
|
|
65
|
+
report.findings.length
|
|
66
|
+
? "問題:"
|
|
67
|
+
: report.executor
|
|
68
|
+
? "檢查:沒有異常。管理員核准後會建立 root executor 排程(boot 與 control task),以 root 執行此 SPK 固定的 executor 與 policy。"
|
|
69
|
+
: "檢查:沒有 root 權限需求或異常。",
|
|
66
70
|
...report.findings.map((f) => ` - ${f}`),
|
|
67
71
|
].join("\n");
|
|
68
72
|
}
|
|
@@ -234,13 +238,15 @@ export async function runCli(argv) {
|
|
|
234
238
|
});
|
|
235
239
|
stdout(`已建立 ${options.template} 專案於 ${targetDir}`);
|
|
236
240
|
if (options.template === "native-go")
|
|
237
|
-
stdout(`下一步:\n cd ${dir}\n (cd backend && go test ./...)\n synopkgland build\n說明見 README.md。`);
|
|
241
|
+
stdout(`下一步:\n cd ${dir}\n (cd backend && go test ./...)\n${existsSync(join(targetDir, "frontend", "package.json")) ? " (cd frontend && npm ci)\n" : ""} synopkgland build\n說明見 README.md。`);
|
|
238
242
|
});
|
|
239
243
|
program
|
|
240
244
|
.command("add <caps...>")
|
|
241
245
|
.description(`加入能力(${CAPABILITY_NAMES.join("、")})或 portal 與 SDK-owned overlay;不覆寫既有應用檔案`)
|
|
242
246
|
.action((caps, _options, command) => {
|
|
243
247
|
const result = addCapabilities(rootOf(command), caps);
|
|
248
|
+
for (const note of result.notes ?? [])
|
|
249
|
+
console.error(`[注意] ${note}`);
|
|
244
250
|
stdout(`已新增:${result.added.join(", ") || "無"};已存在:${result.unchanged.join(", ") || "無"}`);
|
|
245
251
|
});
|
|
246
252
|
program
|
|
@@ -281,7 +287,7 @@ export async function runCli(argv) {
|
|
|
281
287
|
.option("--dev", "Development Package Identity")
|
|
282
288
|
.option("--share <slot=name>", "Compose 共用資料夾", (value, previous) => collectKv(value, previous, "--share"))
|
|
283
289
|
.option("--run-as <slot=name>", "Compose DSM 使用者", (value, previous) => collectKv(value, previous, "--run-as"))
|
|
284
|
-
.option("--param <NAME=value>", "Compose
|
|
290
|
+
.option("--param <NAME=value>", "安裝參數(Compose)或安裝精靈值(native-go/binary)", (value, previous) => collectKv(value, previous, "--param"))
|
|
285
291
|
.option("--dry-run", "只輸出本機部署計畫,不連接 NAS")
|
|
286
292
|
.action(async (options, command) => {
|
|
287
293
|
if (options.arch !== undefined &&
|
|
@@ -292,15 +298,15 @@ export async function runCli(argv) {
|
|
|
292
298
|
dev: options.dev,
|
|
293
299
|
});
|
|
294
300
|
if (plan.kind !== "container" &&
|
|
295
|
-
(options.share || options.runAs
|
|
296
|
-
throw failure("CLI_OPTION_INVALID", "native-go/binary 不接受
|
|
301
|
+
(options.share || options.runAs))
|
|
302
|
+
throw failure("CLI_OPTION_INVALID", "native-go/binary 不接受 --share/--run-as;安裝精靈值請用 --param。");
|
|
297
303
|
if (options.dryRun) {
|
|
298
304
|
emit("deploy", plan, JSON.stringify(plan, null, 2));
|
|
299
305
|
return;
|
|
300
306
|
}
|
|
301
307
|
if (plan.kind !== "container") {
|
|
302
308
|
const host = hostOf(options.host);
|
|
303
|
-
const output = await deployStandalone(plan, host);
|
|
309
|
+
const output = await deployStandalone(plan, host, { params: options.param });
|
|
304
310
|
const status = await standaloneInfo({ root: plan.root, host });
|
|
305
311
|
emit("deploy", { ...plan, output, status }, `已部署 ${plan.packageId}: ${output}\n${formatProjectInfo(status)}${plan.notes.length ? "\n" + plan.notes.join("\n") : ""}`);
|
|
306
312
|
return;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { StandaloneManifest } from "../standalone/manifest.js";
|
|
2
|
+
export type NativeInstallValuesResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
extraValues: Record<string, string>;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
code: string;
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Install wizard values for a native-go/binary deploy. Only an install-selected
|
|
12
|
+
* delegate asks the wizard for anything; preinst refuses an empty selection on
|
|
13
|
+
* the first install, so refuse it here before building or uploading.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveNativeInstallValues(manifest: StandaloneManifest, provided: Record<string, string>, state: {
|
|
16
|
+
installed: boolean;
|
|
17
|
+
}): NativeInstallValuesResult;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const USAGE = "synopkgland deploy --param delegate_share=<shared folder>,或 --param delegate_home=true";
|
|
2
|
+
/** Mirrors the preinst draft check in build-spk/delegate-scope.ts. */
|
|
3
|
+
function validShareName(name) {
|
|
4
|
+
return (name !== "" && name !== "." && !name.includes("..") &&
|
|
5
|
+
!/[/\\:"%\x00-\x1f\x7f]/.test(name) &&
|
|
6
|
+
!/^homes?$/i.test(name) && name.trim() === name && name.length <= 256);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Install wizard values for a native-go/binary deploy. Only an install-selected
|
|
10
|
+
* delegate asks the wizard for anything; preinst refuses an empty selection on
|
|
11
|
+
* the first install, so refuse it here before building or uploading.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveNativeInstallValues(manifest, provided, state) {
|
|
14
|
+
const fail = (code, message) => ({ ok: false, code, message });
|
|
15
|
+
const selected = manifest.capabilities.delegate?.scope === "install-selected";
|
|
16
|
+
const names = Object.keys(provided);
|
|
17
|
+
if (!selected && names.length)
|
|
18
|
+
return fail("DEPLOY_PARAM_UNDECLARED", `${manifest.package} has no install wizard values; remove --param ${names[0]}.`);
|
|
19
|
+
const unknown = names.find((name) => name !== "delegate_share" && name !== "delegate_home");
|
|
20
|
+
if (unknown)
|
|
21
|
+
return fail("DEPLOY_PARAM_UNDECLARED", `--param ${unknown} is not an install wizard value. Use: ${USAGE}.`);
|
|
22
|
+
const { delegate_share: share, delegate_home: home } = provided;
|
|
23
|
+
if (home !== undefined && home !== "true" && home !== "false")
|
|
24
|
+
return fail("DEPLOY_PARAM_TYPE_INVALID", "--param delegate_home must be true or false.");
|
|
25
|
+
if (share !== undefined && !validShareName(share))
|
|
26
|
+
return fail("DEPLOY_PARAM_TYPE_INVALID", `--param delegate_share must be one Shared Folder name, not a path, home or homes.`);
|
|
27
|
+
if (share !== undefined && home === "true")
|
|
28
|
+
return fail("DEPLOY_PARAM_TYPE_INVALID", "Choose either --param delegate_share or --param delegate_home=true, not both.");
|
|
29
|
+
if (selected && !state.installed && share === undefined && home !== "true")
|
|
30
|
+
return fail("DEPLOY_PARAM_REQUIRED", `The first install of ${manifest.package} must select the delegate scope: ${USAGE}.`);
|
|
31
|
+
return { ok: true, extraValues: { ...provided } };
|
|
32
|
+
}
|
package/dist/deploy/plan.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { type CommandRunner } from "../standalone/build.js";
|
|
1
2
|
import type { NativeArchFamily } from "../build-spk/dsm-arch.js";
|
|
2
3
|
import type { NasHost } from "../host/types.js";
|
|
3
4
|
export interface DeploymentPlan {
|
|
4
5
|
root: string;
|
|
5
|
-
kind: "native-go" | "binary" | "container";
|
|
6
|
+
kind: "native-go" | "binary" | "native-layout" | "container";
|
|
6
7
|
packageId: string;
|
|
7
8
|
version: string;
|
|
8
9
|
arch?: NativeArchFamily;
|
|
@@ -15,4 +16,7 @@ export declare function planDeployment(root: string, options?: {
|
|
|
15
16
|
arch?: NativeArchFamily;
|
|
16
17
|
dev?: boolean;
|
|
17
18
|
}): DeploymentPlan;
|
|
18
|
-
export declare function deployStandalone(plan: DeploymentPlan, host: NasHost
|
|
19
|
+
export declare function deployStandalone(plan: DeploymentPlan, host: NasHost, options?: {
|
|
20
|
+
params?: Record<string, string>;
|
|
21
|
+
run?: CommandRunner;
|
|
22
|
+
}): Promise<string>;
|