@synopackageland/cli 0.3.10 → 0.4.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.
Files changed (280) hide show
  1. package/README.md +20 -9
  2. package/dist/bin.js +1 -2
  3. package/dist/build-spk/generator.d.ts +0 -3
  4. package/dist/build-spk/generator.js +135 -287
  5. package/dist/build-spk/native-lifecycle.js +0 -3
  6. package/dist/build-spk/native-payload.js +0 -1
  7. package/dist/cli.js +171 -151
  8. package/dist/compose/analyze.d.ts +1 -2
  9. package/dist/compose/analyze.js +5 -48
  10. package/dist/contract/unsupported-types.d.ts +10 -0
  11. package/dist/contract/unsupported-types.js +49 -0
  12. package/dist/contract/validate.js +25 -2
  13. package/dist/contract/web-launch.js +0 -2
  14. package/dist/deploy/deploy.d.ts +1 -4
  15. package/dist/deploy/deploy.js +45 -156
  16. package/dist/deploy/homes-values.js +1 -1
  17. package/dist/deploy/plan.d.ts +18 -0
  18. package/dist/deploy/plan.js +54 -0
  19. package/dist/deploy/spk-version.d.ts +2 -14
  20. package/dist/deploy/spk-version.js +25 -111
  21. package/dist/dev.d.ts +1 -3
  22. package/dist/dev.js +14 -28
  23. package/dist/error-registry.js +810 -862
  24. package/dist/host/dsm-client.js +12 -272
  25. package/dist/host/dsm-port-profile.d.ts +0 -1
  26. package/dist/host/dsm-port-profile.js +0 -2
  27. package/dist/host/types.d.ts +1 -83
  28. package/dist/index.d.ts +0 -9
  29. package/dist/index.js +0 -6
  30. package/dist/info.d.ts +0 -1
  31. package/dist/info.js +3 -10
  32. package/dist/init.d.ts +11 -1
  33. package/dist/init.js +112 -4
  34. package/dist/log.js +2 -3
  35. package/dist/native/validate.js +0 -1
  36. package/dist/standalone/binary.d.ts +9 -0
  37. package/dist/standalone/binary.js +67 -0
  38. package/dist/standalone/build.d.ts +25 -0
  39. package/dist/standalone/build.js +108 -0
  40. package/dist/standalone/dsm-window.d.ts +26 -0
  41. package/dist/standalone/dsm-window.js +251 -0
  42. package/dist/standalone/helper.d.ts +31 -0
  43. package/dist/standalone/helper.js +104 -0
  44. package/dist/standalone/i18n.d.ts +28 -0
  45. package/dist/standalone/i18n.js +161 -0
  46. package/dist/standalone/inspect-spk.d.ts +21 -0
  47. package/dist/standalone/inspect-spk.js +160 -0
  48. package/dist/standalone/manifest.d.ts +71 -0
  49. package/dist/standalone/manifest.js +276 -0
  50. package/dist/standalone/root-messages.d.ts +7 -0
  51. package/dist/standalone/root-messages.js +250 -0
  52. package/dist/standalone/root-ops.d.ts +42 -0
  53. package/dist/standalone/root-ops.js +101 -0
  54. package/dist/standalone/root-window.d.ts +35 -0
  55. package/dist/standalone/root-window.js +290 -0
  56. package/dist/standalone/spk.d.ts +22 -0
  57. package/dist/standalone/spk.js +205 -0
  58. package/dist/templates/binary/synology-app.yaml +7 -0
  59. package/dist/templates/hello-files/compose.yaml +0 -1
  60. package/dist/templates/hello-web/compose.yaml +13 -10
  61. package/dist/templates/hello-web/html/app.js +1 -23
  62. package/dist/templates/hello-web/html/index.html +1 -3
  63. package/dist/templates/hello-web-page/compose.yaml +13 -10
  64. package/dist/templates/hello-web-page/html/app.js +1 -23
  65. package/dist/templates/hello-web-page/html/index.html +1 -3
  66. package/dist/templates/native-go/README.md +268 -0
  67. package/dist/templates/native-go/backend/cmd/app/main.go +49 -0
  68. package/dist/templates/native-go/backend/cmd/helper/main.go +38 -0
  69. package/dist/templates/native-go/backend/go.mod +3 -0
  70. package/dist/templates/native-go/backend/internal/api/errors.go +33 -0
  71. package/dist/templates/native-go/backend/internal/api/registry.go +94 -0
  72. package/dist/templates/native-go/backend/internal/api/registry_test.go +329 -0
  73. package/dist/templates/native-go/backend/internal/api/server.go +155 -0
  74. package/dist/templates/native-go/backend/internal/app/root_none.go +9 -0
  75. package/dist/templates/native-go/backend/internal/app/routes.go +127 -0
  76. package/dist/templates/native-go/backend/internal/app/routes_test.go +167 -0
  77. package/dist/templates/native-go/backend/internal/dsm/auth.go +118 -0
  78. package/dist/templates/native-go/backend/internal/dsm/auth_test.go +139 -0
  79. package/dist/templates/native-go/backend/internal/helper/control.go +219 -0
  80. package/dist/templates/native-go/backend/internal/helper/control_test.go +242 -0
  81. package/dist/templates/native-go/backend/internal/helper/peer_linux.go +44 -0
  82. package/dist/templates/native-go/backend/internal/helper/peer_other.go +7 -0
  83. package/dist/templates/native-go/backend/internal/helper/process_linux.go +167 -0
  84. package/dist/templates/native-go/backend/internal/helper/process_other.go +5 -0
  85. package/dist/templates/native-go/backend/internal/helper/server_linux.go +83 -0
  86. package/dist/templates/native-go/backend/internal/helper/status.go +271 -0
  87. package/dist/templates/native-go/backend/internal/helper/status_test.go +205 -0
  88. package/dist/templates/native-go/backend/internal/helper/supervision.go +84 -0
  89. package/dist/templates/native-go/backend/internal/helper/supervision_test.go +124 -0
  90. package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +192 -0
  91. package/dist/templates/native-go/backend/internal/helper/supervisor_linux_test.go +302 -0
  92. package/dist/templates/native-go/dsm-package.yaml +58 -0
  93. package/dist/templates/native-go/gitignore +1 -0
  94. package/dist/templates/native-go/i18n/glossary.json +662 -0
  95. package/dist/templates/native-go/i18n/messages/de.json +28 -0
  96. package/dist/templates/native-go/i18n/messages/en.json +28 -0
  97. package/dist/templates/native-go/i18n/messages/es.json +28 -0
  98. package/dist/templates/native-go/i18n/messages/fr.json +28 -0
  99. package/dist/templates/native-go/i18n/messages/it.json +28 -0
  100. package/dist/templates/native-go/i18n/messages/ja.json +28 -0
  101. package/dist/templates/native-go/i18n/messages/ko.json +28 -0
  102. package/dist/templates/native-go/i18n/messages/zh-CN.json +28 -0
  103. package/dist/templates/native-go/i18n/messages/zh-TW.json +28 -0
  104. package/dist/templates/native-go/ui/app.css +35 -0
  105. package/dist/templates/native-go/ui/app.js +94 -0
  106. package/dist/templates/native-go-better-auth/backend/internal/app/identity.go +208 -0
  107. package/dist/templates/native-go-better-auth/backend/internal/app/identity_test.go +113 -0
  108. package/dist/templates/native-go-better-auth/node/app.mjs +72 -0
  109. package/dist/templates/native-go-better-auth/node/build.mjs +2 -0
  110. package/dist/templates/native-go-better-auth/node/package-lock.json +862 -0
  111. package/dist/templates/native-go-better-auth/node/package.json +1 -0
  112. package/dist/templates/native-go-better-auth/node/test/auth.test.mjs +31 -0
  113. package/dist/templates/native-go-integration/backend/internal/app/identity_none.go +6 -0
  114. package/dist/templates/native-go-integration/backend/internal/app/personal.go +203 -0
  115. package/dist/templates/native-go-integration/backend/internal/app/personal_test.go +119 -0
  116. package/dist/templates/native-go-root/backend/internal/app/root.go +107 -0
  117. package/dist/templates/native-go-root/backend/internal/app/root_test.go +124 -0
  118. package/dist/templates/native-go-root/root/whoami.sh +6 -0
  119. package/dist/templates/native-go-vue/README.md +110 -0
  120. package/dist/templates/native-go-vue/frontend/DESIGN.md +78 -0
  121. package/dist/templates/native-go-vue/frontend/package-lock.json +2507 -0
  122. package/dist/templates/native-go-vue/frontend/package.json +6 -0
  123. package/dist/templates/native-go-vue/frontend/src/App.vue +132 -0
  124. package/dist/templates/native-go-vue/frontend/src/context.ts +17 -0
  125. package/dist/templates/native-go-vue/frontend/src/main.ts +26 -0
  126. package/dist/templates/native-go-vue/frontend/src/style.css +14 -0
  127. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +148 -0
  128. package/dist/templates/native-go-vue/frontend/tsconfig.json +1 -0
  129. package/dist/templates/native-go-vue/frontend/vite.config.ts +8 -0
  130. package/dist/templates/native-go-vue/gitignore +2 -0
  131. package/dist/types.d.ts +1 -1
  132. package/dist/validate.js +11 -7
  133. package/package.json +3 -7
  134. package/schema/synology-app.schema.json +36 -37
  135. package/skills/SKILL.md +4 -48
  136. package/skills/reference/create.md +11 -83
  137. package/skills/reference/deploy.md +7 -78
  138. package/skills/reference/diagnose.md +4 -101
  139. package/skills/reference/files.md +5 -41
  140. package/skills/reference/identity.md +3 -29
  141. package/skills/reference/wrap.md +0 -2
  142. package/templates/binary/synology-app.yaml +7 -0
  143. package/templates/hello-files/compose.yaml +0 -1
  144. package/templates/hello-web/compose.yaml +13 -10
  145. package/templates/hello-web/html/app.js +1 -23
  146. package/templates/hello-web/html/index.html +1 -3
  147. package/templates/hello-web-page/compose.yaml +13 -10
  148. package/templates/hello-web-page/html/app.js +1 -23
  149. package/templates/hello-web-page/html/index.html +1 -3
  150. package/templates/native-go/README.md +268 -0
  151. package/templates/native-go/backend/cmd/app/main.go +49 -0
  152. package/templates/native-go/backend/cmd/helper/main.go +38 -0
  153. package/templates/native-go/backend/go.mod +3 -0
  154. package/templates/native-go/backend/internal/api/errors.go +33 -0
  155. package/templates/native-go/backend/internal/api/registry.go +94 -0
  156. package/templates/native-go/backend/internal/api/registry_test.go +329 -0
  157. package/templates/native-go/backend/internal/api/server.go +155 -0
  158. package/templates/native-go/backend/internal/app/root_none.go +9 -0
  159. package/templates/native-go/backend/internal/app/routes.go +127 -0
  160. package/templates/native-go/backend/internal/app/routes_test.go +167 -0
  161. package/templates/native-go/backend/internal/dsm/auth.go +118 -0
  162. package/templates/native-go/backend/internal/dsm/auth_test.go +139 -0
  163. package/templates/native-go/backend/internal/helper/control.go +219 -0
  164. package/templates/native-go/backend/internal/helper/control_test.go +242 -0
  165. package/templates/native-go/backend/internal/helper/peer_linux.go +44 -0
  166. package/templates/native-go/backend/internal/helper/peer_other.go +7 -0
  167. package/templates/native-go/backend/internal/helper/process_linux.go +167 -0
  168. package/templates/native-go/backend/internal/helper/process_other.go +5 -0
  169. package/templates/native-go/backend/internal/helper/server_linux.go +83 -0
  170. package/templates/native-go/backend/internal/helper/status.go +271 -0
  171. package/templates/native-go/backend/internal/helper/status_test.go +205 -0
  172. package/templates/native-go/backend/internal/helper/supervision.go +84 -0
  173. package/templates/native-go/backend/internal/helper/supervision_test.go +124 -0
  174. package/templates/native-go/backend/internal/helper/supervisor_linux.go +192 -0
  175. package/templates/native-go/backend/internal/helper/supervisor_linux_test.go +302 -0
  176. package/templates/native-go/dsm-package.yaml +58 -0
  177. package/templates/native-go/gitignore +1 -0
  178. package/templates/native-go/i18n/glossary.json +662 -0
  179. package/templates/native-go/i18n/messages/de.json +28 -0
  180. package/templates/native-go/i18n/messages/en.json +28 -0
  181. package/templates/native-go/i18n/messages/es.json +28 -0
  182. package/templates/native-go/i18n/messages/fr.json +28 -0
  183. package/templates/native-go/i18n/messages/it.json +28 -0
  184. package/templates/native-go/i18n/messages/ja.json +28 -0
  185. package/templates/native-go/i18n/messages/ko.json +28 -0
  186. package/templates/native-go/i18n/messages/zh-CN.json +28 -0
  187. package/templates/native-go/i18n/messages/zh-TW.json +28 -0
  188. package/templates/native-go/ui/app.css +35 -0
  189. package/templates/native-go/ui/app.js +94 -0
  190. package/templates/native-go-better-auth/backend/internal/app/identity.go +208 -0
  191. package/templates/native-go-better-auth/backend/internal/app/identity_test.go +113 -0
  192. package/templates/native-go-better-auth/node/app.mjs +72 -0
  193. package/templates/native-go-better-auth/node/build.mjs +2 -0
  194. package/templates/native-go-better-auth/node/package-lock.json +862 -0
  195. package/templates/native-go-better-auth/node/package.json +1 -0
  196. package/templates/native-go-better-auth/node/test/auth.test.mjs +31 -0
  197. package/templates/native-go-integration/backend/internal/app/identity_none.go +6 -0
  198. package/templates/native-go-integration/backend/internal/app/personal.go +203 -0
  199. package/templates/native-go-integration/backend/internal/app/personal_test.go +119 -0
  200. package/templates/native-go-root/backend/internal/app/root.go +107 -0
  201. package/templates/native-go-root/backend/internal/app/root_test.go +124 -0
  202. package/templates/native-go-root/root/whoami.sh +6 -0
  203. package/templates/native-go-vue/README.md +110 -0
  204. package/templates/native-go-vue/frontend/DESIGN.md +78 -0
  205. package/templates/native-go-vue/frontend/package-lock.json +2507 -0
  206. package/templates/native-go-vue/frontend/package.json +6 -0
  207. package/templates/native-go-vue/frontend/src/App.vue +132 -0
  208. package/templates/native-go-vue/frontend/src/context.ts +17 -0
  209. package/templates/native-go-vue/frontend/src/main.ts +26 -0
  210. package/templates/native-go-vue/frontend/src/style.css +14 -0
  211. package/templates/native-go-vue/frontend/test/apps.test.ts +148 -0
  212. package/templates/native-go-vue/frontend/tsconfig.json +1 -0
  213. package/templates/native-go-vue/frontend/vite.config.ts +8 -0
  214. package/templates/native-go-vue/gitignore +2 -0
  215. package/dist/attestation/app-package.d.ts +0 -86
  216. package/dist/attestation/app-package.js +0 -206
  217. package/dist/attestation/install-on-host.d.ts +0 -14
  218. package/dist/attestation/install-on-host.js +0 -52
  219. package/dist/attestation/keyring.d.ts +0 -21
  220. package/dist/attestation/keyring.js +0 -168
  221. package/dist/attestation/platform-service.d.ts +0 -70
  222. package/dist/attestation/platform-service.js +0 -250
  223. package/dist/build-spk/broker-glue.d.ts +0 -16
  224. package/dist/build-spk/broker-glue.js +0 -40
  225. package/dist/deploy/catalog-publish.d.ts +0 -3
  226. package/dist/deploy/catalog-publish.js +0 -7
  227. package/dist/doctor.d.ts +0 -22
  228. package/dist/doctor.js +0 -822
  229. package/dist/error-collector.d.ts +0 -2
  230. package/dist/error-collector.js +0 -46
  231. package/dist/host/broker-paths.d.ts +0 -1
  232. package/dist/host/broker-paths.js +0 -1
  233. package/dist/host/broker-upgrade-preflight.d.ts +0 -61
  234. package/dist/host/broker-upgrade-preflight.js +0 -156
  235. package/dist/host/digests.d.ts +0 -5
  236. package/dist/host/digests.js +0 -63
  237. package/dist/host/fake-nas.d.ts +0 -49
  238. package/dist/host/fake-nas.js +0 -193
  239. package/dist/mock-broker/bootstrap.d.ts +0 -2
  240. package/dist/mock-broker/bootstrap.js +0 -8
  241. package/dist/mock-broker/files.d.ts +0 -60
  242. package/dist/mock-broker/files.js +0 -408
  243. package/dist/mock-broker/oidc.d.ts +0 -31
  244. package/dist/mock-broker/oidc.js +0 -161
  245. package/dist/mock-broker/path.d.ts +0 -9
  246. package/dist/mock-broker/path.js +0 -50
  247. package/dist/mock-broker/server.d.ts +0 -19
  248. package/dist/mock-broker/server.js +0 -350
  249. package/dist/publish/build-ledger.d.ts +0 -22
  250. package/dist/publish/build-ledger.js +0 -26
  251. package/dist/publish/community-path.d.ts +0 -6
  252. package/dist/publish/community-path.js +0 -41
  253. package/dist/publish/curated-release.d.ts +0 -78
  254. package/dist/publish/curated-release.js +0 -883
  255. package/dist/publish/file-build-ledger.d.ts +0 -18
  256. package/dist/publish/file-build-ledger.js +0 -268
  257. package/dist/publish/github-pr.d.ts +0 -25
  258. package/dist/publish/github-pr.js +0 -85
  259. package/dist/publish/github-repo.d.ts +0 -8
  260. package/dist/publish/github-repo.js +0 -21
  261. package/dist/publish/platform-service-release.d.ts +0 -60
  262. package/dist/publish/platform-service-release.js +0 -333
  263. package/dist/publish/preflight.d.ts +0 -24
  264. package/dist/publish/preflight.js +0 -138
  265. package/dist/publish/publish.d.ts +0 -27
  266. package/dist/publish/publish.js +0 -136
  267. package/dist/publish/sync-definition.d.ts +0 -4
  268. package/dist/publish/sync-definition.js +0 -48
  269. package/dist/release-bin.d.ts +0 -2
  270. package/dist/release-bin.js +0 -23
  271. package/dist/templates/hello-web/html/sdk.js +0 -68
  272. package/dist/templates/hello-web-page/html/sdk.js +0 -68
  273. package/dist/templates/native/synology-app.yaml +0 -7
  274. package/dist/test-host.d.ts +0 -15
  275. package/dist/test-host.js +0 -37
  276. package/templates/hello-web/html/sdk.js +0 -68
  277. package/templates/hello-web-page/html/sdk.js +0 -68
  278. package/templates/native/synology-app.yaml +0 -7
  279. /package/dist/templates/{native → binary}/native.yaml +0 -0
  280. /package/templates/{native → binary}/native.yaml +0 -0
@@ -1,17 +1,11 @@
1
1
  import { spawnSync } from "node:child_process";
2
- import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
- import { IDENTITY_CGI_PATH } from "./broker-paths.js";
6
- import { packageSourceOrigin } from "../deploy/catalog-publish.js";
7
2
  import { listShareNamesWithSynoagentcli, lookupSharePathWithSynoagentcli } from "./share-lookup.js";
8
3
  import { createSynoagentcliApiCall, fetchSharePermissions, fetchUserGroups, } from "./share-permission-lookup.js";
9
4
  import { fetchPortInfo } from "./port-info-lookup.js";
10
5
  import { dsmFetch } from "./dsm-http.js";
11
6
  import { fetchDsmPortProfileInventory } from "./dsm-port-profile.js";
12
- import { installPackageFromCatalog, installPackageFromLocalSpk, uninstallPackageFromDsm, fetchInstalledPackageState, packageStateFromRecord, } from "./catalog-install.js";
7
+ import { installPackageFromLocalSpk, fetchInstalledPackageState, packageStateFromRecord, } from "./catalog-install.js";
13
8
  import { resolveHostCredentials } from "./credentials.js";
14
- const OIDC_COMPAT_PATH = "/api/v1/inner-loop/oidc-compat";
15
9
  export function createNasHost(options = {}) {
16
10
  const credentials = options.credentials ?? resolveHostCredentials(options.host);
17
11
  if (!credentials) {
@@ -61,9 +55,7 @@ export function homesPathFromDsmUserHomeRead(result) {
61
55
  }
62
56
  function createDsmNasHost(credentials, profileName) {
63
57
  const dsmOrigin = credentials.dsmOrigin.replace(/\/$/, "");
64
- const brokerBaseUrl = `${dsmOrigin}${IDENTITY_CGI_PATH}`;
65
58
  let cookieHeader = credentials.cookieHeader;
66
- const projectEnvCache = new Map();
67
59
  const ensureLogin = async () => {
68
60
  if (cookieHeader) {
69
61
  return;
@@ -77,7 +69,10 @@ function createDsmNasHost(credentials, profileName) {
77
69
  session: "FileStation",
78
70
  format: "cookie",
79
71
  });
80
- const response = await dsmFetch(`${dsmOrigin}/webapi/entry.cgi?${query.toString()}`);
72
+ const response = await dsmFetch(`${dsmOrigin}/webapi/entry.cgi`, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: query });
73
+ const login = await response.json();
74
+ if (!response.ok || login.success !== true)
75
+ throw new Error("DSM login failed");
81
76
  const setCookie = typeof response.headers.getSetCookie === "function"
82
77
  ? response.headers.getSetCookie()
83
78
  : response.headers.get("set-cookie")
@@ -87,140 +82,18 @@ function createDsmNasHost(credentials, profileName) {
87
82
  .map((line) => line.split(";")[0]?.trim())
88
83
  .filter((pair) => Boolean(pair));
89
84
  cookieHeader = pairs.join("; ");
90
- };
91
- const ensureInnerLoopApi = async () => {
92
- await ensureLogin();
93
- const response = await dsmFetch(`${brokerBaseUrl}/api/v1/inner-loop/diagnostics?package=probe`, { headers: { cookie: cookieHeader ?? "" } });
94
- const text = await response.text();
95
- if (response.status === 404 || text.trimStart().startsWith("<")) {
96
- const error = new Error("Broker inner-loop API 不可用(收到 HTML 404)。請將 SynoPkgLandService 升級到 >=0.1.0-0016。");
97
- error.code = "INNER_LOOP_API_MISSING";
98
- throw error;
99
- }
100
- try {
101
- JSON.parse(text);
102
- }
103
- catch {
104
- const error = new Error("Broker inner-loop API 回傳非 JSON 內容。");
105
- error.code = "INNER_LOOP_API_MISSING";
106
- throw error;
107
- }
108
- };
109
- const ensurePackageSourceFeed = (origin) => {
110
- const feed = origin.replace(/\/$/, "") + "/";
111
- const list = synoagentcli(["dsm", "package-center", "source", "list"], profileName);
112
- if (list.status !== 0) {
113
- return;
114
- }
115
- const parsed = JSON.parse(list.stdout);
116
- const items = parsed.data?.items ?? [];
117
- const normalizedFeed = feed.replace(/\/$/, "");
118
- const existing = items.find((item) => item.feed?.replace(/\/$/, "") === normalizedFeed);
119
- if (existing) {
120
- return;
121
- }
122
- const stale = items.find((item) => item.name === "package-land-throwaway");
123
- const payload = { name: "package-land-throwaway", feed };
124
- const staging = mkdtempSync(join(tmpdir(), "syno-package-source-feed-"));
125
- const jsonPath = join(staging, "source.json");
126
- writeFileSync(jsonPath, JSON.stringify(payload));
127
- try {
128
- if (stale?.feed) {
129
- synoagentcli(["dsm", "package-center", "source", "update", stale.feed, "--json-file", jsonPath], profileName);
130
- return;
131
- }
132
- synoagentcli(["dsm", "package-center", "source", "add", "--json-file", jsonPath], profileName);
133
- }
134
- finally {
135
- rmSync(staging, { recursive: true, force: true });
136
- }
85
+ if (!cookieHeader)
86
+ throw new Error("DSM login returned no session cookie");
137
87
  };
138
88
  return {
139
89
  dsmOrigin,
140
- installationId: "live-nas",
141
- async requestAttestation(input) {
142
- await ensureInnerLoopApi();
90
+ async installFromLocalSpk(input) {
143
91
  await ensureLogin();
144
- const response = await dsmFetch(`${brokerBaseUrl}/api/v1/inner-loop/attest`, {
145
- method: "POST",
146
- headers: {
147
- cookie: cookieHeader ?? "",
148
- "content-type": "application/json",
149
- },
150
- body: JSON.stringify(input),
92
+ await installPackageFromLocalSpk({
93
+ dsmOrigin, cookieHeader: cookieHeader ?? "",
94
+ packageId: input.packageId, spkPath: input.spkPath,
95
+ version: input.version, profileName, extraValues: input.extraValues,
151
96
  });
152
- const text = await response.text();
153
- let body;
154
- try {
155
- body = JSON.parse(text);
156
- }
157
- catch {
158
- const error = new Error("Broker inner-loop attest 回傳非 JSON 內容。");
159
- error.code = "INNER_LOOP_API_MISSING";
160
- throw error;
161
- }
162
- if (!response.ok) {
163
- const error = new Error(body.error?.message ?? `Attestation failed (${response.status})`);
164
- error.code = body.error?.code;
165
- throw error;
166
- }
167
- const token = typeof body.token === "string" && body.token.length > 0 ? body.token : undefined;
168
- return {
169
- kind: "local",
170
- attestationDigest: body.attestationDigest ?? "",
171
- ...(token !== undefined ? { token } : {}),
172
- };
173
- },
174
- async ensurePackageSource(origin) {
175
- ensurePackageSourceFeed(origin);
176
- },
177
- async installFromCatalog(input) {
178
- try {
179
- ensurePackageSourceFeed(packageSourceOrigin());
180
- await ensureLogin();
181
- await installPackageFromCatalog({
182
- dsmOrigin,
183
- cookieHeader: cookieHeader ?? "",
184
- packageId: input.packageId,
185
- profileName,
186
- expectedVersion: input.version,
187
- packageSourceOrigin: packageSourceOrigin(),
188
- extraValues: input.extraValues,
189
- });
190
- }
191
- finally {
192
- projectEnvCache.delete(input.packageId);
193
- }
194
- },
195
- async installFromLocalSpk(input) {
196
- try {
197
- await ensureLogin();
198
- await installPackageFromLocalSpk({
199
- dsmOrigin,
200
- cookieHeader: cookieHeader ?? "",
201
- packageId: input.packageId,
202
- spkPath: input.spkPath,
203
- version: input.version,
204
- profileName,
205
- extraValues: input.extraValues,
206
- });
207
- }
208
- finally {
209
- projectEnvCache.delete(input.packageId);
210
- }
211
- },
212
- async uninstallPackage(packageIdentity) {
213
- try {
214
- await ensureLogin();
215
- await uninstallPackageFromDsm({
216
- dsmOrigin,
217
- cookieHeader: cookieHeader ?? "",
218
- packageId: packageIdentity,
219
- });
220
- }
221
- finally {
222
- projectEnvCache.delete(packageIdentity);
223
- }
224
97
  },
225
98
  async getArchFamily() {
226
99
  await ensureLogin();
@@ -261,44 +134,6 @@ function createDsmNasHost(credentials, profileName) {
261
134
  return undefined;
262
135
  }
263
136
  },
264
- async getInstalledProjectEnv(packageIdentity) {
265
- const cached = projectEnvCache.get(packageIdentity);
266
- if (cached) {
267
- return cached;
268
- }
269
- const lookup = (async () => {
270
- await ensureLogin();
271
- const response = await dsmFetch(`${brokerBaseUrl}/api/v1/inner-loop/project-env/${encodeURIComponent(packageIdentity)}`, { headers: { cookie: cookieHeader ?? "" } });
272
- if (response.ok) {
273
- const payload = (await response.json());
274
- if (!payload.env || typeof payload.env !== "object" || Array.isArray(payload.env)) {
275
- return undefined;
276
- }
277
- return Object.fromEntries(Object.entries(payload.env).filter((entry) => typeof entry[1] === "string"));
278
- }
279
- return undefined;
280
- })();
281
- projectEnvCache.set(packageIdentity, lookup);
282
- return lookup;
283
- },
284
- async getAttestationInfo(packageIdentity) {
285
- await ensureLogin();
286
- const response = await dsmFetch(`${brokerBaseUrl}/api/v1/inner-loop/info/${encodeURIComponent(packageIdentity)}`, { headers: { cookie: cookieHeader ?? "" } });
287
- const text = await response.text();
288
- if (response.status === 404 || text.trimStart().startsWith("<")) {
289
- const error = new Error("Broker inner-loop info 不可用(HTML 404)。");
290
- error.code = "INNER_LOOP_API_MISSING";
291
- throw error;
292
- }
293
- try {
294
- return JSON.parse(text);
295
- }
296
- catch {
297
- const error = new Error("Broker inner-loop info 回傳非 JSON 內容。");
298
- error.code = "INNER_LOOP_API_MISSING";
299
- throw error;
300
- }
301
- },
302
137
  async getInstalledPackageState(packageIdentity) {
303
138
  await ensureLogin();
304
139
  const viaDsm = await fetchInstalledPackageState(dsmOrigin, cookieHeader ?? "", packageIdentity);
@@ -355,21 +190,6 @@ function createDsmNasHost(credentials, profileName) {
355
190
  .filter(Boolean)
356
191
  .map((line) => `[status] ${line}`);
357
192
  },
358
- async getDsmDiagnostics(packageIdentity) {
359
- try {
360
- await ensureLogin();
361
- const pkg = packageIdentity ?? "probe";
362
- const response = await dsmFetch(`${brokerBaseUrl}/api/v1/inner-loop/diagnostics?package=${encodeURIComponent(pkg)}`, { headers: { cookie: cookieHeader ?? "" } });
363
- if (!response.ok) {
364
- return undefined;
365
- }
366
- const text = await response.text();
367
- return JSON.parse(text);
368
- }
369
- catch {
370
- return undefined;
371
- }
372
- },
373
193
  async getDsmPortProfileInventory() {
374
194
  try {
375
195
  await ensureLogin();
@@ -379,86 +199,6 @@ function createDsmNasHost(credentials, profileName) {
379
199
  return undefined;
380
200
  }
381
201
  },
382
- async getOidcCompatSettings() {
383
- try {
384
- await ensureLogin();
385
- const response = await dsmFetch(`${brokerBaseUrl}${OIDC_COMPAT_PATH}`, {
386
- headers: { cookie: cookieHeader ?? "" },
387
- });
388
- const text = await response.text();
389
- if (response.status === 404 || text.trimStart().startsWith("<")) {
390
- return undefined;
391
- }
392
- if (!response.ok) {
393
- return undefined;
394
- }
395
- const payload = JSON.parse(text);
396
- const settings = payload.settings;
397
- if (!settings || typeof settings !== "object" || Array.isArray(settings)) {
398
- return undefined;
399
- }
400
- const record = settings;
401
- const origin = record.origin;
402
- if (!origin || typeof origin !== "object" || Array.isArray(origin)) {
403
- return undefined;
404
- }
405
- const originRecord = origin;
406
- if (typeof record.enabled !== "boolean" ||
407
- typeof originRecord.ready !== "boolean" ||
408
- typeof originRecord.kind !== "string" ||
409
- typeof originRecord.setupHint !== "string") {
410
- return undefined;
411
- }
412
- return {
413
- enabled: record.enabled,
414
- origin: {
415
- ready: originRecord.ready,
416
- kind: originRecord.kind,
417
- hostname: typeof originRecord.hostname === "string" ? originRecord.hostname : undefined,
418
- issuerUrl: typeof originRecord.issuerUrl === "string" ? originRecord.issuerUrl : undefined,
419
- setupHint: originRecord.setupHint,
420
- },
421
- };
422
- }
423
- catch {
424
- return undefined;
425
- }
426
- },
427
- async smokeRequireLogin(input) {
428
- await ensureLogin();
429
- const info = await this.getAttestationInfo(input.packageIdentity);
430
- let openUrl = info.openUrl;
431
- if (!openUrl) {
432
- const pkg = synoagentcli(["dsm", "package-center", "get", input.packageIdentity], profileName);
433
- if (pkg.status === 0) {
434
- try {
435
- const parsed = JSON.parse(pkg.stdout);
436
- openUrl = parsed.data?.url?.[0];
437
- }
438
- catch {
439
- // ignore parse errors
440
- }
441
- }
442
- }
443
- if (!openUrl) {
444
- return { ok: false };
445
- }
446
- const origin = new URL(openUrl).origin;
447
- const response = await dsmFetch(`${brokerBaseUrl}/api/v1/auth/login`, {
448
- method: "POST",
449
- headers: {
450
- cookie: cookieHeader ?? input.cookieHeader,
451
- origin,
452
- "content-type": "application/json",
453
- },
454
- body: JSON.stringify({ packageId: input.packageIdentity }),
455
- });
456
- if (!response.ok) {
457
- return { ok: false };
458
- }
459
- const body = (await response.json());
460
- return { ok: Boolean(body.user?.username), username: body.user?.username };
461
- },
462
202
  };
463
203
  }
464
204
  /**
@@ -17,7 +17,6 @@ export interface DsmPortProfileInventory {
17
17
  orphaned: DsmPortProfile[];
18
18
  }
19
19
  /**
20
- * Parses the Docker .sc filename using the same rules as the Broker's
21
20
  * parsePortProfileFilename(). In particular, projectName is everything before
22
21
  * the final two dash-separated container segments.
23
22
  */
@@ -4,7 +4,6 @@ import { dsmFetch } from "./dsm-http.js";
4
4
  /** The precision caveat for the administrator-only fallback. */
5
5
  export const DSM_PORT_PROFILE_PRECISION_WARNING = "API 版未讀取 conf/resource;若有 App 自訂 Compose project 名可能誤報";
6
6
  /**
7
- * Parses the Docker .sc filename using the same rules as the Broker's
8
7
  * parsePortProfileFilename(). In particular, projectName is everything before
9
8
  * the final two dash-separated container segments.
10
9
  */
@@ -17,7 +16,6 @@ export function parsePortProfileFilename(filename) {
17
16
  if (!containerName) {
18
17
  return undefined;
19
18
  }
20
- // Keep this split aligned with packages/broker/src/diagnostics/dsm-residue.ts:
21
19
  // remove the final -<service>-<replica> pair, not an identity-specific guess.
22
20
  const lastDash = containerName.lastIndexOf("-");
23
21
  if (lastDash <= 0) {
@@ -2,77 +2,19 @@ import type { SharePermissionListing } from "../deploy/share-permission-prefligh
2
2
  import type { InstalledPackageState } from "./catalog-install.js";
3
3
  import type { PortInfoEntry } from "./port-info.js";
4
4
  import type { DsmPortProfileInventory } from "./dsm-port-profile.js";
5
- export type AttestationKind = "local" | "app-package" | "none";
6
- export type PackageRoute = "package-only" | "broker-installer" | "unknown";
7
- export type OidcOriginKind = "public-ca" | "quickconnect" | "lan-ip" | "self-signed" | "private-ca" | "http";
8
- export interface HostOidcOriginEvaluation {
9
- ready: boolean;
10
- kind: OidcOriginKind;
11
- hostname?: string;
12
- issuerUrl?: string;
13
- setupHint: string;
14
- }
15
- export interface HostOidcCompatSettings {
16
- enabled: boolean;
17
- origin: HostOidcOriginEvaluation;
18
- }
19
5
  export interface DeployIdentity {
20
6
  packageId: string;
21
7
  displayname: string;
22
8
  developmentInstance: boolean;
23
9
  }
24
- export interface AttestationIssueResult {
25
- kind: "local";
26
- attestationDigest: string;
27
- token?: string;
28
- }
29
- export interface ResidueItem {
30
- kind: "port_profile_sc" | "cm_project_config";
31
- path: string;
32
- name: string;
33
- reason: string;
34
- }
35
- export interface DsmResidueInventory {
36
- items: ResidueItem[];
37
- unreadable: string[];
38
- }
39
- export interface HostAttestationInfo {
40
- packageIdentity: string;
41
- attestationKind: AttestationKind;
42
- developmentInstance: boolean;
43
- openUrl?: string;
44
- readiness?: string;
45
- projectName?: string;
46
- }
47
- export interface HostInstallRecord {
48
- packageId: string;
49
- version?: string;
50
- source?: "package-center" | "local-spk";
51
- extraValues?: Record<string, string>;
52
- }
53
10
  export interface NasHost {
54
11
  readonly dsmOrigin: string;
55
- readonly installationId: string;
56
- requestAttestation(input: {
57
- packageIdentity: string;
58
- contractDigest: string;
59
- bundleDigest: string;
60
- capabilities: string[];
61
- allowCuratedDowngrade?: boolean;
62
- }): Promise<AttestationIssueResult>;
63
- installFromCatalog(input: {
64
- packageId: string;
65
- version?: string;
66
- extraValues?: Record<string, string>;
67
- }): Promise<void>;
68
- installFromLocalSpk?(input: {
12
+ installFromLocalSpk(input: {
69
13
  packageId: string;
70
14
  version: string;
71
15
  spkPath: string;
72
16
  extraValues?: Record<string, string>;
73
17
  }): Promise<void>;
74
- /** Stop and normally uninstall a formal package while preserving App Data. */
75
- uninstallPackage?(packageIdentity: string): Promise<void>;
76
18
  /**
77
19
  * CPU family of this NAS, for picking a native App's target. Returns
78
20
  * undefined when the DSM answer does not map to a family we ship, so the
@@ -94,35 +36,11 @@ export interface NasHost {
94
36
  listPortInfo?(): Promise<PortInfoEntry[] | undefined>;
95
37
  /** Resolve the NAS-specific user-home root when DSM User Home is enabled. */
96
38
  resolveHomesPath?(): Promise<string | undefined>;
97
- getInstalledProjectEnv?(packageIdentity: string): Promise<Record<string, string> | undefined>;
98
- ensurePackageSource?(origin: string): Promise<void>;
99
39
  getInstalledPackageVersion?(packageIdentity: string): Promise<string | undefined>;
100
40
  getInstalledPackageState?(packageIdentity: string): Promise<InstalledPackageState | undefined>;
101
- getAttestationInfo(packageIdentity: string): Promise<HostAttestationInfo>;
102
41
  isPackageInstalled(packageIdentity: string): Promise<boolean>;
103
42
  fetchContainerLogs(packageIdentity: string): Promise<string[]>;
104
- getDsmDiagnostics?(packageIdentity?: string): Promise<{
105
- dsmResidue?: DsmResidueInventory;
106
- packageRoute?: PackageRoute;
107
- isPackageOnly?: boolean;
108
- [key: string]: unknown;
109
- } | undefined>;
110
- /**
111
- * Read DSM PortInfo plus the administrator-visible installed package list.
112
- * This path does not require SynoPkgLandService; undefined means the host
113
- * could not answer and must be treated as unknown by diagnostics.
114
- */
115
43
  getDsmPortProfileInventory?(): Promise<DsmPortProfileInventory | undefined>;
116
- /** Read the optional administrator OIDC compatibility settings endpoint. */
117
- getOidcCompatSettings?(): Promise<HostOidcCompatSettings | undefined>;
118
- smokeRequireLogin(input: {
119
- packageIdentity: string;
120
- cookieHeader: string;
121
- }): Promise<{
122
- ok: boolean;
123
- username?: string;
124
- }>;
125
- markCurated?(packageIdentity: string): void;
126
44
  }
127
45
  export interface HostCredentials {
128
46
  dsmOrigin: string;
package/dist/index.d.ts CHANGED
@@ -6,14 +6,5 @@ export { initFromTemplate, isTemplateName } from "./init.js";
6
6
  export { runDev } from "./dev.js";
7
7
  export { testProject } from "./test-command.js";
8
8
  export { buildSpk } from "./build-spk/generator.js";
9
- export { publishProject, resolveCommunityAppsRoot } from "./publish/publish.js";
10
- export { communityAppsGitHubRepo, communityAppsGitHubUrl, DEFAULT_GITHUB_OWNER, } from "./publish/github-repo.js";
11
- export { InMemoryBuildLedger } from "./publish/build-ledger.js";
12
- export type { BuildLedger } from "./publish/build-ledger.js";
13
- export { createCuratedAttestationSignerFromEnv, isPublicOciDigest, releaseCurated, runCuratedRelease, runCuratedReleaseCli, digestReleaseBundle, validateCuratedCompose, } from "./publish/curated-release.js";
14
- export type { CuratedAttestationSignInput, CuratedAttestationSigner, CuratedComposeGateResult, CuratedReleaseSignInput, CuratedReleaseOptions, CuratedReleaseResult, } from "./publish/curated-release.js";
15
- export { canonicalAppPackageClaims, canonicalCuratedReleaseClaims, digestAppPackageClaims, digestCuratedReleaseClaims, normalizeCapabilities, assertPackageVersionBinding, signCuratedAppPackageAttestationToken, signCuratedReleaseAttestationToken, } from "./attestation/app-package.js";
16
- export type { AppPackageAttestationClaims, AppPackageSigningKey, CuratedAppPackageAttestationInput, CuratedReleaseAttestationClaims, CuratedReleaseAttestationInput, } from "./attestation/app-package.js";
17
- export { startMockBroker, FAKE_USER } from "./mock-broker/server.js";
18
9
  export { RecordingComposeRunner } from "./compose/runner.js";
19
10
  export type { ValidationError, ValidationResult } from "./types.js";
package/dist/index.js CHANGED
@@ -5,10 +5,4 @@ export { initFromTemplate, isTemplateName } from "./init.js";
5
5
  export { runDev } from "./dev.js";
6
6
  export { testProject } from "./test-command.js";
7
7
  export { buildSpk } from "./build-spk/generator.js";
8
- export { publishProject, resolveCommunityAppsRoot } from "./publish/publish.js";
9
- export { communityAppsGitHubRepo, communityAppsGitHubUrl, DEFAULT_GITHUB_OWNER, } from "./publish/github-repo.js";
10
- export { InMemoryBuildLedger } from "./publish/build-ledger.js";
11
- export { createCuratedAttestationSignerFromEnv, isPublicOciDigest, releaseCurated, runCuratedRelease, runCuratedReleaseCli, digestReleaseBundle, validateCuratedCompose, } from "./publish/curated-release.js";
12
- export { canonicalAppPackageClaims, canonicalCuratedReleaseClaims, digestAppPackageClaims, digestCuratedReleaseClaims, normalizeCapabilities, assertPackageVersionBinding, signCuratedAppPackageAttestationToken, signCuratedReleaseAttestationToken, } from "./attestation/app-package.js";
13
- export { startMockBroker, FAKE_USER } from "./mock-broker/server.js";
14
8
  export { RecordingComposeRunner } from "./compose/runner.js";
package/dist/info.d.ts CHANGED
@@ -8,7 +8,6 @@ export interface ProjectInfoOptions {
8
8
  export declare function projectInfo(options: ProjectInfoOptions): Promise<ProjectInfoResult>;
9
9
  export interface ProjectInfoResult {
10
10
  packageIdentity: string;
11
- attestationKind: "local" | "app-package" | "none";
12
11
  developmentInstance: boolean;
13
12
  openUrl?: string;
14
13
  readiness?: string;
package/dist/info.js CHANGED
@@ -3,27 +3,20 @@ import { appOriginFromContract } from "./host/open-url.js";
3
3
  import { resolveDeployIdentity } from "./deploy/identity.js";
4
4
  export async function projectInfo(options) {
5
5
  const identity = resolveDeployIdentity(options.project, { dev: options.dev });
6
- const remote = await options.host.getAttestationInfo(identity.packageId);
6
+ const remote = await options.host.getInstalledPackageState?.(identity.packageId);
7
7
  const installed = await options.host.isPackageInstalled(identity.packageId);
8
8
  const contract = loadContract(options.project.contractPath).contract;
9
9
  return {
10
10
  packageIdentity: identity.packageId,
11
- attestationKind: remote.attestationKind,
12
11
  developmentInstance: identity.developmentInstance,
13
- openUrl: remote.openUrl ?? appOriginFromContract(options.host.dsmOrigin, contract),
14
- readiness: remote.readiness ?? (installed ? "UNKNOWN" : "NOT_INSTALLED"),
12
+ openUrl: appOriginFromContract(options.host.dsmOrigin, contract),
13
+ readiness: remote?.status ?? (installed ? "UNKNOWN" : "NOT_INSTALLED"),
15
14
  installed,
16
15
  };
17
16
  }
18
17
  export function formatProjectInfo(info) {
19
- const attestationLabel = info.attestationKind === "app-package"
20
- ? "Curated(App Package Attestation)"
21
- : info.attestationKind === "local"
22
- ? "Local(Local Attestation)"
23
- : "無";
24
18
  return [
25
19
  `Package Identity:${info.packageIdentity}`,
26
- `Attestation:${attestationLabel}`,
27
20
  `開發用 Instance:${info.developmentInstance ? "是" : "否"}`,
28
21
  `已安裝:${info.installed ? "是" : "否"}`,
29
22
  info.openUrl ? `Open URL:${info.openUrl}` : "Open URL:(未設定)",
package/dist/init.d.ts CHANGED
@@ -1,4 +1,14 @@
1
1
  import type { TemplateName } from "./types.js";
2
2
  export declare function isTemplateName(value: string): value is TemplateName;
3
3
  export declare function listTemplates(): TemplateName[];
4
- export declare function initFromTemplate(template: TemplateName, targetDir: string): void;
4
+ export interface InitOptions {
5
+ /** Standalone templates: INFO.package (default: from the directory name). */
6
+ packageId?: string;
7
+ /** Standalone templates: display name (default: from the directory name). */
8
+ displayName?: string;
9
+ /** native-go: "root" adds administrator-approved root operations (default "none"). */
10
+ privilege?: "none" | "root";
11
+ ui?: "plain" | "vue";
12
+ integration?: "go" | "better-auth";
13
+ }
14
+ export declare function initFromTemplate(template: TemplateName, targetDir: string, options?: InitOptions): void;