@synopackageland/cli 0.27.1 → 0.28.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/CHANGELOG.md +7 -0
- package/README.md +2 -2
- package/dist/standalone/compose-errors.js +3 -3
- package/dist/standalone/compose.js +2 -2
- package/dist/standalone/oidc-resume.d.ts +1 -1
- package/dist/standalone/oidc-resume.js +11 -6
- package/dist/standalone/spk.js +1 -1
- package/package.json +2 -2
- package/skills/reference/compose.md +12 -5
- package/skills/reference/lifecycle.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.28.0 (2026-10-24)
|
|
4
|
+
|
|
5
|
+
- Depend on templates `~0.28.0` with SDK/App 0.28.0 and UI 0.14.10. SDK 0.28.0 reuses executor/v0.27.0 through executor manifest format 1; no executor digests change.
|
|
6
|
+
- Default the Compose startup budget to 900 seconds and document slow-NAS readiness; the SDK owns health timing and the Starting status. No per-App option is added.
|
|
7
|
+
- Keep UI CGI scripts executable in built SPKs, and let external OIDC resume tokens reach only the fixed DSM CGI.
|
|
8
|
+
- The release gate checks SDK 0.27.1+ executor builds against the SDK executor manifest instead of requiring a frozen legacy table entry.
|
|
9
|
+
|
|
3
10
|
## 0.27.1 (2026-10-23)
|
|
4
11
|
|
|
5
12
|
- Read executor release mappings, toolchain and six payload pins from SDK executor manifest format 1. Accept compatible SDK minors independently of CLI versions; keep the frozen 0.26.0/0.27.0 fallback. Remove the CLI digest-recording script.
|
package/README.md
CHANGED
|
@@ -66,8 +66,8 @@ CLI-only patch releases can differ from the SDK patch. Compose import and SDK de
|
|
|
66
66
|
read the SDK pin from the installed templates; explicit App SDK declarations take precedence.
|
|
67
67
|
|
|
68
68
|
`init` and `add` read their templates from the locally installed
|
|
69
|
-
`@synopackageland/templates`. CLI 0.
|
|
70
|
-
update can select the latest templates patch in the 0.
|
|
69
|
+
`@synopackageland/templates`. CLI 0.28.0 depends on `~0.28.0`: npm installation or
|
|
70
|
+
update can select the latest templates patch in the 0.28 minor line. Templates
|
|
71
71
|
patches need only a templates release; update the npm installation to receive them.
|
|
72
72
|
The CLI never fetches templates at runtime, so offline use works after installation;
|
|
73
73
|
commit a lockfile and use `npm ci` to reproduce a chosen dependency tree.
|
|
@@ -13,7 +13,7 @@ export const COMPOSE_ERRORS = {
|
|
|
13
13
|
COMPOSE_STARTUP_INVALID: {
|
|
14
14
|
code: "COMPOSE_STARTUP_INVALID",
|
|
15
15
|
description: "The container startup budget is invalid.",
|
|
16
|
-
suggestion: "Set compose.startup_timeout_seconds to an integer from 2 to 900 seconds; the default is
|
|
16
|
+
suggestion: "Set compose.startup_timeout_seconds to an integer from 2 to 900 seconds; the default is 900, which a loaded HDD NAS may need. Read the same SYNOPKGLAND_STARTUP_BUDGET_SECONDS in the App bootstrap adapter.",
|
|
17
17
|
},
|
|
18
18
|
COMPOSE_STARTUP_TIMEOUT: {
|
|
19
19
|
code: "COMPOSE_STARTUP_TIMEOUT",
|
|
@@ -82,8 +82,8 @@ export const COMPOSE_ERRORS = {
|
|
|
82
82
|
},
|
|
83
83
|
COMPOSE_HEALTH_NOT_READY: {
|
|
84
84
|
code: "COMPOSE_HEALTH_NOT_READY",
|
|
85
|
-
description: "The App health endpoint did not return the expected status.",
|
|
86
|
-
suggestion: "Check the declared App health path/status and upstream health; redirects are not followed.",
|
|
85
|
+
description: "The App health endpoint did not return the expected status within the startup budget.",
|
|
86
|
+
suggestion: "Check the declared App health path/status and upstream health; redirects are not followed. daemon/daemon.log records how long the App stayed unavailable. Keep the default startup budget on slow NAS devices.",
|
|
87
87
|
},
|
|
88
88
|
COMPOSE_REQUEST_INVALID: {
|
|
89
89
|
code: "COMPOSE_REQUEST_INVALID",
|
|
@@ -77,7 +77,7 @@ export function readComposeApp(value, root, arches, fail, context = {}) {
|
|
|
77
77
|
if (value.startup_timeout_seconds !== undefined &&
|
|
78
78
|
(!Number.isInteger(value.startup_timeout_seconds) ||
|
|
79
79
|
value.startup_timeout_seconds < 2 || value.startup_timeout_seconds > 900))
|
|
80
|
-
return invalid("compose.startup_timeout_seconds must be an integer from 2 to 900 seconds (default
|
|
80
|
+
return invalid("compose.startup_timeout_seconds must be an integer from 2 to 900 seconds (default 900).", "COMPOSE_STARTUP_INVALID");
|
|
81
81
|
let hostUdp;
|
|
82
82
|
if (value.host_udp !== undefined) {
|
|
83
83
|
const ports = new Set();
|
|
@@ -178,7 +178,7 @@ export function composeDaemon(m) {
|
|
|
178
178
|
args: ["run"],
|
|
179
179
|
targets: m.compose.targets,
|
|
180
180
|
env: {},
|
|
181
|
-
timeouts: { stop: 30, status: 5, uninstall: 60, ...m.lifecycleTimeouts, start: m.compose.plan.startup_timeout_seconds ?? m.lifecycleTimeouts?.start ??
|
|
181
|
+
timeouts: { stop: 30, status: 5, uninstall: 60, ...m.lifecycleTimeouts, start: m.compose.plan.startup_timeout_seconds ?? m.lifecycleTimeouts?.start ?? 900 },
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
184
|
export function composeNetwork(m) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Only the fixed DSM CGI receives a resume token; external origins are resolved by the SDK. */
|
|
2
2
|
export declare function oidcResumeRuntime(pkg: string, ports: number[]): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Only the fixed DSM CGI receives a resume token; external origins are resolved by the SDK. */
|
|
2
2
|
export function oidcResumeRuntime(pkg, ports) {
|
|
3
3
|
return `(function(param) {
|
|
4
4
|
if (typeof param === 'string') {
|
|
@@ -14,13 +14,18 @@ export function oidcResumeRuntime(pkg, ports) {
|
|
|
14
14
|
}
|
|
15
15
|
if (!param || typeof param !== 'object' || Array.isArray(param)) return false;
|
|
16
16
|
var value = param && param.ssoResume;
|
|
17
|
-
if (typeof value !== 'string') return false;
|
|
17
|
+
if (typeof value !== 'string' || /\\s/.test(value)) return false;
|
|
18
|
+
var external = /^[A-Za-z0-9_-]{1,128}:x[01]:[0-9]{1,19}\\.[0-9]{1,19}$/.test(value);
|
|
18
19
|
var parts = /^([A-Za-z0-9_-]{1,128}):([0-9]{1,5})$/.exec(value);
|
|
19
|
-
if (!parts || ${JSON.stringify(ports)}.indexOf(Number(parts[2])) < 0) return false;
|
|
20
|
+
if (!external && (!parts || ${JSON.stringify(ports)}.indexOf(Number(parts[2])) < 0)) return false;
|
|
20
21
|
var target = new URL(${JSON.stringify(`/webman/3rdparty/${pkg}/sso/authorize.cgi`)},location.origin);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
if (external) {
|
|
23
|
+
target.searchParams.set('resume',value);
|
|
24
|
+
} else {
|
|
25
|
+
var app = new URL(location.origin); app.port = parts[2]; app.pathname = '/_sso/dsm-return';
|
|
26
|
+
target.searchParams.set('return',app.href);
|
|
27
|
+
target.searchParams.set('txn',parts[1]);
|
|
28
|
+
}
|
|
24
29
|
target.searchParams.set('login_attempt','1');
|
|
25
30
|
location.replace(target.href);
|
|
26
31
|
return true;
|
package/dist/standalone/spk.js
CHANGED
|
@@ -410,7 +410,7 @@ function copyUiTree(source, target) {
|
|
|
410
410
|
throw new StandaloneBuildError("STANDALONE_UI_TOO_LARGE", "The UI directory exceeds 64 MiB.");
|
|
411
411
|
}
|
|
412
412
|
copyFileSync(src, join(to, name));
|
|
413
|
-
chmodSync(join(to, name), FILE_MODE);
|
|
413
|
+
chmodSync(join(to, name), name.endsWith(".cgi") ? EXEC_MODE : FILE_MODE);
|
|
414
414
|
}
|
|
415
415
|
else {
|
|
416
416
|
throw new StandaloneBuildError("STANDALONE_UI_SPECIAL_FILE", `The UI directory may contain only regular files and directories: ${src}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Syno Package Land Developer Kit CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@napi-rs/keyring": "^2.1.1",
|
|
30
|
-
"@synopackageland/templates": "~0.
|
|
30
|
+
"@synopackageland/templates": "~0.28.0",
|
|
31
31
|
"ajv": "^8.17.1",
|
|
32
32
|
"commander": "^13.1.0",
|
|
33
33
|
"json-canonicalize": "^3.0.1",
|
|
@@ -37,14 +37,21 @@ scripts run as the package account; containers are managed by Container Manager.
|
|
|
37
37
|
|
|
38
38
|
## Startup budget
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
Omit `compose.startup_timeout_seconds`: the default of 900 seconds lets a loaded
|
|
41
|
+
HDD NAS with 2 GB RAM start the App. Declare a shorter value only with device
|
|
42
|
+
evidence; only integers from 2 through 900 are accepted.
|
|
42
43
|
Lock waiting, status, readiness, stability and handoff share that deadline; there
|
|
43
44
|
is no extra fixed handoff allowance. The cap is a policy bound, not a measured
|
|
44
45
|
DSM lifecycle limit. `daemon: {timeouts: {stop: 120, status: 15, uninstall: 300}}`
|
|
45
46
|
configures the other lifecycle phases without declaring a daemon payload.
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
One readiness probe may take 30 seconds. A health failure after startup closes
|
|
48
|
+
new ingress and the gateway shows a localized, self-refreshing starting page
|
|
49
|
+
(`app_starting` for API clients) while DSM status stays running; the App gets
|
|
50
|
+
the startup budget to recover before its gateway stops. Authority or generation
|
|
51
|
+
failures stop at once. The SDK raises stricter Compose healthcheck timing to
|
|
52
|
+
timeout 30s, retries 3 and start_period equal to the startup budget; declare the
|
|
53
|
+
health command only, without timing or short in-command limits such as
|
|
54
|
+
`curl --max-time 2`.
|
|
48
55
|
Use a matching SDK that implements the field and rebuild the App; older planners
|
|
49
56
|
are rejected for explicit budgets. The SDK plan drives generated daemon start
|
|
50
57
|
and supplies every container with `SYNOPKGLAND_STARTUP_BUDGET_SECONDS`, overriding
|
|
@@ -93,7 +100,7 @@ a build operator trust decision. `check`/`inspect` remain offline.
|
|
|
93
100
|
|
|
94
101
|
| Feature | Current behavior |
|
|
95
102
|
| --- | --- |
|
|
96
|
-
| Files in one directory, profiles, anchors, depends_on, healthcheck | Reference-loader semantics retained; DSM worker compatibility needs device acceptance |
|
|
103
|
+
| Files in one directory, profiles, anchors, depends_on, healthcheck | Reference-loader semantics retained; healthcheck timing receives the SDK slow-NAS floor; DSM worker compatibility needs device acceptance |
|
|
97
104
|
| Named local volumes | Stable package namespace, retained across recreation; inspect inventory |
|
|
98
105
|
| Private bind data | DSM build rejects COMPOSE_PRIVATE_BIND_TIMING_UNSUPPORTED: clean-install preinst precedes pkgvar creation, while worker acquire precedes postinst; no root initialization or automatic volume conversion |
|
|
99
106
|
| Image VOLUME | Build inventories verified image config and assigns a stable named volume |
|
|
@@ -115,7 +115,7 @@ Use existing `daemon.timeouts` for start/stop/status/uninstall (defaults
|
|
|
115
115
|
30/30/5/60 seconds). Start/stop/uninstall accept 2–3600 seconds and status accepts
|
|
116
116
|
1–3600. A `daemon` containing only `timeouts` declares budgets without an
|
|
117
117
|
executable, including background and Compose Apps; Compose start still uses
|
|
118
|
-
`compose.startup_timeout_seconds` (
|
|
118
|
+
`compose.startup_timeout_seconds` (900, 2–900). Background user-manager recovery
|
|
119
119
|
uses the start allowance and its generated package user unit uses the stop
|
|
120
120
|
allowance with `KillMode=control-group`.
|
|
121
121
|
|