@synopackageland/cli 0.1.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 +13 -0
- package/dist/attestation/app-package.d.ts +86 -0
- package/dist/attestation/app-package.js +199 -0
- package/dist/attestation/install-on-host.d.ts +14 -0
- package/dist/attestation/install-on-host.js +52 -0
- package/dist/attestation/keyring.d.ts +21 -0
- package/dist/attestation/keyring.js +168 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +14 -0
- package/dist/build-spk/dsm-arch.d.ts +4 -0
- package/dist/build-spk/dsm-arch.js +32 -0
- package/dist/build-spk/dsm-icons.d.ts +2 -0
- package/dist/build-spk/dsm-icons.js +67 -0
- package/dist/build-spk/generator.d.ts +43 -0
- package/dist/build-spk/generator.js +653 -0
- package/dist/build-spk/native-payload.d.ts +22 -0
- package/dist/build-spk/native-payload.js +654 -0
- package/dist/build-spk/reproducible-archive.d.ts +8 -0
- package/dist/build-spk/reproducible-archive.js +34 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +345 -0
- package/dist/compose/analyze.d.ts +25 -0
- package/dist/compose/analyze.js +346 -0
- package/dist/compose/env.d.ts +7 -0
- package/dist/compose/env.js +36 -0
- package/dist/compose/privilege.d.ts +14 -0
- package/dist/compose/privilege.js +102 -0
- package/dist/compose/runner.d.ts +32 -0
- package/dist/compose/runner.js +84 -0
- package/dist/contract/load.d.ts +25 -0
- package/dist/contract/load.js +87 -0
- package/dist/contract/schema-validate.d.ts +3 -0
- package/dist/contract/schema-validate.js +50 -0
- package/dist/contract/validate.d.ts +3 -0
- package/dist/contract/validate.js +80 -0
- package/dist/contract/web-launch.d.ts +19 -0
- package/dist/contract/web-launch.js +94 -0
- package/dist/deploy/catalog-publish.d.ts +3 -0
- package/dist/deploy/catalog-publish.js +7 -0
- package/dist/deploy/deploy.d.ts +22 -0
- package/dist/deploy/deploy.js +136 -0
- package/dist/deploy/identity-shared.d.ts +3 -0
- package/dist/deploy/identity-shared.js +14 -0
- package/dist/deploy/identity.d.ts +7 -0
- package/dist/deploy/identity.js +20 -0
- package/dist/deploy/package-source.d.ts +7 -0
- package/dist/deploy/package-source.js +17 -0
- package/dist/deploy/run-as-values.d.ts +18 -0
- package/dist/deploy/run-as-values.js +48 -0
- package/dist/deploy/share-values.d.ts +20 -0
- package/dist/deploy/share-values.js +60 -0
- package/dist/deploy/spk-info.d.ts +12 -0
- package/dist/deploy/spk-info.js +41 -0
- package/dist/deploy/spk-version.d.ts +4 -0
- package/dist/deploy/spk-version.js +64 -0
- package/dist/dev.d.ts +13 -0
- package/dist/dev.js +31 -0
- package/dist/discovery.d.ts +8 -0
- package/dist/discovery.js +22 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +18 -0
- package/dist/host/broker-paths.d.ts +1 -0
- package/dist/host/broker-paths.js +1 -0
- package/dist/host/catalog-install.d.ts +59 -0
- package/dist/host/catalog-install.js +326 -0
- package/dist/host/credentials.d.ts +2 -0
- package/dist/host/credentials.js +37 -0
- package/dist/host/digests.d.ts +5 -0
- package/dist/host/digests.js +55 -0
- package/dist/host/dsm-client.d.ts +6 -0
- package/dist/host/dsm-client.js +290 -0
- package/dist/host/dsm-http.d.ts +1 -0
- package/dist/host/dsm-http.js +87 -0
- package/dist/host/fake-nas.d.ts +16 -0
- package/dist/host/fake-nas.js +116 -0
- package/dist/host/open-url.d.ts +5 -0
- package/dist/host/open-url.js +13 -0
- package/dist/host/share-lookup.d.ts +3 -0
- package/dist/host/share-lookup.js +144 -0
- package/dist/host/types.d.ts +67 -0
- package/dist/host/types.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +14 -0
- package/dist/info.d.ts +17 -0
- package/dist/info.js +34 -0
- package/dist/init.d.ts +4 -0
- package/dist/init.js +31 -0
- package/dist/inspect.d.ts +13 -0
- package/dist/inspect.js +102 -0
- package/dist/load-env.d.ts +1 -0
- package/dist/load-env.js +31 -0
- package/dist/log.d.ts +13 -0
- package/dist/log.js +20 -0
- package/dist/mock-broker/bootstrap.d.ts +2 -0
- package/dist/mock-broker/bootstrap.js +8 -0
- package/dist/mock-broker/files.d.ts +60 -0
- package/dist/mock-broker/files.js +408 -0
- package/dist/mock-broker/oidc.d.ts +31 -0
- package/dist/mock-broker/oidc.js +161 -0
- package/dist/mock-broker/path.d.ts +9 -0
- package/dist/mock-broker/path.js +50 -0
- package/dist/mock-broker/server.d.ts +19 -0
- package/dist/mock-broker/server.js +350 -0
- package/dist/publish/build-ledger.d.ts +22 -0
- package/dist/publish/build-ledger.js +26 -0
- package/dist/publish/community-path.d.ts +6 -0
- package/dist/publish/community-path.js +41 -0
- package/dist/publish/curated-release.d.ts +78 -0
- package/dist/publish/curated-release.js +693 -0
- package/dist/publish/file-build-ledger.d.ts +18 -0
- package/dist/publish/file-build-ledger.js +268 -0
- package/dist/publish/github-pr.d.ts +25 -0
- package/dist/publish/github-pr.js +85 -0
- package/dist/publish/github-repo.d.ts +8 -0
- package/dist/publish/github-repo.js +21 -0
- package/dist/publish/publish.d.ts +23 -0
- package/dist/publish/publish.js +128 -0
- package/dist/publish/sync-definition.d.ts +4 -0
- package/dist/publish/sync-definition.js +48 -0
- package/dist/skill.d.ts +10 -0
- package/dist/skill.js +50 -0
- package/dist/templates/compose-import/compose.yaml +11 -0
- package/dist/templates/compose-import/synology-app.yaml +15 -0
- package/dist/templates/hello-files/com.synology.hello.files.dev.spk +0 -0
- package/dist/templates/hello-files/compose.yaml +8 -0
- package/dist/templates/hello-files/synology-app.yaml +13 -0
- package/dist/templates/hello-web/compose.yaml +7 -0
- package/dist/templates/hello-web/html/app.js +23 -0
- package/dist/templates/hello-web/html/index.html +15 -0
- package/dist/templates/hello-web/html/sdk.js +68 -0
- package/dist/templates/hello-web/synology-app.yaml +13 -0
- package/dist/templates/hello-web-page/com.synology.hello.web.page.dev.spk +0 -0
- package/dist/templates/hello-web-page/compose.yaml +7 -0
- package/dist/templates/hello-web-page/html/app.js +23 -0
- package/dist/templates/hello-web-page/html/index.html +15 -0
- package/dist/templates/hello-web-page/html/sdk.js +68 -0
- package/dist/templates/hello-web-page/synology-app.yaml +13 -0
- package/dist/test-command.d.ts +13 -0
- package/dist/test-command.js +26 -0
- package/dist/test-host.d.ts +13 -0
- package/dist/test-host.js +24 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.js +1 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.js +103 -0
- package/package.json +38 -0
- package/schema/synology-app.schema.json +137 -0
- package/skills/SKILL.md +51 -0
- package/skills/reference/create.md +34 -0
- package/skills/reference/deploy.md +41 -0
- package/skills/reference/diagnose.md +42 -0
- package/skills/reference/files.md +37 -0
- package/skills/reference/identity.md +31 -0
- package/skills/reference/wrap.md +35 -0
- package/templates/compose-import/compose.yaml +11 -0
- package/templates/compose-import/synology-app.yaml +15 -0
- package/templates/hello-files/com.synology.hello.files.dev.spk +0 -0
- package/templates/hello-files/compose.yaml +8 -0
- package/templates/hello-files/synology-app.yaml +13 -0
- package/templates/hello-web/compose.yaml +7 -0
- package/templates/hello-web/html/app.js +23 -0
- package/templates/hello-web/html/index.html +15 -0
- package/templates/hello-web/html/sdk.js +68 -0
- package/templates/hello-web/synology-app.yaml +13 -0
- package/templates/hello-web-page/com.synology.hello.web.page.dev.spk +0 -0
- package/templates/hello-web-page/compose.yaml +7 -0
- package/templates/hello-web-page/html/app.js +23 -0
- package/templates/hello-web-page/html/index.html +15 -0
- package/templates/hello-web-page/html/sdk.js +68 -0
- package/templates/hello-web-page/synology-app.yaml +13 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AppContract } from "../types.js";
|
|
2
|
+
export declare const SHARE_VALUE_REQUIRED = "SHARE_VALUE_REQUIRED";
|
|
3
|
+
export declare const SHARE_LOGICAL_NAME_REQUIRED = "SHARE_LOGICAL_NAME_REQUIRED";
|
|
4
|
+
export declare const SHARE_NOT_FOUND = "SHARE_NOT_FOUND";
|
|
5
|
+
export declare function sharedFolderParameterNames(contract: AppContract): string[];
|
|
6
|
+
export declare function isPhysicalSharePath(value: string): boolean;
|
|
7
|
+
export type ShareResolveResult = {
|
|
8
|
+
ok: true;
|
|
9
|
+
extraValues: Record<string, string>;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
code: string;
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function resolveSharedFolderExtraValues(input: {
|
|
16
|
+
requiredKeys: string[];
|
|
17
|
+
provided: Record<string, string>;
|
|
18
|
+
existingEnv?: Record<string, string>;
|
|
19
|
+
lookup: (logicalName: string) => Promise<string | undefined>;
|
|
20
|
+
}): Promise<ShareResolveResult>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { collectInstallParameters } from "../contract/load.js";
|
|
2
|
+
export const SHARE_VALUE_REQUIRED = "SHARE_VALUE_REQUIRED";
|
|
3
|
+
export const SHARE_LOGICAL_NAME_REQUIRED = "SHARE_LOGICAL_NAME_REQUIRED";
|
|
4
|
+
export const SHARE_NOT_FOUND = "SHARE_NOT_FOUND";
|
|
5
|
+
export function sharedFolderParameterNames(contract) {
|
|
6
|
+
return collectInstallParameters(contract)
|
|
7
|
+
.filter((item) => item.param.type === "shared_folder")
|
|
8
|
+
.map((item) => item.name);
|
|
9
|
+
}
|
|
10
|
+
export function isPhysicalSharePath(value) {
|
|
11
|
+
const trimmed = value.trim();
|
|
12
|
+
if (trimmed.startsWith("/")) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return /(?:^|\/)volume(?:USB|SATA)?\d+/i.test(trimmed);
|
|
16
|
+
}
|
|
17
|
+
export async function resolveSharedFolderExtraValues(input) {
|
|
18
|
+
if (input.requiredKeys.length === 0) {
|
|
19
|
+
return { ok: true, extraValues: {} };
|
|
20
|
+
}
|
|
21
|
+
const extraValues = {};
|
|
22
|
+
const missing = [];
|
|
23
|
+
for (const key of input.requiredKeys) {
|
|
24
|
+
const raw = input.provided[key];
|
|
25
|
+
if (raw === undefined || raw.trim() === "") {
|
|
26
|
+
const existing = input.existingEnv?.[key];
|
|
27
|
+
if (typeof existing === "string" && existing.trim() !== "") {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
missing.push(key);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const logical = raw.trim();
|
|
34
|
+
if (isPhysicalSharePath(logical)) {
|
|
35
|
+
return {
|
|
36
|
+
ok: false,
|
|
37
|
+
code: SHARE_LOGICAL_NAME_REQUIRED,
|
|
38
|
+
message: `Shared Folder「${key}」必須是這台 NAS 上的邏輯 Share 名,不能傳 /volume1/... 實體路徑。`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const resolved = await input.lookup(logical);
|
|
42
|
+
if (!resolved || resolved.trim() === "") {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
code: SHARE_NOT_FOUND,
|
|
46
|
+
message: `這台 NAS 找不到 Shared Folder「${logical}」。請改傳已存在的邏輯名;不會猜測實體路徑。`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
extraValues[key] = resolved;
|
|
50
|
+
}
|
|
51
|
+
if (missing.length > 0) {
|
|
52
|
+
const example = `--share ${missing[0]}=photos`;
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
code: SHARE_VALUE_REQUIRED,
|
|
56
|
+
message: `契約有 Shared Folder 槽「${missing.join("、")}」。請傳每個槽在這台 NAS 上的邏輯 Share 名(例如 ${example}),或改走會跳出 Package Center 安裝精靈的安裝。禁止以 extra_values={} 繼續,否則會 bind 空路徑(Container Manager 2202)。`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return { ok: true, extraValues };
|
|
60
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface SpkInfo {
|
|
2
|
+
package: string;
|
|
3
|
+
version: string;
|
|
4
|
+
displayname?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
maintainer?: string;
|
|
7
|
+
install_dep_packages?: string;
|
|
8
|
+
os_min_ver?: string;
|
|
9
|
+
startable?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function parseSpkInfoContent(info: string): SpkInfo;
|
|
12
|
+
export declare function readSpkInfo(spkPath: string): Promise<SpkInfo>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { mkdtempSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { extractSpk } from "../build-spk/generator.js";
|
|
6
|
+
function parseInfoField(info, key) {
|
|
7
|
+
const match = new RegExp(`^${key}="((?:\\\\.|[^"\\\\])*)"`, "m").exec(info);
|
|
8
|
+
if (!match) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
return match[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
12
|
+
}
|
|
13
|
+
export function parseSpkInfoContent(info) {
|
|
14
|
+
const packageName = parseInfoField(info, "package");
|
|
15
|
+
const version = parseInfoField(info, "version");
|
|
16
|
+
if (!packageName || !version) {
|
|
17
|
+
throw new Error("SPK INFO missing package or version");
|
|
18
|
+
}
|
|
19
|
+
const startableRaw = parseInfoField(info, "startable");
|
|
20
|
+
return {
|
|
21
|
+
package: packageName,
|
|
22
|
+
version,
|
|
23
|
+
displayname: parseInfoField(info, "displayname"),
|
|
24
|
+
description: parseInfoField(info, "description"),
|
|
25
|
+
maintainer: parseInfoField(info, "maintainer"),
|
|
26
|
+
install_dep_packages: parseInfoField(info, "install_dep_packages"),
|
|
27
|
+
os_min_ver: parseInfoField(info, "os_min_ver"),
|
|
28
|
+
startable: startableRaw === undefined ? undefined : startableRaw === "yes",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export async function readSpkInfo(spkPath) {
|
|
32
|
+
const dir = mkdtempSync(join(tmpdir(), "syno-spk-info-"));
|
|
33
|
+
try {
|
|
34
|
+
await extractSpk(spkPath, dir);
|
|
35
|
+
const info = readFileSync(join(dir, "INFO"), "utf8");
|
|
36
|
+
return parseSpkInfoContent(info);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
rmSync(dir, { recursive: true, force: true });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ProjectRoot } from "../discovery.js";
|
|
2
|
+
import type { NasHost } from "../host/types.js";
|
|
3
|
+
export declare function resolveDeploySpkVersion(project: ProjectRoot, host: NasHost, packageId: string): Promise<string>;
|
|
4
|
+
export declare function publishDeploySpk(spkPath: string): Promise<string>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { loadContract } from "../contract/load.js";
|
|
2
|
+
import { comparePackageVersions } from "@synopackageland/package-source/index-manifest";
|
|
3
|
+
import { resolveNextSpkVersion } from "@synopackageland/package-source/next-version";
|
|
4
|
+
import { fetchPackageSourceManifest, fetchPackageSourceManifestFromR2, resolvePublishTarget, } from "@synopackageland/package-source/publish-spk";
|
|
5
|
+
import { publishBuiltSpk } from "./catalog-publish.js";
|
|
6
|
+
import { isDevelopmentPackageIdentity } from "./identity-shared.js";
|
|
7
|
+
const LIVE_TEST_FALLBACK_ORIGIN = "https://syno-package-source-throwaway.bidacumen.workers.dev";
|
|
8
|
+
function defaultSpkVersion(contractVersion) {
|
|
9
|
+
return /-\d+$/.test(contractVersion) ? contractVersion : `${contractVersion}-0001`;
|
|
10
|
+
}
|
|
11
|
+
function bumpBuildNumber(version) {
|
|
12
|
+
const match = /^(.+)-(\d+)$/.exec(version);
|
|
13
|
+
if (!match) {
|
|
14
|
+
return `${version}-0002`;
|
|
15
|
+
}
|
|
16
|
+
const next = String(Number(match[2]) + 1).padStart(4, "0");
|
|
17
|
+
return `${match[1]}-${next}`;
|
|
18
|
+
}
|
|
19
|
+
async function resolvePackageSourceManifest(origin) {
|
|
20
|
+
try {
|
|
21
|
+
const manifest = await fetchPackageSourceManifest(origin);
|
|
22
|
+
if (manifest) {
|
|
23
|
+
return manifest;
|
|
24
|
+
}
|
|
25
|
+
if (origin !== LIVE_TEST_FALLBACK_ORIGIN) {
|
|
26
|
+
return fetchPackageSourceManifest(LIVE_TEST_FALLBACK_ORIGIN);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
async function resolveOfflineDeploySpkVersion(project, host, packageId) {
|
|
35
|
+
const contract = loadContract(project.contractPath).contract;
|
|
36
|
+
const base = defaultSpkVersion(String(contract.version ?? "1.0.0"));
|
|
37
|
+
if (!(await host.isPackageInstalled(packageId))) {
|
|
38
|
+
return base;
|
|
39
|
+
}
|
|
40
|
+
const installed = await host.getInstalledPackageVersion?.(packageId);
|
|
41
|
+
return installed ? bumpBuildNumber(installed) : base;
|
|
42
|
+
}
|
|
43
|
+
export async function resolveDeploySpkVersion(project, host, packageId) {
|
|
44
|
+
if (host.installationId !== "live-nas" || isDevelopmentPackageIdentity(packageId)) {
|
|
45
|
+
return resolveOfflineDeploySpkVersion(project, host, packageId);
|
|
46
|
+
}
|
|
47
|
+
const contract = loadContract(project.contractPath).contract;
|
|
48
|
+
const target = resolvePublishTarget();
|
|
49
|
+
const manifest = (await fetchPackageSourceManifestFromR2(target)) ??
|
|
50
|
+
(await resolvePackageSourceManifest(target.origin));
|
|
51
|
+
let version = resolveNextSpkVersion(String(contract.version ?? "1.0.0"), packageId, manifest);
|
|
52
|
+
const installed = await host.getInstalledPackageVersion?.(packageId);
|
|
53
|
+
if (installed) {
|
|
54
|
+
const installedNext = bumpBuildNumber(installed);
|
|
55
|
+
if (comparePackageVersions(installedNext, version) > 0) {
|
|
56
|
+
version = installedNext;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return version;
|
|
60
|
+
}
|
|
61
|
+
export async function publishDeploySpk(spkPath) {
|
|
62
|
+
const published = await publishBuiltSpk(spkPath);
|
|
63
|
+
return published.version;
|
|
64
|
+
}
|
package/dist/dev.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ProjectRoot } from "./discovery.js";
|
|
2
|
+
import type { ComposeRunner } from "./compose/runner.js";
|
|
3
|
+
export interface DevOptions {
|
|
4
|
+
project: ProjectRoot;
|
|
5
|
+
filesRoot?: string;
|
|
6
|
+
composeRunner?: ComposeRunner;
|
|
7
|
+
}
|
|
8
|
+
export interface DevHandle {
|
|
9
|
+
brokerBaseUrl: string;
|
|
10
|
+
bootstrapPath: string;
|
|
11
|
+
close(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare function runDev(options: DevOptions): Promise<DevHandle>;
|
package/dist/dev.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { loadContract } from "./contract/load.js";
|
|
2
|
+
import { writeMockBrokerBootstrap } from "./mock-broker/bootstrap.js";
|
|
3
|
+
import { startMockBroker } from "./mock-broker/server.js";
|
|
4
|
+
import { createDockerComposeRunner } from "./compose/runner.js";
|
|
5
|
+
export async function runDev(options) {
|
|
6
|
+
const parsed = loadContract(options.project.contractPath);
|
|
7
|
+
const packageId = String(parsed.contract.package);
|
|
8
|
+
const broker = await startMockBroker({
|
|
9
|
+
packageId,
|
|
10
|
+
filesRoot: options.filesRoot,
|
|
11
|
+
});
|
|
12
|
+
const bootstrapPath = writeMockBrokerBootstrap(options.project.root, {
|
|
13
|
+
brokerBaseUrl: broker.baseUrl,
|
|
14
|
+
jwksUrl: broker.jwksUrl,
|
|
15
|
+
packageId,
|
|
16
|
+
mock: true,
|
|
17
|
+
});
|
|
18
|
+
const composeRunner = options.composeRunner ?? createDockerComposeRunner();
|
|
19
|
+
await composeRunner.up(options.project.root);
|
|
20
|
+
await composeRunner.waitReady(options.project.root);
|
|
21
|
+
return {
|
|
22
|
+
brokerBaseUrl: broker.baseUrl,
|
|
23
|
+
bootstrapPath,
|
|
24
|
+
close: async () => {
|
|
25
|
+
if (composeRunner.down) {
|
|
26
|
+
await composeRunner.down(options.project.root);
|
|
27
|
+
}
|
|
28
|
+
await broker.close();
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const CONTRACT_FILENAME = "synology-app.yaml";
|
|
2
|
+
export declare const COMPOSE_FILENAME = "compose.yaml";
|
|
3
|
+
export interface ProjectRoot {
|
|
4
|
+
root: string;
|
|
5
|
+
contractPath: string;
|
|
6
|
+
composePath: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function findProjectRoot(startDir: string): ProjectRoot | null;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
export const CONTRACT_FILENAME = "synology-app.yaml";
|
|
4
|
+
export const COMPOSE_FILENAME = "compose.yaml";
|
|
5
|
+
export function findProjectRoot(startDir) {
|
|
6
|
+
let current = resolve(startDir);
|
|
7
|
+
while (true) {
|
|
8
|
+
const contractPath = join(current, CONTRACT_FILENAME);
|
|
9
|
+
if (existsSync(contractPath)) {
|
|
10
|
+
return {
|
|
11
|
+
root: current,
|
|
12
|
+
contractPath,
|
|
13
|
+
composePath: join(current, COMPOSE_FILENAME),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const parent = dirname(current);
|
|
17
|
+
if (parent === current) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
current = parent;
|
|
21
|
+
}
|
|
22
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SourceSpan, ValidationError } from "./types.js";
|
|
2
|
+
export declare function makeError(code: string, span: SourceSpan, message: string, suggestion: string, severity?: "error" | "warning"): ValidationError;
|
|
3
|
+
export declare function contractSpan(file: string, line: number, column: number, path?: string): SourceSpan;
|
|
4
|
+
export declare function composeSpan(file: string, line: number, column: number, path?: string): SourceSpan;
|
|
5
|
+
export declare function formatError(error: ValidationError): string;
|
|
6
|
+
export declare function formatErrors(errors: ValidationError[]): string;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function makeError(code, span, message, suggestion, severity = "error") {
|
|
2
|
+
return { code, span, message, suggestion, severity };
|
|
3
|
+
}
|
|
4
|
+
export function contractSpan(file, line, column, path) {
|
|
5
|
+
return { file, line, column, path };
|
|
6
|
+
}
|
|
7
|
+
export function composeSpan(file, line, column, path) {
|
|
8
|
+
return { file, line, column, path };
|
|
9
|
+
}
|
|
10
|
+
export function formatError(error) {
|
|
11
|
+
const location = error.span.path
|
|
12
|
+
? `${error.span.file}:${error.span.line}:${error.span.column} (${error.span.path})`
|
|
13
|
+
: `${error.span.file}:${error.span.line}:${error.span.column}`;
|
|
14
|
+
return `[${error.code}] ${location}\n${error.message}\n建議:${error.suggestion}`;
|
|
15
|
+
}
|
|
16
|
+
export function formatErrors(errors) {
|
|
17
|
+
return errors.map(formatError).join("\n\n");
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const IDENTITY_CGI_PATH = "/webman/3rdparty/SynoPkgLandService/index.cgi";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const IDENTITY_CGI_PATH = "/webman/3rdparty/SynoPkgLandService/index.cgi";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
interface CatalogPackageEntry {
|
|
2
|
+
package: string;
|
|
3
|
+
version: string;
|
|
4
|
+
link: string;
|
|
5
|
+
md5: string;
|
|
6
|
+
size: number;
|
|
7
|
+
beta?: boolean;
|
|
8
|
+
qinst?: boolean;
|
|
9
|
+
deppkgs?: string | Record<string, unknown> | null;
|
|
10
|
+
breakpkgs?: unknown;
|
|
11
|
+
replacepkgs?: unknown;
|
|
12
|
+
}
|
|
13
|
+
export interface CatalogInstallOptions {
|
|
14
|
+
dsmOrigin: string;
|
|
15
|
+
cookieHeader: string;
|
|
16
|
+
packageId: string;
|
|
17
|
+
profileName?: string;
|
|
18
|
+
expectedVersion?: string;
|
|
19
|
+
packageSourceOrigin?: string;
|
|
20
|
+
extraValues?: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
export interface InstalledPackageState {
|
|
23
|
+
installed: boolean;
|
|
24
|
+
version?: string;
|
|
25
|
+
status?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface UploadedCatalogPackage {
|
|
28
|
+
id: string;
|
|
29
|
+
taskId: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function packageStateFromListPayload(payload: unknown, packageId: string): InstalledPackageState | undefined;
|
|
32
|
+
export declare function fetchInstalledPackageState(dsmOrigin: string, cookieHeader: string, packageId: string): Promise<InstalledPackageState | undefined>;
|
|
33
|
+
export declare function waitForInstalledVersion(readState: () => InstalledPackageState | undefined | Promise<InstalledPackageState | undefined>, options: {
|
|
34
|
+
packageId: string;
|
|
35
|
+
expectedVersion?: string;
|
|
36
|
+
deadlineMs?: number;
|
|
37
|
+
pollMs?: number;
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
export declare function catalogInstallationRequests(entry: Pick<CatalogPackageEntry, "package" | "version" | "size" | "beta" | "link" | "md5" | "qinst" | "deppkgs" | "breakpkgs" | "replacepkgs">, installed: boolean, sid: string, volumePath?: string): {
|
|
40
|
+
check: Record<string, string>;
|
|
41
|
+
install: Record<string, string>;
|
|
42
|
+
};
|
|
43
|
+
export declare function catalogCompoundSteps(uploaded: UploadedCatalogPackage, entry: Pick<CatalogPackageEntry, "version" | "size">, options: {
|
|
44
|
+
blupgrade: boolean;
|
|
45
|
+
extraValues?: Record<string, string>;
|
|
46
|
+
}): unknown[];
|
|
47
|
+
export declare function catalogUpgradeCompoundSteps(uploaded: UploadedCatalogPackage, entry: Pick<CatalogPackageEntry, "version" | "size">, extraValues?: Record<string, string>): unknown[];
|
|
48
|
+
export interface LocalSpkInstallOptions {
|
|
49
|
+
dsmOrigin: string;
|
|
50
|
+
cookieHeader: string;
|
|
51
|
+
packageId: string;
|
|
52
|
+
spkPath: string;
|
|
53
|
+
version: string;
|
|
54
|
+
profileName?: string;
|
|
55
|
+
extraValues?: Record<string, string>;
|
|
56
|
+
}
|
|
57
|
+
export declare function installPackageFromLocalSpk(options: LocalSpkInstallOptions): Promise<void>;
|
|
58
|
+
export declare function installPackageFromCatalog(options: CatalogInstallOptions): Promise<void>;
|
|
59
|
+
export {};
|