@synopackageland/cli 0.17.6 → 0.17.8
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
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.17.8 (2026-10-20)
|
|
4
|
+
|
|
5
|
+
- Update SDK 0.17.7 executor and lifecycle digests for the administrator-role fix.
|
|
6
|
+
|
|
7
|
+
## 0.17.7 (2026-10-20)
|
|
8
|
+
|
|
9
|
+
- Inspect Compose Apps with custom icons and localized titles using their archived build inputs, preserving every icon size and strict launcher validation. Preserve declared daemon uninstall hooks when checking fixed lifecycle scripts.
|
|
10
|
+
|
|
3
11
|
## 0.17.6 (2026-10-20)
|
|
4
12
|
|
|
5
13
|
- Inspect sharedFolder, Portal and install-selected Apps by reconstructing fixed lifecycle scripts from their complete inputs, including native HTTPS ingress and App hooks.
|
|
@@ -34,5 +34,7 @@ export declare function iconReport(root: string, icon: string | undefined): Icon
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function windowIconTemplate(icons: PackageIcons): string;
|
|
36
36
|
export declare function windowIconFile(icons: PackageIcons, size: number): string;
|
|
37
|
+
/** Recover the build's exact icon inputs from an SPK, including hand-drawn sizes. */
|
|
38
|
+
export declare function readDsmWindowIcons(uiDir: string): PackageIcons;
|
|
37
39
|
export declare function writeDsmWindowIcons(uiDir: string, icons: PackageIcons): void;
|
|
38
40
|
export declare function writePackageCenterIcons(spkRoot: string, icons: PackageIcons): void;
|
|
@@ -149,6 +149,36 @@ export function windowIconTemplate(icons) {
|
|
|
149
149
|
export function windowIconFile(icons, size) {
|
|
150
150
|
return windowIconTemplate(icons).replace("{0}", String(size));
|
|
151
151
|
}
|
|
152
|
+
/** Recover the build's exact icon inputs from an SPK, including hand-drawn sizes. */
|
|
153
|
+
export function readDsmWindowIcons(uiDir) {
|
|
154
|
+
const dir = join(uiDir, "images");
|
|
155
|
+
const candidates = readdirSync(dir).filter(name => /^app_[a-f0-9]{12}_256\.png$/.test(name));
|
|
156
|
+
if (candidates.length !== 1)
|
|
157
|
+
throw new Error("expected one complete DSM window icon set");
|
|
158
|
+
const template = candidates[0].replace(/_256\.png$/, "_{0}.png");
|
|
159
|
+
const window = new Map();
|
|
160
|
+
let solid = false;
|
|
161
|
+
for (const size of WINDOW_ICON_SIZES) {
|
|
162
|
+
const name = template.replace("{0}", String(size));
|
|
163
|
+
const bytes = readFileSync(join(dir, name));
|
|
164
|
+
if (bytes.length > MAX_ICON_BYTES)
|
|
165
|
+
throw new Error(`${name}: invalid DSM window icon`);
|
|
166
|
+
const image = decodePng(bytes);
|
|
167
|
+
if (image.width !== size || image.height !== size)
|
|
168
|
+
throw new Error(`${name}: invalid DSM window icon`);
|
|
169
|
+
if (size === 256)
|
|
170
|
+
solid = isSolid(image);
|
|
171
|
+
window.set(size, bytes);
|
|
172
|
+
}
|
|
173
|
+
const icons = {
|
|
174
|
+
source: window.get(256).equals(defaultPackageIcons().packageIcon256) ? "default" : "custom",
|
|
175
|
+
window, solid,
|
|
176
|
+
packageIcon: window.get(64), packageIcon256: window.get(256),
|
|
177
|
+
};
|
|
178
|
+
if (windowIconTemplate(icons) !== `images/${template}`)
|
|
179
|
+
throw new Error("DSM window icon filenames differ from their content hash");
|
|
180
|
+
return icons;
|
|
181
|
+
}
|
|
152
182
|
export function writeDsmWindowIcons(uiDir, icons) {
|
|
153
183
|
mkdirSync(join(uiDir, "images"), { recursive: true });
|
|
154
184
|
for (const [size, png] of icons.window)
|
|
@@ -53,5 +53,16 @@
|
|
|
53
53
|
"armv7": "57b6350c2812783cb536384f8b363c26d894af6589b5f19464d71d8d0a8035d5"
|
|
54
54
|
},
|
|
55
55
|
"goToolchain": "go1.26.9"
|
|
56
|
+
},
|
|
57
|
+
"0.17.7": {
|
|
58
|
+
"x86_64": "6d9d5a12ac4c990639b31c555560a1b6e49cbe1c267c626a23b91833dcc4452e",
|
|
59
|
+
"aarch64": "efbed582ce1249fed09de72b7bbe553510a55553e44ccf76fa93c684864e8bb8",
|
|
60
|
+
"armv7": "670f83c3349497263c96b0244ec142153c094d5e223dae091c9c8614c0ea04b6",
|
|
61
|
+
"lifecycle": {
|
|
62
|
+
"x86_64": "9bb53301670b43cdcd6e21cebac99ab7abd82962d874f32423a81e6cb49d4972",
|
|
63
|
+
"aarch64": "38fe873c86eb102c850baa1f304114a83a31d1df72defd22792bc37610fec9bb",
|
|
64
|
+
"armv7": "256fb348b275da7ac5728a3cb7cb7c65660de0d5c2c59430ab4f5ade1b0a3681"
|
|
65
|
+
},
|
|
66
|
+
"goToolchain": "go1.26.9"
|
|
56
67
|
}
|
|
57
68
|
}
|
|
@@ -24,6 +24,7 @@ import { daemonConfig, readDaemon, readLifecycleTimeouts } from "./daemon.js";
|
|
|
24
24
|
import { ROOT_SCRIPT_HINTS } from "./root-ops.js";
|
|
25
25
|
import { DELETE_STATE_KEY } from "../build-spk/uninstall-wizard.js";
|
|
26
26
|
import { readUninstallRecord, stateItemTexts } from "./uninstall.js";
|
|
27
|
+
import { DSM_LANGS } from "./i18n.js";
|
|
27
28
|
import { BACKGROUND_UNIT_DIR, BACKGROUND_WORKER_PAYLOAD, BRIDGE_WORKER_ARGS, backgroundUnitName, renderBackgroundUnit, } from "./background.js";
|
|
28
29
|
import { renderStandaloneResource } from "./resource.js";
|
|
29
30
|
import { recoverSharedFolder, renderSharedFolderUpgradeWizardFiles, sharedFolderInstallSteps, SHARED_FOLDER_MARKER, } from "./shared-folder.js";
|
|
@@ -39,7 +40,7 @@ import { listPortExposures, loadCompose } from "../compose/analyze.js";
|
|
|
39
40
|
import { uninstallCleanup, } from "../runtime/uninstall-cleanup.js";
|
|
40
41
|
import { PORTAL_JSON_RELPATH, PORTAL_MUSTACHE_RELPATH, renderPortalJson, renderPortalLifecycle, renderPortalMustache, renderPortalWizardStep, } from "../portal/package.js";
|
|
41
42
|
import { isPortalAlias } from "../portal/alias.js";
|
|
42
|
-
import { defaultPackageIcons, MAX_ICON_BYTES } from "../build-spk/dsm-icons.js";
|
|
43
|
+
import { defaultPackageIcons, MAX_ICON_BYTES, readDsmWindowIcons } from "../build-spk/dsm-icons.js";
|
|
43
44
|
import { isDefaultLoginAsset } from "../build-spk/login-style.js";
|
|
44
45
|
import { decodePng } from "../build-spk/png.js";
|
|
45
46
|
/** The SPK kind of each sdk-package.json backend a CGI is built for: Go itself, or the runtime of an App in another language. */
|
|
@@ -198,7 +199,7 @@ export async function inspectSpk(spkPath, expectedKind) {
|
|
|
198
199
|
if (standalone && portal)
|
|
199
200
|
findings.push(...inspectPortalInfo(info, hasExecutor));
|
|
200
201
|
const daemon = standalone
|
|
201
|
-
? await checkDaemon(dir, info, paths, payload, findings, hasExecutor, background, combined, nativeGateway)
|
|
202
|
+
? await checkDaemon(dir, info, paths, payload, findings, hasExecutor, background, combined, nativeGateway, uninstallHook?.uninstall)
|
|
202
203
|
: undefined;
|
|
203
204
|
if (background)
|
|
204
205
|
checkBackground(dir, info, payload, findings, hasExecutor, daemon, kind !== "native-go", metadata.lifecycleTimeouts);
|
|
@@ -627,6 +628,7 @@ async function inspectUnifiedCompose(dir, payload, metadata, findings) {
|
|
|
627
628
|
displayname: info.displayname,
|
|
628
629
|
description: info.description,
|
|
629
630
|
maintainer: info.maintainer,
|
|
631
|
+
i18n: { info: archivedInfoTranslations(info) },
|
|
630
632
|
os_min_ver: info.os_min_ver,
|
|
631
633
|
build: Number(info.version?.split("-").pop()),
|
|
632
634
|
arches: [arch],
|
|
@@ -653,7 +655,10 @@ async function inspectUnifiedCompose(dir, payload, metadata, findings) {
|
|
|
653
655
|
throw new Error("unexpected worker resource; unapproved Shares must never auto-acquire");
|
|
654
656
|
if (readdirSync(join(dir, "conf")).some((n) => !["privilege", ...(resource ? ["resource"] : [])].includes(n)))
|
|
655
657
|
throw new Error("unexpected Compose resource");
|
|
656
|
-
|
|
658
|
+
// Replay build's shared renderer with the archived bytes, never a project
|
|
659
|
+
// path or the SDK default. Each hand-drawn icon size affects the URL hash.
|
|
660
|
+
const icons = readDsmWindowIcons(join(root, "ui"));
|
|
661
|
+
if (readOptional(join(root, "ui/config")) !== renderUiConfig(manifest, icons))
|
|
657
662
|
throw new Error("LAUNCHER_TYPE_MISMATCH classless Compose must use the shared url launcher");
|
|
658
663
|
if (g &&
|
|
659
664
|
(cfg.package !== info.package ||
|
|
@@ -787,7 +792,7 @@ async function recoverCompose(dir, value, findings) {
|
|
|
787
792
|
return undefined;
|
|
788
793
|
}
|
|
789
794
|
}
|
|
790
|
-
async function checkDaemon(dir, info, paths, payload, findings, executor, background, combined, nativeGateway) {
|
|
795
|
+
async function checkDaemon(dir, info, paths, payload, findings, executor, background, combined, nativeGateway, uninstall) {
|
|
791
796
|
if (![...paths].some((path) => path.startsWith("daemon/")))
|
|
792
797
|
return;
|
|
793
798
|
if (info.precheckstartstop !== "yes")
|
|
@@ -843,6 +848,7 @@ async function checkDaemon(dir, info, paths, payload, findings, executor, backgr
|
|
|
843
848
|
root: dir,
|
|
844
849
|
...(combined ? { lifecycleTimeouts: daemon.timeouts } : {}),
|
|
845
850
|
daemon,
|
|
851
|
+
uninstall,
|
|
846
852
|
...combined,
|
|
847
853
|
capabilities: {
|
|
848
854
|
...(executor ? { rootOps: true } : {}),
|
|
@@ -879,6 +885,22 @@ async function checkDaemon(dir, info, paths, payload, findings, executor, backgr
|
|
|
879
885
|
findings.push("daemon/config.json or the payload does not match the fixed daemon contract");
|
|
880
886
|
}
|
|
881
887
|
}
|
|
888
|
+
/** INFO retains the localized title inputs used by build's ui/config renderer. */
|
|
889
|
+
function archivedInfoTranslations(info) {
|
|
890
|
+
const translations = {};
|
|
891
|
+
for (const [locale, lang] of Object.entries(DSM_LANGS)) {
|
|
892
|
+
if (locale === "en")
|
|
893
|
+
continue;
|
|
894
|
+
const displayname = info[`displayname_${lang}`];
|
|
895
|
+
const description = info[`description_${lang}`];
|
|
896
|
+
if (displayname || description)
|
|
897
|
+
translations[locale] = {
|
|
898
|
+
...(displayname ? { displayname } : {}),
|
|
899
|
+
...(description ? { description } : {}),
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
return translations;
|
|
903
|
+
}
|
|
882
904
|
function readInfo(path, findings, kind, compose = false) {
|
|
883
905
|
if (!existsSync(path)) {
|
|
884
906
|
findings.push("INFO is missing");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/cli",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.8",
|
|
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.17.
|
|
30
|
+
"@synopackageland/templates": "0.17.10",
|
|
31
31
|
"ajv": "^8.17.1",
|
|
32
32
|
"commander": "^13.1.0",
|
|
33
33
|
"json-canonicalize": "^3.0.1",
|