@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,866 +1,814 @@
1
1
  export const ERROR_REGISTRY = {
2
- // --- Contract Validation ---
3
- CONTRACT_SCHEMA_UNSUPPORTED: {
4
- code: "CONTRACT_SCHEMA_UNSUPPORTED",
5
- description: "synology-app.yaml 的 schema 版本不受支援。",
6
- suggestion: "請將 synology-app.yaml 的 schema 欄位設為 1。",
7
- },
8
- CONTRACT_MISSING_FIELD: {
9
- code: "CONTRACT_MISSING_FIELD",
10
- description: "synology-app.yaml 缺少必填欄位。",
11
- suggestion: "請在 synology-app.yaml 補上缺少的必填欄位(例如 package, version, displayname 等)。",
12
- },
13
- CONTRACT_SCHEMA_INVALID: {
14
- code: "CONTRACT_SCHEMA_INVALID",
15
- description: "synology-app.yaml 格式與 JSON Schema 規格不符。",
16
- suggestion: "請修正 synology-app.yaml 的欄位格式以符合規範。",
17
- },
18
- PACKAGE_IDENTITY_TOO_LONG: {
19
- code: "PACKAGE_IDENTITY_TOO_LONG",
20
- description: "Package Identity 超過長度上限(正式身分上限 28 字元,最終身分上限 32 字元)。",
21
- suggestion: "請縮短 synology-app.yaml 中的 package 名稱(正式身分至多 28 字元,以保留 4 字元供 .dev 開發後綴使用)。",
22
- },
23
- CONTRACT_PACKAGE_TOO_LONG: {
24
- code: "CONTRACT_PACKAGE_TOO_LONG",
25
- description: "Package Identity 超過 DSM 上限 32 字元。",
26
- suggestion: "請縮短 synology-app.yaml 中的 package 名稱至 32 字元以內。",
27
- },
28
- CONTRACT_ADMINPORT_INVALID: {
29
- code: "CONTRACT_ADMINPORT_INVALID",
30
- description: "adminport 必須是整數。",
31
- suggestion: "請在 synology-app.yaml 提供與 Compose published port 對應的整數 adminport。",
32
- },
33
- CONTRACT_ADMINPORT_UNMAPPED: {
34
- code: "CONTRACT_ADMINPORT_UNMAPPED",
35
- description: "adminport 未在 Compose ports 宣告中對應到容器 port。",
36
- suggestion: "請在 compose.yaml 的 ports 區塊宣告與 adminport 對應的連接埠映射(例如 \"8080:80\")。",
37
- },
38
- CONTRACT_LAUNCH_INVALID: {
39
- code: "CONTRACT_LAUNCH_INVALID",
40
- description: "integration.web.launch 模式無效。",
41
- suggestion: "請改為 dsm-window(DSM 視窗,預設)或 new-page(新分頁),Headless App 請省略此欄位。",
42
- },
43
- CONTRACT_LAUNCH_REQUIRES_WEB: {
44
- code: "CONTRACT_LAUNCH_REQUIRES_WEB",
45
- description: "Headless App 不需要宣告 Web Launch Mode。",
46
- suggestion: "請省略 integration.web.launch,或補上對應 Compose published port 的 adminport。",
47
- },
48
- CONTRACT_INVALID_STRING: {
49
- code: "CONTRACT_INVALID_STRING",
50
- description: "合約字串含有不允許的控制字元或未允許的插值語法。",
51
- suggestion: "請移除控制字元與 ${ 插值語法,安裝參數請在 install 區塊宣告。",
52
- },
53
- CONTRACT_DSM_USER_DUPLICATE: {
54
- code: "CONTRACT_DSM_USER_DUPLICATE",
55
- description: "每顆 App 至多宣告一個 dsm_user 安裝參數。",
56
- suggestion: "請在 synology-app.yaml 只保留一個 Container Run-as 參數。",
57
- },
58
- INSTALL_STRING_TOO_LONG: {
59
- code: "INSTALL_STRING_TOO_LONG",
60
- description: "Install Parameter 字串預設值超過 256 字元。",
61
- suggestion: "請縮短 synology-app.yaml 中 install 參數的預設字串長度。",
62
- },
63
- INSTALL_STRING_INVALID: {
64
- code: "INSTALL_STRING_INVALID",
65
- description: "Install Parameter 字串值含有不合法字元或插值。",
66
- suggestion: "請移除 install 參數預設值中的控制字元與 ${ 插值語法。",
67
- },
68
- INSTALL_PARAMETER_UNREFERENCED: {
69
- code: "INSTALL_PARAMETER_UNREFERENCED",
70
- description: "install 宣告的參數未在 Compose 中被引用。",
71
- suggestion: "請在 compose.yaml 以 ${參數名稱} 引用該參數,或從 synology-app.yaml 移除未使用的宣告。",
72
- },
73
- INSTALL_DSM_USER_UNREFERENCED: {
74
- code: "INSTALL_DSM_USER_UNREFERENCED",
75
- description: "dsm_user 參數未在 Compose 中完整引用 UID 與 GID。",
76
- suggestion: "請在 compose.yaml 將容器 user 或 PUID/PGID 設為 ${NAME_UID}:${NAME_GID}。",
77
- },
78
- CONTRACT_HOMES_PATH_FORBIDDEN: {
79
- code: "CONTRACT_HOMES_PATH_FORBIDDEN",
80
- description: "homes Install Parameter 不得在契約中寫入 NAS 實體路徑或預設值。",
81
- suggestion: "請只宣告 type: homes 並在 Compose 引用該參數,由 glue/Broker 在安裝時解析這台 NAS 的 User Home 路徑。",
82
- },
83
- CONTRACT_POSIX_ALL_SHARES_VALUE_FORBIDDEN: {
84
- code: "CONTRACT_POSIX_ALL_SHARES_VALUE_FORBIDDEN",
85
- description: "POSIX all-shares 參數不得在契約中指定 default 或 NAS 實體路徑。",
86
- suggestion: "請只宣告 type: posix_all_shares,讓 wizard/CLI 在安裝時取得當下的 Share snapshot。",
87
- },
88
- DSM_USER_REQUIRED: {
89
- code: "DSM_USER_REQUIRED",
90
- description: "有 Shared Folder 時必須宣告恰好一個 dsm_user 作為 Container Run-as。",
91
- suggestion: "請在 synology-app.yaml 新增 install.<NAME>.type: dsm_user,並在 Compose 引用 ${NAME_UID}:${NAME_GID}。",
92
- },
93
- // --- Compose / Security Validation ---
94
- PROJECT_RUNTIME_EXCLUSIVE: {
95
- code: "PROJECT_RUNTIME_EXCLUSIVE",
96
- description: "專案同時存在 compose.yaml 與 native.yaml,兩者互斥。",
97
- suggestion: "請選擇使用 compose.yaml(容器 App)或 native.yaml(原生 App),並刪除另一個檔案。",
98
- },
99
- COMPOSE_MISSING: {
100
- code: "COMPOSE_MISSING",
101
- description: "找不到 compose.yaml 或 native.yaml。",
102
- suggestion: "請在專案根目錄建立 compose.yaml 或 native.yaml。",
103
- },
104
- COMPOSE_SERVICE_NOT_FOUND: {
105
- code: "COMPOSE_SERVICE_NOT_FOUND",
106
- description: "depends_on 引用的服務不存在於 compose.yaml 中。",
107
- suggestion: "請修正 compose.yaml 中的 depends_on,指向正確已定義的 service 名稱。",
108
- },
109
- COMPOSE_NUMERIC_COMMAND_ARG_FORBIDDEN: {
110
- code: "COMPOSE_NUMERIC_COMMAND_ARG_FORBIDDEN",
111
- description: "會走 DSM Docker Project resource worker 的 Compose command/entrypoint 陣列含純數字字串,可能在 worker YAML round-trip 後變成整數而無法 acquire。",
112
- suggestion: "請把整個命令包成單一字串,例如 command: [\"sh\", \"-c\", \"httpd -f -p 8080 -h /srv\"],或與 flag 併寫成 \"-p8080\"。",
113
- },
114
- COMPOSE_DYNAMIC_ROUTE_UNSUPPORTED: {
115
- code: "COMPOSE_DYNAMIC_ROUTE_UNSUPPORTED",
116
- description: "Compose dynamic route 超出 D1/D2 白名單,或使用 DSM worker 不會載入的 secret/config 來源。",
117
- suggestion: "請只使用 string/boolean wizard answer 的 ${NAME} interpolation;secret/config 因 DSM worker 不讀 docker-compose.override.yml 而拒收。",
118
- },
119
- COMPOSE_LEGACY_BROKER_STATE_PRESENT: {
120
- code: "COMPOSE_LEGACY_BROKER_STATE_PRESENT",
121
- description: "偵測到既有 Broker installer App Data,dynamic package-only route 不支援同一 Package Identity 的就地遷移。",
122
- suggestion: "請改用新的 Package Identity 安裝,或先完整卸載舊套件並清除 App Data。",
123
- },
124
- COMPOSE_BUILD_FORBIDDEN: {
125
- code: "COMPOSE_BUILD_FORBIDDEN",
126
- description: "D0 Compose route 禁止在 NAS install-time 使用 build:;build capability 永久拒收。",
127
- suggestion: "請移除 build:,改用已存在的 image(最好使用 image@sha256:... 固定 digest),再重新執行 validate。",
128
- },
129
- COMPOSE_SOCKET_MOUNT_FORBIDDEN: {
130
- code: "COMPOSE_SOCKET_MOUNT_FORBIDDEN",
131
- description: "嚴禁掛載 Docker Socket 或系統敏感 Socket。",
132
- suggestion: "請從 compose.yaml 移除 docker.sock 掛載;如需存取檔案請改用 shared_folder 或 File Gateway。",
133
- },
134
- COMPOSE_BIND_SOURCE_FORBIDDEN: {
135
- code: "COMPOSE_BIND_SOURCE_FORBIDDEN",
136
- description: "掛載來源路徑不合法或屬於受保護的系統路徑。",
137
- suggestion: "請使用受控的 ${SYNOPKG_PKGVAR}、${SYNO_APP_SECRETS_DIR} 或已宣告的 ${SHARED_FOLDER} 槽位。",
138
- },
139
- COMPOSE_BIND_SOURCE_UNDECLARED: {
140
- code: "COMPOSE_BIND_SOURCE_UNDECLARED",
141
- description: "Volume 掛載使用了未宣告的 Shared Folder 變數。",
142
- suggestion: "請先在 synology-app.yaml 的 install 區塊宣告該 shared_folder 參數。",
143
- },
144
- COMPOSE_BIND_SUFFIX_INVALID: {
145
- code: "COMPOSE_BIND_SUFFIX_INVALID",
146
- description: "Shared Folder 子路徑格式不合法(含有 .. 或控制字元)。",
147
- suggestion: "請改用合法的相對子路徑,例如 ${MEDIA_SHARE}/data:/data。",
148
- },
149
- COMPOSE_POSIX_ALL_SHARES_UNDECLARED: {
150
- code: "COMPOSE_POSIX_ALL_SHARES_UNDECLARED",
151
- description: "Compose 使用了未宣告的 POSIX all-shares marker。",
152
- suggestion: "請宣告 type: posix_all_shares,讓 package-only wizard/CLI 取得安裝當下的 Share snapshot。",
153
- },
154
- COMPOSE_POSIX_ALL_SHARES_SUFFIX_FORBIDDEN: {
155
- code: "COMPOSE_POSIX_ALL_SHARES_SUFFIX_FORBIDDEN",
156
- description: "POSIX all-shares marker 不得附加 Share 子路徑。",
157
- suggestion: "請只使用完整的 ${ALL_SHARES} source;每個 Share 的 container target 由 package-only preinst 展開。",
158
- },
159
- COMPOSE_HOST_BIND_FORBIDDEN: {
160
- code: "COMPOSE_HOST_BIND_FORBIDDEN",
161
- description: "禁止直接硬編碼本機路徑(例如 /volume1/... 或 ./)。",
162
- suggestion: "請在 synology-app.yaml 宣告 shared_folder 參數,並在 Compose 改用 ${SLOT} 引用。",
163
- },
164
- COMPOSE_NAMED_VOLUME_UNDECLARED: {
165
- code: "COMPOSE_NAMED_VOLUME_UNDECLARED",
166
- description: "服務使用了未在頂層 volumes 宣告的 Named Volume。",
167
- suggestion: "請在 compose.yaml 頂層 volumes 區塊補上該 Volume 宣告,或改用受控目錄。",
168
- },
169
- COMPOSE_USER_ROOT_FORBIDDEN: {
170
- code: "COMPOSE_USER_ROOT_FORBIDDEN",
171
- description: "容器以 root (0:0) 執行,違反最小權限原則。",
172
- suggestion: "請在 synology-app.yaml 宣告 dsm_user 並在 Compose 使用 ${USER_UID}:${USER_GID}。",
173
- },
174
- COMPOSE_USER_CONFLICTS_DSM_USER: {
175
- code: "COMPOSE_USER_CONFLICTS_DSM_USER",
176
- description: "Compose 服務自定義了 user 欄位,與 contract 宣告的 dsm_user 衝突。",
177
- suggestion: "請移除 Compose 中的 user 欄位,交由 dsm_user 自動注入 ${NAME_UID}:${NAME_GID} 與 group_add。",
178
- },
179
- COMPOSE_USER_NUMERIC_FORBIDDEN: {
180
- code: "COMPOSE_USER_NUMERIC_FORBIDDEN",
181
- description: "禁止在 compose.yaml 硬編碼數字 uid:gid。",
182
- suggestion: "請在 synology-app.yaml 宣告 dsm_user,並在 Compose 引用 ${NAME_UID}:${NAME_GID}。",
183
- },
184
- COMPOSE_PRIVILEGED_FORBIDDEN: {
185
- code: "COMPOSE_PRIVILEGED_FORBIDDEN",
186
- description: "使用了 privileged: true 但未在合約宣告。",
187
- suggestion: "請在 synology-app.yaml 加上 privilege.privileged: true,或移除 privileged: true。",
188
- },
189
- COMPOSE_HOST_NETWORK_FORBIDDEN: {
190
- code: "COMPOSE_HOST_NETWORK_FORBIDDEN",
191
- description: "使用了 host network 模式但未在合約宣告。",
192
- suggestion: "請在 synology-app.yaml 加上 privilege.host_network: true,或改用受控網路模式。",
193
- },
194
- COMPOSE_HOST_PID_FORBIDDEN: {
195
- code: "COMPOSE_HOST_PID_FORBIDDEN",
196
- description: "使用了 pid: host 但未在合約宣告。",
197
- suggestion: "請在 synology-app.yaml 加上 privilege.host_pid: true,或移除 pid: host。",
198
- },
199
- COMPOSE_HOST_IPC_FORBIDDEN: {
200
- code: "COMPOSE_HOST_IPC_FORBIDDEN",
201
- description: "使用了 ipc: host 但未在合約宣告。",
202
- suggestion: "請在 synology-app.yaml 加上 privilege.host_ipc: true,或移除 ipc: host。",
203
- },
204
- COMPOSE_DEVICES_FORBIDDEN: {
205
- code: "COMPOSE_DEVICES_FORBIDDEN",
206
- description: "使用了 devices 裝置存取但未在合約宣告。",
207
- suggestion: "請在 synology-app.yaml 加上 privilege.devices: true,或移除 devices 區塊。",
208
- },
209
- COMPOSE_CAP_ADD_FORBIDDEN: {
210
- code: "COMPOSE_CAP_ADD_FORBIDDEN",
211
- description: "使用了 cap_add 權限提升但未在合約宣告。",
212
- suggestion: "請在 synology-app.yaml 加上 privilege.cap_add: true,或移除 cap_add 區塊。",
213
- },
214
- COMPOSE_ENV_MISSING: {
215
- code: "COMPOSE_ENV_MISSING",
216
- description: "專案缺少必要的環境變數目錄結構。",
217
- suggestion: "請確認 SYNOPKG_PKGVAR 與 secrets 目錄已正確建立。",
218
- },
219
- COMPOSE_NOT_HEALTHY: {
220
- code: "COMPOSE_NOT_HEALTHY",
221
- description: "Compose 服務未能於時限內通過 healthcheck 達到 healthy 狀態。",
222
- suggestion: "請檢查容器健康檢查設定與應用程式日誌:synopkgland log --host <nas>。",
223
- },
224
- COMPOSE_NOT_RUNNING: {
225
- code: "COMPOSE_NOT_RUNNING",
226
- description: "Compose 服務未能於時限內維持 running 狀態。",
227
- suggestion: "請檢查容器啟動腳本與日誌以排除崩潰原因:synopkgland log --host <nas>。",
228
- },
229
- // --- Native Validation / Payload ---
230
- NATIVE_LOAD_FAILED: {
231
- code: "NATIVE_LOAD_FAILED",
232
- description: "無法讀取或解析 native.yaml。",
233
- suggestion: "請確認 native.yaml 存在且為合法 YAML 格式。",
234
- },
235
- NATIVE_SCHEMA_INVALID: {
236
- code: "NATIVE_SCHEMA_INVALID",
237
- description: "native.yaml schema 版本無效(必須為整數 1)。",
238
- suggestion: "請在 native.yaml 設定 schema: 1。",
239
- },
240
- NATIVE_TARGETS_REQUIRED: {
241
- code: "NATIVE_TARGETS_REQUIRED",
242
- description: "native.yaml 缺少 targets 區塊。",
243
- suggestion: "請在 native.yaml 宣告 targets 區塊並指定 x86_64 或 aarch64 目標。",
244
- },
245
- NATIVE_TARGETS_EMPTY: {
246
- code: "NATIVE_TARGETS_EMPTY",
247
- description: "native.yaml 中的 targets 區塊不可為空。",
248
- suggestion: "請在 native.yaml 的 targets 內至少定義一個架構目標(x86_64 或 aarch64)。",
249
- },
250
- NATIVE_ARCH_UNKNOWN: {
251
- code: "NATIVE_ARCH_UNKNOWN",
252
- description: "native.yaml 定義了不受支援的架構目標名稱。",
253
- suggestion: "目標架構名稱僅支援 x86_64 與 aarch64。",
254
- },
255
- NATIVE_TARGET_INVALID: {
256
- code: "NATIVE_TARGET_INVALID",
257
- description: "native.yaml 目標架構定義無效。",
258
- suggestion: "每個目標架構必須包含 path 或 url 下載來源設定。",
259
- },
260
- NATIVE_TARGET_NOT_DECLARED: {
261
- code: "NATIVE_TARGET_NOT_DECLARED",
262
- description: "欲建置或部署的架構目標未在 native.yaml 中宣告。",
263
- suggestion: "請在 native.yaml 的 targets 補上該架構目標,或透過 --arch 指定已宣告的目標。",
264
- },
265
- NATIVE_TARGET_SOURCE_EXCLUSIVE: {
266
- code: "NATIVE_TARGET_SOURCE_EXCLUSIVE",
267
- description: "目標架構不可同時包含 path 與 url,兩者互斥。",
268
- suggestion: "請在該目標架構中只保留 path(本機)或 url(遠端二進位檔)。",
269
- },
270
- NATIVE_PATH_FORBIDDEN_IN_LISTING: {
271
- code: "NATIVE_PATH_FORBIDDEN_IN_LISTING",
272
- description: "公開上架審查禁止使用本機 path 來源的 native 目標。",
273
- suggestion: "請將 target 改為公開可下載的 url 並附帶 sha256 校驗碼。",
274
- },
275
- NATIVE_SHA256_REQUIRED_IN_LISTING: {
276
- code: "NATIVE_SHA256_REQUIRED_IN_LISTING",
277
- description: "公開上架審查要求 url 目標必須提供 sha256 校驗碼。",
278
- suggestion: "請在 native.yaml 的 url 目標補上 64 位十六進位 sha256 欄位。",
279
- },
280
- NATIVE_SHA256_INVALID: {
281
- code: "NATIVE_SHA256_INVALID",
282
- description: "sha256 校驗碼格式無效。",
283
- suggestion: "請提供恰好 64 字元的十六進位 SHA-256 字串。",
284
- },
285
- NATIVE_STRIP_COMPONENTS_INVALID: {
286
- code: "NATIVE_STRIP_COMPONENTS_INVALID",
287
- description: "strip_components 必須是非負整數。",
288
- suggestion: "請在 native.yaml 將 strip_components 設為大於等於 0 的整數。",
289
- },
290
- NATIVE_SERVICE_REQUIRED: {
291
- code: "NATIVE_SERVICE_REQUIRED",
292
- description: "native.yaml 缺少 service 區塊。",
293
- suggestion: "請在 native.yaml 補上 service 區塊並宣告 exec 與 args/env。",
294
- },
295
- NATIVE_SERVICE_USER_FORBIDDEN: {
296
- code: "NATIVE_SERVICE_USER_FORBIDDEN",
297
- description: "native service 不允許自訂 user 欄位(固定以 package 使用者執行)。",
298
- suggestion: "請從 native.yaml 的 service 區塊移除 user 欄位。",
299
- },
300
- NATIVE_SERVICE_SHELL_FIELD_FORBIDDEN: {
301
- code: "NATIVE_SERVICE_SHELL_FIELD_FORBIDDEN",
302
- description: "禁止在 native service 使用 command/shell 等字串欄位以免 shell injection。",
303
- suggestion: "請改用 exec(路徑)與 args(字串陣列)方式宣告啟動指令。",
304
- },
305
- NATIVE_EXEC_REQUIRED: {
306
- code: "NATIVE_EXEC_REQUIRED",
307
- description: "native service 缺少 exec 執行檔路徑。",
308
- suggestion: "請在 native.yaml 的 service 區塊指定 exec: <相對路徑>。",
309
- },
310
- NATIVE_EXEC_INVALID_PATH: {
311
- code: "NATIVE_EXEC_INVALID_PATH",
312
- description: "exec 必須是相對路徑,且不可包含 .. 或絕對路徑。",
313
- suggestion: "請指定相對於安裝根目錄的合法相對路徑,例如 exec: bin/app。",
314
- },
315
- NATIVE_ARGS_INVALID: {
316
- code: "NATIVE_ARGS_INVALID",
317
- description: "service.args 必須是字串陣列。",
318
- suggestion: "請在 native.yaml 將 args 宣告為字串列表格式(例如 args: [\"--port\", \"8080\"])。",
319
- },
320
- NATIVE_ENV_INVALID: {
321
- code: "NATIVE_ENV_INVALID",
322
- description: "service.env 必須是 key-value 字串映射表。",
323
- suggestion: "請將 env 宣告為字典物件且每個值皆為字串。",
324
- },
325
- NATIVE_PKGVAR_REQUIRED: {
326
- code: "NATIVE_PKGVAR_REQUIRED",
327
- description: "原生二進位 App 必須在 args 或 env 中引用 ${SYNOPKG_PKGVAR} 以指定資料路徑。",
328
- suggestion: "請在 native.yaml 的 service.args 或 service.env 加入 ${SYNOPKG_PKGVAR} 參數。",
329
- },
330
- NATIVE_ARCH_FAMILY_REQUIRED: {
331
- code: "NATIVE_ARCH_FAMILY_REQUIRED",
332
- description: "建置原生 SPK 時缺少目標架構家族(x86_64 或 aarch64)。",
333
- suggestion: "請在指令加上 --arch x86_64 或 --arch aarch64。",
334
- },
335
- NATIVE_ARCH_UNDETERMINED: {
336
- code: "NATIVE_ARCH_UNDETERMINED",
337
- description: "無法從目標 NAS 的 CPU 資訊自動判定架構家族。",
338
- suggestion: "請使用 --arch x86_64 或 --arch aarch64 明確指定目標架構。",
339
- },
340
- NATIVE_PAYLOAD_BUNDLE_COLLISION: {
341
- code: "NATIVE_PAYLOAD_BUNDLE_COLLISION",
342
- description: "原生 payload 解壓縮內容與 App Bundle 核心保留檔衝突。",
343
- suggestion: "請檢查 payload 內容,避免在根目錄覆蓋 synology-app.yaml 或 native.yaml。",
344
- },
345
- NATIVE_PAYLOAD_DOWNLOAD_FAILED: {
346
- code: "NATIVE_PAYLOAD_DOWNLOAD_FAILED",
347
- description: "下載原生二進位檔 payload 失敗。",
348
- suggestion: "請檢查 native.yaml 中的 url 是否有效且網路連線正常。",
349
- },
350
- NATIVE_PAYLOAD_DOWNLOAD_INVALID: {
351
- code: "NATIVE_PAYLOAD_DOWNLOAD_INVALID",
352
- description: "下載的原生 payload 回傳內容無效。",
353
- suggestion: "請確認目標 URL 回傳了有效的二進位檔案內容。",
354
- },
355
- NATIVE_PAYLOAD_DUPLICATE_ENTRY: {
356
- code: "NATIVE_PAYLOAD_DUPLICATE_ENTRY",
357
- description: "原生 payload 壓縮檔內包含重複的檔案路徑。",
358
- suggestion: "請重新打包原始檔案,確保壓縮檔內無重複 entry。",
359
- },
360
- NATIVE_PAYLOAD_ERROR: {
361
- code: "NATIVE_PAYLOAD_ERROR",
362
- description: "處理原生二進位 payload 時發生未預期錯誤。",
363
- suggestion: "請檢查 payload 壓縮檔完整性或重新建置 SPK。",
364
- },
365
- NATIVE_PAYLOAD_EXTRACTION_FAILED: {
366
- code: "NATIVE_PAYLOAD_EXTRACTION_FAILED",
367
- description: "解壓縮原生二進位 payload 失敗。",
368
- suggestion: "請確認壓縮檔格式正確無損壞,且支援 tar.gz / tar.xz / zip。",
369
- },
370
- NATIVE_PAYLOAD_INVALID_HARDLINK: {
371
- code: "NATIVE_PAYLOAD_INVALID_HARDLINK",
372
- description: "原生 payload 含有無效或循環的 hardlink。",
373
- suggestion: "請移除壓縮檔中不合法的 hardlink 後重新打包。",
374
- },
375
- NATIVE_PAYLOAD_INVALID_STRIP_COMPONENTS: {
376
- code: "NATIVE_PAYLOAD_INVALID_STRIP_COMPONENTS",
377
- description: "strip_components 設定超過了壓縮檔目錄層級深度。",
378
- suggestion: "請在 native.yaml 調整或減少 strip_components 數值。",
379
- },
380
- NATIVE_PAYLOAD_INVALID_SYMLINK: {
381
- code: "NATIVE_PAYLOAD_INVALID_SYMLINK",
382
- description: "原生 payload 含有無效的符號連結。",
383
- suggestion: "請檢查壓縮檔內的 symlink 目標是否存在且合法。",
384
- },
385
- NATIVE_PAYLOAD_INVALID_ZIP: {
386
- code: "NATIVE_PAYLOAD_INVALID_ZIP",
387
- description: "ZIP 壓縮檔格式無效或已損壞。",
388
- suggestion: "請檢查 zip 檔案完整性或重新打包。",
389
- },
390
- NATIVE_PAYLOAD_SHA256_MISMATCH: {
391
- code: "NATIVE_PAYLOAD_SHA256_MISMATCH",
392
- description: "下載的 payload SHA-256 校驗碼與 native.yaml 宣告不符。",
393
- suggestion: "請更新 native.yaml 中的 sha256 欄位以符合實際檔案雜湊。",
394
- },
395
- NATIVE_PAYLOAD_SOURCE_AMBIGUOUS: {
396
- code: "NATIVE_PAYLOAD_SOURCE_AMBIGUOUS",
397
- description: "目標架構同時宣告了 path 與 url,來源衝突。",
398
- suggestion: "請在該目標架構中只保留 path 或 url 其中一種來源。",
399
- },
400
- NATIVE_PAYLOAD_SOURCE_REQUIRED: {
401
- code: "NATIVE_PAYLOAD_SOURCE_REQUIRED",
402
- description: "目標架構缺少 path 或 url 來源設定。",
403
- suggestion: "請在 native.yaml 的 targets 內為各架構補上 path 或 url。",
404
- },
405
- NATIVE_PAYLOAD_SYMLINK_CYCLE: {
406
- code: "NATIVE_PAYLOAD_SYMLINK_CYCLE",
407
- description: "原生 payload 包含循環符號連結 (Symlink cycle)。",
408
- suggestion: "請移除壓縮檔中的循環 symlink。",
409
- },
410
- NATIVE_PAYLOAD_UNSAFE_HARDLINK: {
411
- code: "NATIVE_PAYLOAD_UNSAFE_HARDLINK",
412
- description: "原生 payload hardlink 試圖連結至目標目錄外。",
413
- suggestion: "請確保 hardlink 僅指向 payload 目錄內部的有效檔案。",
414
- },
415
- NATIVE_PAYLOAD_UNSAFE_PATH: {
416
- code: "NATIVE_PAYLOAD_UNSAFE_PATH",
417
- description: "原生 payload 含有路徑穿越 (Path traversal) 等不安全路徑。",
418
- suggestion: "請確保壓縮檔內無包含 .. 或絕對路徑的檔案名稱。",
419
- },
420
- NATIVE_PAYLOAD_UNSAFE_SYMLINK: {
421
- code: "NATIVE_PAYLOAD_UNSAFE_SYMLINK",
422
- description: "原生 payload symlink 指向了安裝目錄之外。",
423
- suggestion: "請確保 symlink 僅指向 payload 目錄內部的相對目標。",
424
- },
425
- NATIVE_PAYLOAD_UNSUPPORTED_ENTRY: {
426
- code: "NATIVE_PAYLOAD_UNSUPPORTED_ENTRY",
427
- description: "原生 payload 包含不支援的特殊檔案類型(如 device node 或 fifo)。",
428
- suggestion: "請從壓縮檔中移除特殊檔案,僅保留一般檔案、目錄與合法 symlink。",
429
- },
430
- NATIVE_PAYLOAD_UNSUPPORTED_ZIP: {
431
- code: "NATIVE_PAYLOAD_UNSUPPORTED_ZIP",
432
- description: "不支援的 ZIP 特性(例如 ZIP64、多卷分割或密碼加密)。",
433
- suggestion: "請使用標準未加密的 ZIP 或改用 tar.gz 打包。",
434
- },
435
- NATIVE_PAYLOAD_XZ_FAILED: {
436
- code: "NATIVE_PAYLOAD_XZ_FAILED",
437
- description: "解壓縮 tar.xz 失敗。",
438
- suggestion: "請確認本機已安裝 xz 工具且檔案未損壞。",
439
- },
440
- NATIVE_PAYLOAD_XZ_UNAVAILABLE: {
441
- code: "NATIVE_PAYLOAD_XZ_UNAVAILABLE",
442
- description: "系統中找不到 xz 指令可用於解壓縮 .tar.xz 檔案。",
443
- suggestion: "請在作業系統中安裝 xz-utils 或改用 tar.gz 格式打包。",
444
- },
445
- // --- SPK Build & Attestation ---
446
- EMBEDDED_ATTESTATION_TOKEN_EMPTY: {
447
- code: "EMBEDDED_ATTESTATION_TOKEN_EMPTY",
448
- description: "建置 Curated SPK 時嵌入的 Attestation Token 為空。",
449
- suggestion: "請檢查 CI Attestation 簽章步驟是否正常產出 JWT。",
450
- },
451
- BUILD_SPK_FAILED: {
452
- code: "BUILD_SPK_FAILED",
453
- description: "SPK 打包流程失敗。",
454
- suggestion: "請檢查 validate 錯誤與目錄檔案權限後重試。",
455
- },
456
- // --- Deploy & Host ---
457
- VALIDATION_FAILED: {
458
- code: "VALIDATION_FAILED",
459
- description: "專案未通過契約或安全驗證,終止部署。",
460
- suggestion: "請先執行 synopkgland validate 排除合約與 Compose 錯誤。",
461
- },
462
- DEPLOY_FAILED: {
463
- code: "DEPLOY_FAILED",
464
- description: "部署至 NAS 時發生未分類錯誤。",
465
- suggestion: "請檢查 NAS 網路連線與日誌:synopkgland log --host <nas>。",
466
- },
467
- DEPLOY_PERSONAL_BUILD_EXHAUSTED: {
468
- code: "DEPLOY_PERSONAL_BUILD_EXHAUSTED",
469
- description: "Personal App 的 Package Build 已用盡 0001–9999 命名範圍。",
470
- suggestion: "請改用新的 App Version,或先清理並確認不會與 Curated 版本命名空間混用。",
471
- },
472
- DEPLOY_VERSION_NOT_ASCENDING: {
473
- code: "DEPLOY_VERSION_NOT_ASCENDING",
474
- description: "部署產生的 Package Version 不高於既有版本。",
475
- suggestion: "請提高 synology-app.yaml 的 version,或確認目標 NAS 與 Package Source 上的既有版本。",
476
- },
477
- SHARE_VALUE_REQUIRED: {
478
- code: "SHARE_VALUE_REQUIRED",
479
- description: "部署時缺少合約中宣告的 shared_folder 實際路徑映射。",
480
- suggestion: "請使用 --share <SLOT>=<邏輯名> 提供對應的 Shared Folder 名稱。",
481
- },
482
- SHARE_LOGICAL_NAME_REQUIRED: {
483
- code: "SHARE_LOGICAL_NAME_REQUIRED",
484
- description: "Share 參數必須提供邏輯名稱,禁止使用 /volume1/... 等實體路徑。",
485
- suggestion: "請指定 DSM 控制台中的 Shared Folder 邏輯名稱,例如 --share MEDIA_SHARE=photos。",
486
- },
487
- SHARE_NOT_FOUND: {
488
- code: "SHARE_NOT_FOUND",
489
- description: "在目標 NAS 上找不到指定的 Shared Folder。",
490
- suggestion: "請在 DSM 控制台建立該 Shared Folder,或檢查名稱拼字。",
491
- },
492
- HOMES_NOT_ENABLED: {
493
- code: "HOMES_NOT_ENABLED",
494
- description: "目標 NAS 未啟用 User Home,或無法解析 homes 的實體 bind source。",
495
- suggestion: "請在這台 NAS 啟用 DSM User Home,並確認 Broker/glue 能回傳解析後的路徑,再重新部署。",
496
- },
497
- DSM_USER_LOGICAL_NAME_REQUIRED: {
498
- code: "DSM_USER_LOGICAL_NAME_REQUIRED",
499
- description: "dsm_user 參數必須提供 DSM 使用者邏輯名稱,禁止使用數字 UID。",
500
- suggestion: "請在 --run-as 指定 DSM 使用者帳號名稱(例如 --run-as RUN_AS=alice)。",
501
- },
502
- SHARE_RUN_AS_NO_ACCESS: {
503
- code: "SHARE_RUN_AS_NO_ACCESS",
504
- description: "deploy 的安裝前檢查發現選定的 Container Run-as 使用者對選定的 Shared Folder 沒有權限(或被明確拒絕)。容器會以該使用者掛載該 Share,安裝會成功但 runtime 讀寫會拿到 Permission denied。",
505
- suggestion: "請在 DSM 控制台把該 Shared Folder 的權限授予該使用者(或其群組),或改選別的使用者/Share,再重新部署。此檢查只在 deploy 進行;Package Center 安裝精靈不經過這裡,ACL 仍是管理員的前提責任。",
506
- },
507
- PORT_ALREADY_IN_USE: {
508
- code: "PORT_ALREADY_IN_USE",
509
- description: "deploy 的安裝前檢查發現 Compose published TCP port 已被其他服務或容器佔用。",
510
- suggestion: "請更換 synology-app.yaml/compose.yaml 的 published host port;同一 Package Identity 的既有容器會在升級或重裝時放行。",
511
- },
512
- CURATED_DEPLOY_REFUSED: {
513
- code: "CURATED_DEPLOY_REFUSED",
514
- description: "目標 NAS 已持有 Curated App Package Attestation,禁止隨意覆蓋部署。",
515
- suggestion: "請改用 --dev 部署至開發隔離環境,或加上 --replace-curated 明確降級。",
516
- },
517
- CATALOG_PUBLISH_FAILED: {
518
- code: "CATALOG_PUBLISH_FAILED",
519
- description: "發布 SPK 至 Package Source 失敗。",
520
- suggestion: "請確認 Package Source 服務運作正常且網路可達。",
521
- },
522
- LOCAL_SPK_INSTALL_UNSUPPORTED: {
523
- code: "LOCAL_SPK_INSTALL_UNSUPPORTED",
524
- description: "目標主機介面不支援直接安裝本機 SPK。",
525
- suggestion: "請透過 Package Center 或支援 local-spk 安裝的 Host Adapter 進行部署。",
526
- },
527
- CATALOG_INSTALL_FAILED: {
528
- code: "CATALOG_INSTALL_FAILED",
529
- description: "NAS Package Center 安裝套件失敗。",
530
- suggestion: "請至 DSM Package Center 檢查安裝日誌或手動嘗試安裝。",
531
- },
532
- DEPLOY_PARAM_UNDECLARED: {
533
- code: "DEPLOY_PARAM_UNDECLARED",
534
- description: "deploy --param 提供了契約未宣告的 Install Parameter。",
535
- suggestion: "請只傳 synology-app.yaml install 中宣告的 string 或 boolean 名稱。",
536
- },
537
- DEPLOY_PARAM_TYPE_INVALID: {
538
- code: "DEPLOY_PARAM_TYPE_INVALID",
539
- description: "deploy --param 的值不符合契約宣告的 string 或 boolean 型別。",
540
- suggestion: "string 請傳非空字串;boolean 請只傳 true 或 false。",
541
- },
542
- DEPLOY_POSIX_ALL_SHARES_LOOKUP_FAILED: {
543
- code: "DEPLOY_POSIX_ALL_SHARES_LOOKUP_FAILED",
544
- description: "無法以管理員 session 列出部署當下的 Shared Folder 清單。",
545
- suggestion: "請確認 DSM 管理員 session 可呼叫 SYNO.Core.Share list,或用 --param NAME=... 明確提供清單。",
546
- },
547
- DSM_DEPENDENCY_CONFLICT: {
548
- code: "DSM_DEPENDENCY_CONFLICT",
549
- description: "DSM 複合安裝請求因執行中的依賴套件而拒絕。",
550
- suggestion: "請先停止列出的依賴套件再重試升級。",
551
- },
552
- DSM_COMPOUND_FAILED: {
553
- code: "DSM_COMPOUND_FAILED",
554
- description: "DSM 複合安裝請求的子步驟失敗。",
555
- suggestion: "請檢查回應中的 api、method、errorCode 與 DSM Package Center 日誌後重試。",
556
- },
557
- DSM_REQUEST_FAILED: {
558
- code: "DSM_REQUEST_FAILED",
559
- description: "DSM SYNO.Entry.Request 複合請求失敗。",
560
- suggestion: "請檢查 DSM session、請求參數與 Package Center 日誌後重試。",
561
- },
562
- INNER_LOOP_API_MISSING: {
563
- code: "INNER_LOOP_API_MISSING",
564
- description: "目標 NAS 上的 SynoPkgLandService Broker inner-loop API 不可用。",
565
- suggestion: "請確認已在 NAS 安裝並啟動 SynoPkgLandService (Broker >= 0.1.0-0016)。",
566
- },
567
- ATTESTATION_FAILED: {
568
- code: "ATTESTATION_FAILED",
569
- description: "向 NAS 申請或驗證 Local Attestation 失敗。",
570
- suggestion: "請檢查 DSM 登入身分是否為管理者,以及 Broker 運作狀態。",
571
- },
572
- NOT_INSTALLED: {
573
- code: "NOT_INSTALLED",
574
- description: "套件尚未在目標 NAS 上安裝部署。",
575
- suggestion: "請先執行 synopkgland deploy --host <nas> 安裝套件。",
576
- },
577
- HOST_CREDENTIALS_MISSING: {
578
- code: "HOST_CREDENTIALS_MISSING",
579
- description: "找不到目標 NAS 的連線憑證。",
580
- suggestion: "請在 ~/.synoagentcli/setting.json 設定 profile,或設定 DSM_URL 與 DSM_PASSWORD 環境變數。",
581
- },
582
- HOST_UNREACHABLE: {
583
- code: "HOST_UNREACHABLE",
584
- description: "無法連線至目標 NAS(連線逾時或網路不可達)。",
585
- suggestion: "請檢查 NAS IP/網址與網路連線;Node 網路若遇 EHOSTUNREACH 可使用 curl fallback 模式。",
586
- },
587
- BROKER_NOT_INSTALLED: {
588
- code: "BROKER_NOT_INSTALLED",
589
- description: "目標 NAS 尚未安裝 SynoPkgLandService (Broker)。",
590
- suggestion: "請至 DSM Package Center 安裝 SynoPkgLandService 套件。",
591
- },
592
- PACKAGE_BROKEN: {
593
- code: "PACKAGE_BROKEN",
594
- description: "套件在 DSM Package Center 處於損毀或安裝失敗狀態 (status 150 / broken)。",
595
- suggestion: "請至 DSM Package Center 嘗試修復 (Repair) 或重新安裝套件。",
596
- },
597
- ATTESTATION_TRUST_ROOT_MISSING: {
598
- code: "ATTESTATION_TRUST_ROOT_MISSING",
599
- description: "Broker 缺少生產環境 Attestation Trust Root 信任根憑證。",
600
- suggestion: "請確認 SynoPkgLandService 套件完整安裝且 trust root keyring 未被移除。",
601
- },
602
- ATTESTATION_MISSING: {
603
- code: "ATTESTATION_MISSING",
604
- description: "App Bundle 缺少必要的 Attestation 簽章憑證。",
605
- suggestion: "請先透過 synopkgland deploy 簽發 Local Attestation 或透過 Curated CI 簽署。",
606
- },
607
- ATTESTATION_INVALID: {
608
- code: "ATTESTATION_INVALID",
609
- description: "Attestation Token 驗證失敗或與目前 App Bundle 雜湊不符。",
610
- suggestion: "檔案修改後請重新執行 synopkgland deploy 產生並安裝新 Attestation。",
611
- },
612
- READINESS_TIMEOUT: {
613
- code: "READINESS_TIMEOUT",
614
- description: "App 容器未在時限內就緒 (Readiness Deadline)。",
615
- suggestion: "請使用 synopkgland log --host <nas> 檢查容器啟動日誌與健康檢查。",
616
- },
617
- PROJECT_BINDING_NOT_FOUND: {
618
- code: "PROJECT_BINDING_NOT_FOUND",
619
- description: "在 Broker 中找不到此套件的 Project Binding 紀錄。",
620
- suggestion: "請執行 synopkgland deploy --host <nas> 重新建立部署。",
621
- },
622
- PROJECT_BINDING_DRIFTED: {
623
- code: "PROJECT_BINDING_DRIFTED",
624
- description: "Container Manager 中的實際專案狀態與 Broker 綁定記錄不一致。",
625
- suggestion: "請執行 synopkgland deploy --host <nas> 重新同步專案。",
626
- },
627
- PROJECT_BINDING_REMOVED: {
628
- code: "PROJECT_BINDING_REMOVED",
629
- description: "此套件的 Project Binding 已被標記為移除。",
630
- suggestion: "請執行 synopkgland deploy --host <nas> 重新安裝套件。",
631
- },
632
- PROJECT_BINDING_UNKNOWN: {
633
- code: "PROJECT_BINDING_UNKNOWN",
634
- description: "Container Manager 暫時無法取得 Project 狀態。",
635
- suggestion: "請至 DSM 確認 Container Manager 服務正常運作。",
636
- },
637
- CLI_VERSION_DRIFT: {
638
- code: "CLI_VERSION_DRIFT",
639
- description: "本機 @synopackageland/cli 版本與 CI TOOLCHAIN_VERSION 不一致。",
640
- suggestion: "請更新 package.json / package-lock.json 或執行 npm install @synopackageland/cli@latest。",
641
- },
642
- PROJECT_FILES_MISSING: {
643
- code: "PROJECT_FILES_MISSING",
644
- description: "專案根目錄缺少核心檔案(synology-app.yaml, compose.yaml/native.yaml, README.md, icon.png)。",
645
- suggestion: "請補齊缺失的專案核心檔案。",
646
- },
647
- TRUSTED_APP_ENTRY_FAILED: {
648
- code: "TRUSTED_APP_ENTRY_FAILED",
649
- description: "Trusted App Entry HTTP 探測失敗(回傳非 200 或無法連線)。",
650
- suggestion: "請檢查 Web Station 入口與容器 Web 服務是否正常監聽 adminport。",
651
- },
652
- TEST_HOST_FAILED: {
653
- code: "TEST_HOST_FAILED",
654
- description: "在 NAS 上執行 Open smoke 測試失敗(無法取得 DSM User Context)。",
655
- suggestion: "請檢查 App 是否正確呼叫 requireLogin 或檢查 DSM Session 登入態。",
656
- },
657
- // --- Curated Release & Trust Root ---
658
- CURATED_TRUST_ROOT_MISSING: {
659
- code: "CURATED_TRUST_ROOT_MISSING",
660
- description: "缺少 Curated Public Keyring 信任根設定。",
661
- suggestion: "請設定 SYNOPKGLAND_CURATED_ATTESTATION_KEYRING 或 SYNOPKGLAND_CURATED_ATTESTATION_KEYRING_PATH。",
662
- },
663
- CURATED_TRUST_ROOT_INVALID: {
664
- code: "CURATED_TRUST_ROOT_INVALID",
665
- description: "Curated Public Keyring 格式或內容無效。",
666
- suggestion: "請確認信任根為合法 JSON 且包含合規的 RS256 公鑰物件。",
667
- },
668
- CURATED_SIGNING_KEY_UNKNOWN: {
669
- code: "CURATED_SIGNING_KEY_UNKNOWN",
670
- description: "簽署金鑰的 kid 不存在於 Curated Public Keyring 中。",
671
- suggestion: "請確認所使用的簽署金鑰已登錄於受信任的 Keyring 信任根。",
672
- },
673
- CURATED_SIGNING_KEY_REVOKED: {
674
- code: "CURATED_SIGNING_KEY_REVOKED",
675
- description: "簽署金鑰已被標記為撤銷 (revoked)。",
676
- suggestion: "請更換為有效且處於 active 狀態的簽署金鑰。",
677
- },
678
- CURATED_SIGNING_KEY_NOT_ACTIVE: {
679
- code: "CURATED_SIGNING_KEY_NOT_ACTIVE",
680
- description: "簽署金鑰非 active 狀態(可能為 verify-only)。",
681
- suggestion: "請使用具備簽章權限的 active 簽署金鑰。",
682
- },
683
- CURATED_SIGNING_KEY_MISMATCH: {
684
- code: "CURATED_SIGNING_KEY_MISMATCH",
685
- description: "私鑰對應的公鑰內容與 Keyring 中登錄的公鑰不符。",
686
- suggestion: "請檢查簽署金鑰與 Keyring 憑證是否匹配。",
687
- },
688
- CURATED_SIGNING_MATERIAL_MISSING: {
689
- code: "CURATED_SIGNING_MATERIAL_MISSING",
690
- description: "缺少 Curated 簽署私鑰環境變數。",
691
- suggestion: "請設定 SYNOPKGLAND_CURATED_ATTESTATION_PRIVATE_JWK 或 PRIVATE_PKCS8。",
692
- },
693
- CURATED_SIGNING_MATERIAL_AMBIGUOUS: {
694
- code: "CURATED_SIGNING_MATERIAL_AMBIGUOUS",
695
- description: "同時設定了 JWK 與 PKCS8 私鑰環境變數,來源衝突。",
696
- suggestion: "請僅保留 SYNOPKGLAND_CURATED_ATTESTATION_PRIVATE_JWK 或 PRIVATE_PKCS8 其中之一。",
697
- },
698
- CURATED_SIGNING_MATERIAL_INVALID: {
699
- code: "CURATED_SIGNING_MATERIAL_INVALID",
700
- description: "提供的簽署私鑰格式無效或無法匯入。",
701
- suggestion: "請確認私鑰為合法未加密的 RS256 RSA 私鑰。",
702
- },
703
- CURATED_RELEASE_SIGNER_MISSING: {
704
- code: "CURATED_RELEASE_SIGNER_MISSING",
705
- description: "發布流程中未提供 Attestation 簽章器。",
706
- suggestion: "請確認 CI 權限與 release custody 金鑰已正確注入。",
707
- },
708
- CURATED_RELEASE_FAILED: {
709
- code: "CURATED_RELEASE_FAILED",
710
- description: "Curated Release 發布流程失敗。",
711
- suggestion: "請檢查 release CI 日誌以定位失敗步驟。",
712
- },
713
- CURATED_APP_NOT_FOUND: {
714
- code: "CURATED_APP_NOT_FOUND",
715
- description: "在 Community Apps 目錄中找不到目標 App。",
716
- suggestion: "請確認 synopkgland-community-apps/apps/<package> 目錄存在。",
717
- },
718
- CURATED_APP_VERSION_REQUIRED: {
719
- code: "CURATED_APP_VERSION_REQUIRED",
720
- description: "發布時合約必須宣告 version 版本號。",
721
- suggestion: "請在 synology-app.yaml 設定合法的 version(例如 1.0.0)。",
722
- },
723
- CURATED_BUILD_INVALID: {
724
- code: "CURATED_BUILD_INVALID",
725
- description: "Package Build 號碼格式無效(必須為四位數字)。",
726
- suggestion: "請確保 build 號碼為四位數字字串(例如 0001)。",
727
- },
728
- CURATED_BUILD_MUST_NOT_BE_IN_SOURCE_VERSION: {
729
- code: "CURATED_BUILD_MUST_NOT_BE_IN_SOURCE_VERSION",
730
- description: "合約中的 version 不得包含 -build 後綴(Build 由 CI Ledger 分配)。",
731
- suggestion: "請將 synology-app.yaml 的 version 改為純語意化版本(例如 1.0.0,不含 -0001)。",
732
- },
733
- CURATED_PACKAGE_IDENTITY_REQUIRED: {
734
- code: "CURATED_PACKAGE_IDENTITY_REQUIRED",
735
- description: "合約中缺少 package 識別碼宣告。",
736
- suggestion: "請在 synology-app.yaml 設定 package 欄位。",
737
- },
738
- CURATED_DEVELOPMENT_IDENTITY_FORBIDDEN: {
739
- code: "CURATED_DEVELOPMENT_IDENTITY_FORBIDDEN",
740
- description: "Curated 上架發布嚴禁使用 .dev 開發後綴識別碼。",
741
- suggestion: "請移除 package 名稱末尾的 .dev 後綴。",
742
- },
743
- CURATED_PACKAGE_DIRECTORY_MISMATCH: {
744
- code: "CURATED_PACKAGE_DIRECTORY_MISMATCH",
745
- description: "Community Apps 目錄名稱與 synology-app.yaml 中的 package 名稱不一致。",
746
- suggestion: "請將 app 目錄重新命名為 apps/<package>。",
747
- },
748
- CURATED_VALIDATION_FAILED: {
749
- code: "CURATED_VALIDATION_FAILED",
750
- description: "專案未通過 Curated listing profile 嚴格驗證門檻。",
751
- suggestion: "請執行 synopkgland validate 排除錯誤後再進行 release。",
752
- },
753
- CURATED_NATIVE_MISSING: {
754
- code: "CURATED_NATIVE_MISSING",
755
- description: "原生 App 發布時找不到 native.yaml 定義檔。",
756
- suggestion: "請在專案根目錄補上 native.yaml。",
757
- },
758
- CURATED_NATIVE_TARGETS_EMPTY: {
759
- code: "CURATED_NATIVE_TARGETS_EMPTY",
760
- description: "原生 App 發布時 targets 不可為空。",
761
- suggestion: "請在 native.yaml targets 至少定義一個架構目標。",
762
- },
763
- CURATED_COMPOSE_MISSING: {
764
- code: "CURATED_COMPOSE_MISSING",
765
- description: "容器 App 發布時找不到 compose.yaml 定義檔。",
766
- suggestion: "請在專案根目錄補上 compose.yaml。",
767
- },
768
- CURATED_COMPOSE_GATE_FAILED: {
769
- code: "CURATED_COMPOSE_GATE_FAILED",
770
- description: "Compose 未通過 Curated CI 嚴格門檻(如映像檔必須帶 immutable sha256 digest)。",
771
- suggestion: "請在 compose.yaml 使用固定 digest 的公開 OCI 映像檔(image@sha256:...),並移除 build 區塊。",
772
- },
773
- CURATED_COMPOSE_BUILD_FORBIDDEN: {
774
- code: "CURATED_COMPOSE_BUILD_FORBIDDEN",
775
- description: "Curated 發布禁止使用 compose build: 區塊。",
776
- suggestion: "請移除 compose.yaml 中的 build: 區塊,並指定已發布至公開 registry 的 image。",
777
- },
778
- CURATED_COMPOSE_IMAGE_REQUIRED: {
779
- code: "CURATED_COMPOSE_IMAGE_REQUIRED",
780
- description: "Curated 服務必須宣告 image 映像檔名稱。",
781
- suggestion: "請在 compose.yaml 的 service 中宣告 image: 欄位。",
782
- },
783
- CURATED_COMPOSE_IMAGE_DIGEST_REQUIRED: {
784
- code: "CURATED_COMPOSE_IMAGE_DIGEST_REQUIRED",
785
- description: "Curated 映像檔必須使用不可變的 @sha256: 摘要鎖定。",
786
- suggestion: "請在 image 加上不可變的 SHA-256 Digest(例如 image: redis@sha256:...)。",
787
- },
788
- CURATED_COMPOSE_SERVICES_REQUIRED: {
789
- code: "CURATED_COMPOSE_SERVICES_REQUIRED",
790
- description: "compose.yaml 缺少 services 區塊或服務為空。",
791
- suggestion: "請在 compose.yaml 至少定義一個容器服務。",
792
- },
793
- CURATED_BROKER_ROUTE_FORBIDDEN: {
794
- code: "CURATED_BROKER_ROUTE_FORBIDDEN",
795
- description: "此 Compose 會落到 Broker installer 路線;rootless Broker 不支援 Container Manager,Curated listing 拒絕。",
796
- suggestion: "請改成零設定 resource-worker:使用 ./html bind 與預先 build 的 image;將 ${SYNOPKG_PKGVAR} 等平台 bind 改成 named volume,或改用 D1 dynamic route 的 string/boolean install 參數。",
797
- },
798
- CURATED_BUNDLE_FILE_MISSING: {
799
- code: "CURATED_BUNDLE_FILE_MISSING",
800
- description: "打包 Curated Release 時缺少必要的 Bundle 檔案。",
801
- suggestion: "請確認專案根目錄包含完整的 synology-app.yaml 與 compose.yaml/native.yaml。",
802
- },
803
- CURATED_ATTESTATION_BINDING_FAILED: {
804
- code: "CURATED_ATTESTATION_BINDING_FAILED",
805
- description: "Curated Attestation Token 簽署或綁定聲明失敗。",
806
- suggestion: "請檢查 signing keys 與 claims 內容。",
807
- },
808
- CURATED_ATTESTATION_SIGNATURE_INVALID: {
809
- code: "CURATED_ATTESTATION_SIGNATURE_INVALID",
810
- description: "Curated Attestation JWT 簽章無效。",
811
- suggestion: "請確認簽署私鑰與公開信任根 Keyring 一致。",
812
- },
813
- CURATED_BUILD_FAILED: {
814
- code: "CURATED_BUILD_FAILED",
815
- description: "建置 Curated SPK 失敗。",
816
- suggestion: "請檢查建置日誌以排除檔案或權限錯誤。",
817
- },
818
- CURATED_RELEASE_ATTESTATION_BINDING_FAILED: {
819
- code: "CURATED_RELEASE_ATTESTATION_BINDING_FAILED",
820
- description: "Detached Release Attestation 綁定 SPK 雜湊失敗。",
821
- suggestion: "請確保產出的 SPK 位元組雜湊與簽署聲明一致。",
822
- },
823
- CURATED_EMBEDDED_ATTESTATION_MISSING: {
824
- code: "CURATED_EMBEDDED_ATTESTATION_MISSING",
825
- description: "已建置的 Curated SPK 內缺少嵌入的 Attestation Token。",
826
- suggestion: "請檢查 build-spk 是否正確將 token 寫入 package/.synopkgland/token。",
827
- },
828
- CURATED_EMBEDDED_ATTESTATION_BINDING_FAILED: {
829
- code: "CURATED_EMBEDDED_ATTESTATION_BINDING_FAILED",
830
- description: "SPK 內嵌入的 Attestation 與 Release Claims 聲明不符。",
831
- suggestion: "請確認嵌入式 Token 的 Digest 與 Claims 一致。",
832
- },
833
- // --- Publish & Preflight ---
834
- PREFLIGHT_FAILED: {
835
- code: "PREFLIGHT_FAILED",
836
- description: "送審公開發布前置檢查未通過。",
837
- suggestion: "請先修正 preflight 列出的錯誤後再重新送審。",
838
- },
839
- COMMUNITY_APPS_ROOT_MISSING: {
840
- code: "COMMUNITY_APPS_ROOT_MISSING",
841
- description: "找不到 synopkgland-community-apps 本機副本。",
842
- suggestion: "請 clone synopkgland-community-apps 並設定 SYNOPKGLAND_COMMUNITY_APPS_ROOT 環境變數。",
843
- },
844
- PACKAGE_IDENTITY_MISSING: {
845
- code: "PACKAGE_IDENTITY_MISSING",
846
- description: "專案 synology-app.yaml 中缺少 package 欄位。",
847
- suggestion: "請在 synology-app.yaml 補上 package 宣告。",
848
- },
849
- PACKAGE_DIRECTORY_MISMATCH: {
850
- code: "PACKAGE_DIRECTORY_MISMATCH",
851
- description: "專案目錄或 Community Apps 子目錄與 package 名稱不一致。",
852
- suggestion: "請確保專案目錄名稱與 package 宣告一致。",
853
- },
854
- PUBLISH_SOURCE_IS_COMMUNITY_APP: {
855
- code: "PUBLISH_SOURCE_IS_COMMUNITY_APP",
856
- description: "publish 指令不可在 synopkgland-community-apps/apps 目錄內直接執行。",
857
- suggestion: "請在您的獨立 App 開發專案目錄中執行 public-release-submit。",
858
- },
859
- PUBLISH_PR_FAILED: {
860
- code: "PUBLISH_PR_FAILED",
861
- description: "透過 GitHub CLI 建立 Pull Request 失敗。",
862
- suggestion: "請確認 gh 已登入 (gh auth login) 或已設定 GITHUB_TOKEN。",
863
- },
2
+ "COMPOSE_ROUTE_UNSUPPORTED": {
3
+ "code": "COMPOSE_ROUTE_UNSUPPORTED",
4
+ "description": "Compose 沒有可用的 DSM resource worker 執行路徑。",
5
+ "suggestion": "使用 prebuilt image 與支援的安裝參數;移除不支援的特權、secret 或 build 設定。"
6
+ },
7
+ "LOCAL_SPK_INSTALL_FAILED": {
8
+ "code": "LOCAL_SPK_INSTALL_FAILED",
9
+ "description": "DSM 本機 SPK 安裝失敗。",
10
+ "suggestion": "查看 DSM Package Center 安裝錯誤,確認套件版本及需求。"
11
+ },
12
+ "CONTRACT_SCHEMA_UNSUPPORTED": {
13
+ "code": "CONTRACT_SCHEMA_UNSUPPORTED",
14
+ "description": "synology-app.yaml 的 schema 版本不受支援。",
15
+ "suggestion": "請將 synology-app.yaml 的 schema 欄位設為 1。"
16
+ },
17
+ "CONTRACT_MISSING_FIELD": {
18
+ "code": "CONTRACT_MISSING_FIELD",
19
+ "description": "synology-app.yaml 缺少必填欄位。",
20
+ "suggestion": "請在 synology-app.yaml 補上缺少的必填欄位(例如 package, version, displayname 等)。"
21
+ },
22
+ "CONTRACT_SCHEMA_INVALID": {
23
+ "code": "CONTRACT_SCHEMA_INVALID",
24
+ "description": "synology-app.yaml 格式與 JSON Schema 規格不符。",
25
+ "suggestion": "請修正 synology-app.yaml 的欄位格式以符合規範。"
26
+ },
27
+ "PACKAGE_IDENTITY_TOO_LONG": {
28
+ "code": "PACKAGE_IDENTITY_TOO_LONG",
29
+ "description": "Package Identity 超過長度上限(正式身分上限 28 字元,最終身分上限 32 字元)。",
30
+ "suggestion": "請縮短 synology-app.yaml 中的 package 名稱(正式身分至多 28 字元,以保留 4 字元供 .dev 開發後綴使用)。"
31
+ },
32
+ "CONTRACT_PACKAGE_TOO_LONG": {
33
+ "code": "CONTRACT_PACKAGE_TOO_LONG",
34
+ "description": "Package Identity 超過 DSM 上限 32 字元。",
35
+ "suggestion": "請縮短 synology-app.yaml 中的 package 名稱至 32 字元以內。"
36
+ },
37
+ "CONTRACT_ADMINPORT_INVALID": {
38
+ "code": "CONTRACT_ADMINPORT_INVALID",
39
+ "description": "adminport 必須是整數。",
40
+ "suggestion": "請在 synology-app.yaml 提供與 Compose published port 對應的整數 adminport。"
41
+ },
42
+ "CONTRACT_ADMINPORT_UNMAPPED": {
43
+ "code": "CONTRACT_ADMINPORT_UNMAPPED",
44
+ "description": "adminport 未在 Compose ports 宣告中對應到容器 port。",
45
+ "suggestion": "請在 compose.yaml 的 ports 區塊宣告與 adminport 對應的連接埠映射(例如 \"8080:80\")。"
46
+ },
47
+ "CONTRACT_LAUNCH_INVALID": {
48
+ "code": "CONTRACT_LAUNCH_INVALID",
49
+ "description": "integration.web.launch 模式無效。",
50
+ "suggestion": "請改為 dsm-window(DSM 視窗,預設)或 new-page(新分頁),Headless App 請省略此欄位。"
51
+ },
52
+ "CONTRACT_LAUNCH_REQUIRES_WEB": {
53
+ "code": "CONTRACT_LAUNCH_REQUIRES_WEB",
54
+ "description": "Headless App 不需要宣告 Web Launch Mode。",
55
+ "suggestion": "請省略 integration.web.launch,或補上對應 Compose published port 的 adminport。"
56
+ },
57
+ "CONTRACT_INVALID_STRING": {
58
+ "code": "CONTRACT_INVALID_STRING",
59
+ "description": "合約字串含有不允許的控制字元或未允許的插值語法。",
60
+ "suggestion": "請移除控制字元與 ${ 插值語法,安裝參數請在 install 區塊宣告。"
61
+ },
62
+ "CONTRACT_DSM_USER_DUPLICATE": {
63
+ "code": "CONTRACT_DSM_USER_DUPLICATE",
64
+ "description": "每顆 App 至多宣告一個 dsm_user 安裝參數。",
65
+ "suggestion": "請在 synology-app.yaml 只保留一個 Container Run-as 參數。"
66
+ },
67
+ "INSTALL_STRING_TOO_LONG": {
68
+ "code": "INSTALL_STRING_TOO_LONG",
69
+ "description": "Install Parameter 字串預設值超過 256 字元。",
70
+ "suggestion": "請縮短 synology-app.yaml 中 install 參數的預設字串長度。"
71
+ },
72
+ "INSTALL_STRING_INVALID": {
73
+ "code": "INSTALL_STRING_INVALID",
74
+ "description": "Install Parameter 字串值含有不合法字元或插值。",
75
+ "suggestion": "請移除 install 參數預設值中的控制字元與 ${ 插值語法。"
76
+ },
77
+ "CONTRACT_SECRET_UNSUPPORTED": {
78
+ "code": "CONTRACT_SECRET_UNSUPPORTED",
79
+ "description": "install.<NAME>.type: secret 目前沒有可用的安裝路徑。2026-08-27 於 vt-nas 實測:無論是否在 Compose 引用,Package Center 安裝都以 DSM broken/150 結束且不建立 Container Manager project(同一台 NAS 上無參數的對照套件正常安裝)。",
80
+ "suggestion": "請改用 type: string(非敏感值),或把敏感值改成 App 啟動後自行取得/由管理員放進 ${SYNO_APP_SECRETS_DIR} 的檔案。secret 型別要能用,需要先讓 DSM worker 的失敗原因可觀測(見 STATUS.md A22/A45)。"
81
+ },
82
+ "CONTRACT_HOMES_UNSUPPORTED": {
83
+ "code": "CONTRACT_HOMES_UNSUPPORTED",
84
+ "description": "install.<NAME>.type: homes 目前沒有可用的安裝路徑。2026-08-27 於 vt-nas 實測:wizard 不產生輸入控制項,Package Center 安裝以 DSM broken/150 結束;CLI deploy 能解析出 /volume1/homes,但 DSM 於 compound install 回 4540 拒絕。",
85
+ "suggestion": "若 App 需要一個由管理員選定的資料夾,請改用 type: shared_folder。homes 型別要能用,需要補齊 wizard 控制項與 preinst materialization(見 STATUS.md A46)。"
86
+ },
87
+ "INSTALL_PARAMETER_UNREFERENCED": {
88
+ "code": "INSTALL_PARAMETER_UNREFERENCED",
89
+ "description": "install 宣告的參數未在 Compose 中被引用。",
90
+ "suggestion": "請在 compose.yaml 以 ${參數名稱} 引用該參數,或從 synology-app.yaml 移除未使用的宣告。"
91
+ },
92
+ "CONTRACT_HOMES_PATH_FORBIDDEN": {
93
+ "code": "CONTRACT_HOMES_PATH_FORBIDDEN",
94
+ "description": "homes Install Parameter 不得在契約中寫入 NAS 實體路徑或預設值。",
95
+ "suggestion": "請只宣告 type: homes 並在 Compose 引用該參數,由套件 在安裝時解析這台 NAS 的 User Home 路徑。"
96
+ },
97
+ "CONTRACT_POSIX_ALL_SHARES_VALUE_FORBIDDEN": {
98
+ "code": "CONTRACT_POSIX_ALL_SHARES_VALUE_FORBIDDEN",
99
+ "description": "POSIX all-shares 參數不得在契約中指定 default 或 NAS 實體路徑。",
100
+ "suggestion": "請只宣告 type: posix_all_shares,讓 wizard/CLI 在安裝時取得當下的 Share snapshot。"
101
+ },
102
+ "CONTRACT_POSIX_ALL_SHARES_LISTING_UNSUPPORTED": {
103
+ "code": "CONTRACT_POSIX_ALL_SHARES_LISTING_UNSUPPORTED",
104
+ "description": "posix_all_shares 需要 CLI 在安裝時以管理員 session 取得這台 NAS 的 Share 清單快照;Package Center 與 Package Source listing 無法履行此合約。",
105
+ "suggestion": "請使用 synopkgland deploy --host <name>,由管理員 session 在安裝時取得 Share 清單快照;此型別不能透過 Package Center 或 Package Source listing 上架。"
106
+ },
107
+ "DSM_USER_REQUIRED": {
108
+ "code": "DSM_USER_REQUIRED",
109
+ "description": "有 Shared Folder 時必須宣告恰好一個 dsm_user 作為 Container Run-as。",
110
+ "suggestion": "請在 synology-app.yaml 新增 install.<NAME>.type: dsm_user,並在 Compose 引用 ${NAME_UID}:${NAME_GID}。"
111
+ },
112
+ "PROJECT_RUNTIME_EXCLUSIVE": {
113
+ "code": "PROJECT_RUNTIME_EXCLUSIVE",
114
+ "description": "專案同時存在 compose.yaml 與 native.yaml,兩者互斥。",
115
+ "suggestion": "請選擇使用 compose.yaml(容器 App)或 native.yaml(原生 App),並刪除另一個檔案。"
116
+ },
117
+ "COMPOSE_MISSING": {
118
+ "code": "COMPOSE_MISSING",
119
+ "description": "找不到 compose.yaml 或 native.yaml。",
120
+ "suggestion": "請在專案根目錄建立 compose.yaml 或 native.yaml。"
121
+ },
122
+ "COMPOSE_SERVICE_NOT_FOUND": {
123
+ "code": "COMPOSE_SERVICE_NOT_FOUND",
124
+ "description": "depends_on 引用的服務不存在於 compose.yaml 中。",
125
+ "suggestion": "請修正 compose.yaml 中的 depends_on,指向正確已定義的 service 名稱。"
126
+ },
127
+ "COMPOSE_NUMERIC_COMMAND_ARG_FORBIDDEN": {
128
+ "code": "COMPOSE_NUMERIC_COMMAND_ARG_FORBIDDEN",
129
+ "description": "會走 DSM Docker Project resource worker 的 Compose command/entrypoint 陣列含純數字字串,可能在 worker YAML round-trip 後變成整數而無法 acquire。",
130
+ "suggestion": "請把整個命令包成單一字串,例如 command: [\"sh\", \"-c\", \"httpd -f -p 8080 -h /srv\"],或與 flag 併寫成 \"-p8080\"。"
131
+ },
132
+ "COMPOSE_DYNAMIC_ROUTE_UNSUPPORTED": {
133
+ "code": "COMPOSE_DYNAMIC_ROUTE_UNSUPPORTED",
134
+ "description": "Compose dynamic route 超出 D1/D2 白名單,或使用 DSM worker 不會載入的 secret/config 來源。",
135
+ "suggestion": "請只使用 string/boolean wizard answer 的 ${NAME} interpolation;secret/config 因 DSM worker 不讀 docker-compose.override.yml 而拒收。"
136
+ },
137
+ "COMPOSE_BUILD_FORBIDDEN": {
138
+ "code": "COMPOSE_BUILD_FORBIDDEN",
139
+ "description": "D0 Compose route 禁止在 NAS install-time 使用 build:;build capability 永久拒收。",
140
+ "suggestion": "請移除 build:,改用已存在的 image(最好使用 image@sha256:... 固定 digest),再重新執行 validate。"
141
+ },
142
+ "COMPOSE_SOCKET_MOUNT_FORBIDDEN": {
143
+ "code": "COMPOSE_SOCKET_MOUNT_FORBIDDEN",
144
+ "description": "嚴禁掛載 Docker Socket 或系統敏感 Socket。",
145
+ "suggestion": "請從 compose.yaml 移除 docker.sock 掛載;如需存取檔案請改用 shared_folder 或 App 自己的檔案 API。"
146
+ },
147
+ "COMPOSE_BIND_SOURCE_FORBIDDEN": {
148
+ "code": "COMPOSE_BIND_SOURCE_FORBIDDEN",
149
+ "description": "掛載來源路徑不合法或屬於受保護的系統路徑。",
150
+ "suggestion": "請使用受控的 ${SYNOPKG_PKGVAR}、${SYNO_APP_SECRETS_DIR} 或已宣告的 ${SHARED_FOLDER} 槽位。"
151
+ },
152
+ "COMPOSE_BIND_SOURCE_UNDECLARED": {
153
+ "code": "COMPOSE_BIND_SOURCE_UNDECLARED",
154
+ "description": "Volume 掛載使用了未宣告的 Shared Folder 變數。",
155
+ "suggestion": "請先在 synology-app.yaml 的 install 區塊宣告該 shared_folder 參數。"
156
+ },
157
+ "COMPOSE_BIND_SUFFIX_INVALID": {
158
+ "code": "COMPOSE_BIND_SUFFIX_INVALID",
159
+ "description": "Shared Folder 子路徑格式不合法(含有 .. 或控制字元)。",
160
+ "suggestion": "請改用合法的相對子路徑,例如 ${MEDIA_SHARE}/data:/data。"
161
+ },
162
+ "COMPOSE_POSIX_ALL_SHARES_UNDECLARED": {
163
+ "code": "COMPOSE_POSIX_ALL_SHARES_UNDECLARED",
164
+ "description": "Compose 使用了未宣告的 POSIX all-shares marker。",
165
+ "suggestion": "請宣告 type: posix_all_shares,讓 package-only wizard/CLI 取得安裝當下的 Share snapshot。"
166
+ },
167
+ "COMPOSE_POSIX_ALL_SHARES_SUFFIX_FORBIDDEN": {
168
+ "code": "COMPOSE_POSIX_ALL_SHARES_SUFFIX_FORBIDDEN",
169
+ "description": "POSIX all-shares marker 不得附加 Share 子路徑。",
170
+ "suggestion": "請只使用完整的 ${ALL_SHARES} source;每個 Share 的 container target 由 package-only preinst 展開。"
171
+ },
172
+ "COMPOSE_HOST_BIND_FORBIDDEN": {
173
+ "code": "COMPOSE_HOST_BIND_FORBIDDEN",
174
+ "description": "禁止直接硬編碼本機路徑(例如 /volume1/... 或 ./)。",
175
+ "suggestion": "請在 synology-app.yaml 宣告 shared_folder 參數,並在 Compose 改用 ${SLOT} 引用。"
176
+ },
177
+ "COMPOSE_NAMED_VOLUME_UNDECLARED": {
178
+ "code": "COMPOSE_NAMED_VOLUME_UNDECLARED",
179
+ "description": "服務使用了未在頂層 volumes 宣告的 Named Volume。",
180
+ "suggestion": "請在 compose.yaml 頂層 volumes 區塊補上該 Volume 宣告,或改用受控目錄。"
181
+ },
182
+ "COMPOSE_USER_ROOT_FORBIDDEN": {
183
+ "code": "COMPOSE_USER_ROOT_FORBIDDEN",
184
+ "description": "容器以 root (0:0) 執行,違反最小權限原則。",
185
+ "suggestion": "請在 synology-app.yaml 宣告 dsm_user 並在 Compose 使用 ${USER_UID}:${USER_GID}。"
186
+ },
187
+ "COMPOSE_USER_CONFLICTS_DSM_USER": {
188
+ "code": "COMPOSE_USER_CONFLICTS_DSM_USER",
189
+ "description": "Compose 服務自定義了 user 欄位,與 contract 宣告的 dsm_user 衝突。",
190
+ "suggestion": "請移除 Compose 中的 user 欄位,交由 dsm_user 自動注入 ${NAME_UID}:${NAME_GID} 與 group_add。"
191
+ },
192
+ "COMPOSE_USER_NUMERIC_FORBIDDEN": {
193
+ "code": "COMPOSE_USER_NUMERIC_FORBIDDEN",
194
+ "description": "禁止在 compose.yaml 硬編碼數字 uid:gid。",
195
+ "suggestion": "請在 synology-app.yaml 宣告 dsm_user,並在 Compose 引用 ${NAME_UID}:${NAME_GID}。"
196
+ },
197
+ "COMPOSE_PRIVILEGED_FORBIDDEN": {
198
+ "code": "COMPOSE_PRIVILEGED_FORBIDDEN",
199
+ "description": "使用了 privileged: true 但未在合約宣告。",
200
+ "suggestion": "請在 synology-app.yaml 加上 privilege.privileged: true,或移除 privileged: true。"
201
+ },
202
+ "COMPOSE_HOST_NETWORK_FORBIDDEN": {
203
+ "code": "COMPOSE_HOST_NETWORK_FORBIDDEN",
204
+ "description": "使用了 host network 模式但未在合約宣告。",
205
+ "suggestion": "請在 synology-app.yaml 加上 privilege.host_network: true,或改用受控網路模式。"
206
+ },
207
+ "COMPOSE_HOST_PID_FORBIDDEN": {
208
+ "code": "COMPOSE_HOST_PID_FORBIDDEN",
209
+ "description": "使用了 pid: host 但未在合約宣告。",
210
+ "suggestion": "請在 synology-app.yaml 加上 privilege.host_pid: true,或移除 pid: host。"
211
+ },
212
+ "COMPOSE_HOST_IPC_FORBIDDEN": {
213
+ "code": "COMPOSE_HOST_IPC_FORBIDDEN",
214
+ "description": "使用了 ipc: host 但未在合約宣告。",
215
+ "suggestion": "請在 synology-app.yaml 加上 privilege.host_ipc: true,或移除 ipc: host。"
216
+ },
217
+ "COMPOSE_DEVICES_FORBIDDEN": {
218
+ "code": "COMPOSE_DEVICES_FORBIDDEN",
219
+ "description": "使用了 devices 裝置存取但未在合約宣告。",
220
+ "suggestion": "請在 synology-app.yaml 加上 privilege.devices: true,或移除 devices 區塊。"
221
+ },
222
+ "COMPOSE_CAP_ADD_FORBIDDEN": {
223
+ "code": "COMPOSE_CAP_ADD_FORBIDDEN",
224
+ "description": "使用了 cap_add 權限提升但未在合約宣告。",
225
+ "suggestion": "請在 synology-app.yaml 加上 privilege.cap_add: true,或移除 cap_add 區塊。"
226
+ },
227
+ "COMPOSE_ENV_MISSING": {
228
+ "code": "COMPOSE_ENV_MISSING",
229
+ "description": "專案缺少必要的環境變數目錄結構。",
230
+ "suggestion": "請確認 SYNOPKG_PKGVAR 與 secrets 目錄已正確建立。"
231
+ },
232
+ "COMPOSE_NOT_HEALTHY": {
233
+ "code": "COMPOSE_NOT_HEALTHY",
234
+ "description": "Compose 服務未能於時限內通過 healthcheck 達到 healthy 狀態。",
235
+ "suggestion": "請檢查容器健康檢查設定與應用程式日誌:synopkgland log --host <nas>。"
236
+ },
237
+ "COMPOSE_NOT_RUNNING": {
238
+ "code": "COMPOSE_NOT_RUNNING",
239
+ "description": "Compose 服務未能於時限內維持 running 狀態。",
240
+ "suggestion": "請檢查容器啟動腳本與日誌以排除崩潰原因:synopkgland log --host <nas>。"
241
+ },
242
+ "NATIVE_LOAD_FAILED": {
243
+ "code": "NATIVE_LOAD_FAILED",
244
+ "description": "無法讀取或解析 native.yaml。",
245
+ "suggestion": "請確認 native.yaml 存在且為合法 YAML 格式。"
246
+ },
247
+ "NATIVE_SCHEMA_INVALID": {
248
+ "code": "NATIVE_SCHEMA_INVALID",
249
+ "description": "native.yaml schema 版本無效(必須為整數 1)。",
250
+ "suggestion": "請在 native.yaml 設定 schema: 1。"
251
+ },
252
+ "NATIVE_TARGETS_REQUIRED": {
253
+ "code": "NATIVE_TARGETS_REQUIRED",
254
+ "description": "native.yaml 缺少 targets 區塊。",
255
+ "suggestion": "請在 native.yaml 宣告 targets 區塊並指定 x86_64 或 aarch64 目標。"
256
+ },
257
+ "NATIVE_TARGETS_EMPTY": {
258
+ "code": "NATIVE_TARGETS_EMPTY",
259
+ "description": "native.yaml 中的 targets 區塊不可為空。",
260
+ "suggestion": "請在 native.yaml 的 targets 內至少定義一個架構目標(x86_64 或 aarch64)。"
261
+ },
262
+ "NATIVE_ARCH_UNKNOWN": {
263
+ "code": "NATIVE_ARCH_UNKNOWN",
264
+ "description": "native.yaml 定義了不受支援的架構目標名稱。",
265
+ "suggestion": "目標架構名稱僅支援 x86_64 與 aarch64。"
266
+ },
267
+ "NATIVE_TARGET_INVALID": {
268
+ "code": "NATIVE_TARGET_INVALID",
269
+ "description": "native.yaml 目標架構定義無效。",
270
+ "suggestion": "每個目標架構必須包含 path 或 url 下載來源設定。"
271
+ },
272
+ "NATIVE_TARGET_NOT_DECLARED": {
273
+ "code": "NATIVE_TARGET_NOT_DECLARED",
274
+ "description": "欲建置或部署的架構目標未在 native.yaml 中宣告。",
275
+ "suggestion": "請在 native.yaml 的 targets 補上該架構目標,或透過 --arch 指定已宣告的目標。"
276
+ },
277
+ "NATIVE_TARGET_SOURCE_EXCLUSIVE": {
278
+ "code": "NATIVE_TARGET_SOURCE_EXCLUSIVE",
279
+ "description": "目標架構不可同時包含 path 與 url,兩者互斥。",
280
+ "suggestion": "請在該目標架構中只保留 path(本機)或 url(遠端二進位檔)。"
281
+ },
282
+ "NATIVE_PATH_FORBIDDEN_IN_LISTING": {
283
+ "code": "NATIVE_PATH_FORBIDDEN_IN_LISTING",
284
+ "description": "公開上架審查禁止使用本機 path 來源的 native 目標。",
285
+ "suggestion": "請將 target 改為公開可下載的 url 並附帶 sha256 校驗碼。"
286
+ },
287
+ "NATIVE_SHA256_REQUIRED_IN_LISTING": {
288
+ "code": "NATIVE_SHA256_REQUIRED_IN_LISTING",
289
+ "description": "公開上架審查要求 url 目標必須提供 sha256 校驗碼。",
290
+ "suggestion": "請在 native.yaml 的 url 目標補上 64 位十六進位 sha256 欄位。"
291
+ },
292
+ "NATIVE_SHA256_INVALID": {
293
+ "code": "NATIVE_SHA256_INVALID",
294
+ "description": "sha256 校驗碼格式無效。",
295
+ "suggestion": "請提供恰好 64 字元的十六進位 SHA-256 字串。"
296
+ },
297
+ "NATIVE_STRIP_COMPONENTS_INVALID": {
298
+ "code": "NATIVE_STRIP_COMPONENTS_INVALID",
299
+ "description": "strip_components 必須是非負整數。",
300
+ "suggestion": "請在 native.yaml 將 strip_components 設為大於等於 0 的整數。"
301
+ },
302
+ "NATIVE_SERVICE_REQUIRED": {
303
+ "code": "NATIVE_SERVICE_REQUIRED",
304
+ "description": "native.yaml 缺少 service 區塊。",
305
+ "suggestion": "請在 native.yaml 補上 service 區塊並宣告 exec 與 args/env。"
306
+ },
307
+ "NATIVE_SERVICE_USER_FORBIDDEN": {
308
+ "code": "NATIVE_SERVICE_USER_FORBIDDEN",
309
+ "description": "native service 不允許自訂 user 欄位(固定以 package 使用者執行)。",
310
+ "suggestion": "請從 native.yaml 的 service 區塊移除 user 欄位。"
311
+ },
312
+ "NATIVE_SERVICE_SHELL_FIELD_FORBIDDEN": {
313
+ "code": "NATIVE_SERVICE_SHELL_FIELD_FORBIDDEN",
314
+ "description": "禁止在 native service 使用 command/shell 等字串欄位以免 shell injection。",
315
+ "suggestion": "請改用 exec(路徑)與 args(字串陣列)方式宣告啟動指令。"
316
+ },
317
+ "NATIVE_EXEC_REQUIRED": {
318
+ "code": "NATIVE_EXEC_REQUIRED",
319
+ "description": "native service 缺少 exec 執行檔路徑。",
320
+ "suggestion": "請在 native.yaml 的 service 區塊指定 exec: <相對路徑>。"
321
+ },
322
+ "NATIVE_EXEC_INVALID_PATH": {
323
+ "code": "NATIVE_EXEC_INVALID_PATH",
324
+ "description": "exec 必須是相對路徑,且不可包含 .. 或絕對路徑。",
325
+ "suggestion": "請指定相對於安裝根目錄的合法相對路徑,例如 exec: bin/app。"
326
+ },
327
+ "NATIVE_ARGS_INVALID": {
328
+ "code": "NATIVE_ARGS_INVALID",
329
+ "description": "service.args 必須是字串陣列。",
330
+ "suggestion": "請在 native.yaml 將 args 宣告為字串列表格式(例如 args: [\"--port\", \"8080\"])。"
331
+ },
332
+ "NATIVE_ENV_INVALID": {
333
+ "code": "NATIVE_ENV_INVALID",
334
+ "description": "service.env 必須是 key-value 字串映射表。",
335
+ "suggestion": "請將 env 宣告為字典物件且每個值皆為字串。"
336
+ },
337
+ "NATIVE_PKGVAR_REQUIRED": {
338
+ "code": "NATIVE_PKGVAR_REQUIRED",
339
+ "description": "原生二進位 App 必須在 args 或 env 中引用 ${SYNOPKG_PKGVAR} 以指定資料路徑。",
340
+ "suggestion": "請在 native.yaml 的 service.args 或 service.env 加入 ${SYNOPKG_PKGVAR} 參數。"
341
+ },
342
+ "NATIVE_ARCH_FAMILY_REQUIRED": {
343
+ "code": "NATIVE_ARCH_FAMILY_REQUIRED",
344
+ "description": "建置原生 SPK 時缺少目標架構家族(x86_64 或 aarch64)。",
345
+ "suggestion": "請在指令加上 --arch x86_64 或 --arch aarch64。"
346
+ },
347
+ "NATIVE_ARCH_UNDETERMINED": {
348
+ "code": "NATIVE_ARCH_UNDETERMINED",
349
+ "description": "無法從目標 NAS 的 CPU 資訊自動判定架構家族。",
350
+ "suggestion": "請使用 --arch x86_64 或 --arch aarch64 明確指定目標架構。"
351
+ },
352
+ "NATIVE_PAYLOAD_BUNDLE_COLLISION": {
353
+ "code": "NATIVE_PAYLOAD_BUNDLE_COLLISION",
354
+ "description": "原生 payload 解壓縮內容與 App Bundle 核心保留檔衝突。",
355
+ "suggestion": "請檢查 payload 內容,避免在根目錄覆蓋 synology-app.yaml 或 native.yaml。"
356
+ },
357
+ "NATIVE_PAYLOAD_DOWNLOAD_FAILED": {
358
+ "code": "NATIVE_PAYLOAD_DOWNLOAD_FAILED",
359
+ "description": "下載原生二進位檔 payload 失敗。",
360
+ "suggestion": "請檢查 native.yaml 中的 url 是否有效且網路連線正常。"
361
+ },
362
+ "NATIVE_PAYLOAD_DOWNLOAD_INVALID": {
363
+ "code": "NATIVE_PAYLOAD_DOWNLOAD_INVALID",
364
+ "description": "下載的原生 payload 回傳內容無效。",
365
+ "suggestion": "請確認目標 URL 回傳了有效的二進位檔案內容。"
366
+ },
367
+ "NATIVE_PAYLOAD_DUPLICATE_ENTRY": {
368
+ "code": "NATIVE_PAYLOAD_DUPLICATE_ENTRY",
369
+ "description": "原生 payload 壓縮檔內包含重複的檔案路徑。",
370
+ "suggestion": "請重新打包原始檔案,確保壓縮檔內無重複 entry。"
371
+ },
372
+ "NATIVE_PAYLOAD_ERROR": {
373
+ "code": "NATIVE_PAYLOAD_ERROR",
374
+ "description": "處理原生二進位 payload 時發生未預期錯誤。",
375
+ "suggestion": "請檢查 payload 壓縮檔完整性或重新建置 SPK。"
376
+ },
377
+ "NATIVE_PAYLOAD_EXTRACTION_FAILED": {
378
+ "code": "NATIVE_PAYLOAD_EXTRACTION_FAILED",
379
+ "description": "解壓縮原生二進位 payload 失敗。",
380
+ "suggestion": "請確認壓縮檔格式正確無損壞,且支援 tar.gz / tar.xz / zip。"
381
+ },
382
+ "NATIVE_PAYLOAD_INVALID_HARDLINK": {
383
+ "code": "NATIVE_PAYLOAD_INVALID_HARDLINK",
384
+ "description": "原生 payload 含有無效或循環的 hardlink。",
385
+ "suggestion": "請移除壓縮檔中不合法的 hardlink 後重新打包。"
386
+ },
387
+ "NATIVE_PAYLOAD_INVALID_STRIP_COMPONENTS": {
388
+ "code": "NATIVE_PAYLOAD_INVALID_STRIP_COMPONENTS",
389
+ "description": "strip_components 設定超過了壓縮檔目錄層級深度。",
390
+ "suggestion": "請在 native.yaml 調整或減少 strip_components 數值。"
391
+ },
392
+ "NATIVE_PAYLOAD_INVALID_SYMLINK": {
393
+ "code": "NATIVE_PAYLOAD_INVALID_SYMLINK",
394
+ "description": "原生 payload 含有無效的符號連結。",
395
+ "suggestion": "請檢查壓縮檔內的 symlink 目標是否存在且合法。"
396
+ },
397
+ "NATIVE_PAYLOAD_INVALID_ZIP": {
398
+ "code": "NATIVE_PAYLOAD_INVALID_ZIP",
399
+ "description": "ZIP 壓縮檔格式無效或已損壞。",
400
+ "suggestion": "請檢查 zip 檔案完整性或重新打包。"
401
+ },
402
+ "NATIVE_PAYLOAD_SHA256_MISMATCH": {
403
+ "code": "NATIVE_PAYLOAD_SHA256_MISMATCH",
404
+ "description": "下載的 payload SHA-256 校驗碼與 native.yaml 宣告不符。",
405
+ "suggestion": "請更新 native.yaml 中的 sha256 欄位以符合實際檔案雜湊。"
406
+ },
407
+ "NATIVE_PAYLOAD_SOURCE_AMBIGUOUS": {
408
+ "code": "NATIVE_PAYLOAD_SOURCE_AMBIGUOUS",
409
+ "description": "目標架構同時宣告了 path 與 url,來源衝突。",
410
+ "suggestion": "請在該目標架構中只保留 path 或 url 其中一種來源。"
411
+ },
412
+ "NATIVE_PAYLOAD_SOURCE_REQUIRED": {
413
+ "code": "NATIVE_PAYLOAD_SOURCE_REQUIRED",
414
+ "description": "目標架構缺少 path 或 url 來源設定。",
415
+ "suggestion": "請在 native.yaml 的 targets 內為各架構補上 path 或 url。"
416
+ },
417
+ "NATIVE_PAYLOAD_SYMLINK_CYCLE": {
418
+ "code": "NATIVE_PAYLOAD_SYMLINK_CYCLE",
419
+ "description": "原生 payload 包含循環符號連結 (Symlink cycle)。",
420
+ "suggestion": "請移除壓縮檔中的循環 symlink。"
421
+ },
422
+ "NATIVE_PAYLOAD_UNSAFE_HARDLINK": {
423
+ "code": "NATIVE_PAYLOAD_UNSAFE_HARDLINK",
424
+ "description": "原生 payload hardlink 試圖連結至目標目錄外。",
425
+ "suggestion": "請確保 hardlink 僅指向 payload 目錄內部的有效檔案。"
426
+ },
427
+ "NATIVE_PAYLOAD_UNSAFE_PATH": {
428
+ "code": "NATIVE_PAYLOAD_UNSAFE_PATH",
429
+ "description": "原生 payload 含有路徑穿越 (Path traversal) 等不安全路徑。",
430
+ "suggestion": "請確保壓縮檔內無包含 .. 或絕對路徑的檔案名稱。"
431
+ },
432
+ "NATIVE_PAYLOAD_UNSAFE_SYMLINK": {
433
+ "code": "NATIVE_PAYLOAD_UNSAFE_SYMLINK",
434
+ "description": "原生 payload symlink 指向了安裝目錄之外。",
435
+ "suggestion": "請確保 symlink 僅指向 payload 目錄內部的相對目標。"
436
+ },
437
+ "NATIVE_PAYLOAD_UNSUPPORTED_ENTRY": {
438
+ "code": "NATIVE_PAYLOAD_UNSUPPORTED_ENTRY",
439
+ "description": "原生 payload 包含不支援的特殊檔案類型(如 device node 或 fifo)。",
440
+ "suggestion": "請從壓縮檔中移除特殊檔案,僅保留一般檔案、目錄與合法 symlink。"
441
+ },
442
+ "NATIVE_PAYLOAD_UNSUPPORTED_ZIP": {
443
+ "code": "NATIVE_PAYLOAD_UNSUPPORTED_ZIP",
444
+ "description": "不支援的 ZIP 特性(例如 ZIP64、多卷分割或密碼加密)。",
445
+ "suggestion": "請使用標準未加密的 ZIP 或改用 tar.gz 打包。"
446
+ },
447
+ "NATIVE_PAYLOAD_XZ_FAILED": {
448
+ "code": "NATIVE_PAYLOAD_XZ_FAILED",
449
+ "description": "解壓縮 tar.xz 失敗。",
450
+ "suggestion": "請確認本機已安裝 xz 工具且檔案未損壞。"
451
+ },
452
+ "NATIVE_PAYLOAD_XZ_UNAVAILABLE": {
453
+ "code": "NATIVE_PAYLOAD_XZ_UNAVAILABLE",
454
+ "description": "系統中找不到 xz 指令可用於解壓縮 .tar.xz 檔案。",
455
+ "suggestion": "請在作業系統中安裝 xz-utils 或改用 tar.gz 格式打包。"
456
+ },
457
+ "BUILD_SPK_FAILED": {
458
+ "code": "BUILD_SPK_FAILED",
459
+ "description": "SPK 打包流程失敗。",
460
+ "suggestion": "請檢查 validate 錯誤與目錄檔案權限後重試。"
461
+ },
462
+ "VALIDATION_FAILED": {
463
+ "code": "VALIDATION_FAILED",
464
+ "description": "專案未通過契約或安全驗證,終止部署。",
465
+ "suggestion": "請先執行 synopkgland validate 排除合約與 Compose 錯誤。"
466
+ },
467
+ "DEPLOY_FAILED": {
468
+ "code": "DEPLOY_FAILED",
469
+ "description": "部署至 NAS 時發生未分類錯誤。",
470
+ "suggestion": "請檢查 NAS 網路連線與日誌:synopkgland log --host <nas>。"
471
+ },
472
+ "SHARE_VALUE_REQUIRED": {
473
+ "code": "SHARE_VALUE_REQUIRED",
474
+ "description": "部署時缺少合約中宣告的 shared_folder 實際路徑映射。",
475
+ "suggestion": "請使用 --share <SLOT>=<邏輯名> 提供對應的 Shared Folder 名稱。"
476
+ },
477
+ "SHARE_LOGICAL_NAME_REQUIRED": {
478
+ "code": "SHARE_LOGICAL_NAME_REQUIRED",
479
+ "description": "Share 參數必須提供邏輯名稱,禁止使用 /volume1/... 等實體路徑。",
480
+ "suggestion": "請指定 DSM 控制台中的 Shared Folder 邏輯名稱,例如 --share MEDIA_SHARE=photos。"
481
+ },
482
+ "SHARE_NOT_FOUND": {
483
+ "code": "SHARE_NOT_FOUND",
484
+ "description": "在目標 NAS 上找不到指定的 Shared Folder。",
485
+ "suggestion": "請在 DSM 控制台建立該 Shared Folder,或檢查名稱拼字。"
486
+ },
487
+ "HOMES_NOT_ENABLED": {
488
+ "code": "HOMES_NOT_ENABLED",
489
+ "description": "目標 NAS 未啟用 User Home,或無法解析 homes 的實體 bind source。",
490
+ "suggestion": "請在這台 NAS 啟用 DSM User Home,並確認 DSM API 能回傳解析後的路徑,再重新部署。"
491
+ },
492
+ "DSM_USER_LOGICAL_NAME_REQUIRED": {
493
+ "code": "DSM_USER_LOGICAL_NAME_REQUIRED",
494
+ "description": "dsm_user 參數必須提供 DSM 使用者邏輯名稱,禁止使用數字 UID。",
495
+ "suggestion": "請在 --run-as 指定 DSM 使用者帳號名稱(例如 --run-as RUN_AS=alice)。"
496
+ },
497
+ "SHARE_RUN_AS_NO_ACCESS": {
498
+ "code": "SHARE_RUN_AS_NO_ACCESS",
499
+ "description": "deploy 的安裝前檢查發現選定的 Container Run-as 使用者對選定的 Shared Folder 沒有權限(或被明確拒絕)。容器會以該使用者掛載該 Share,安裝會成功但 runtime 讀寫會拿到 Permission denied。",
500
+ "suggestion": "請在 DSM 控制台把該 Shared Folder 的權限授予該使用者(或其群組),或改選別的使用者/Share,再重新部署。此檢查只在 deploy 進行;Package Center 安裝精靈不經過這裡,ACL 仍是管理員的前提責任。"
501
+ },
502
+ "PORT_ALREADY_IN_USE": {
503
+ "code": "PORT_ALREADY_IN_USE",
504
+ "description": "deploy 的安裝前檢查發現 Compose published TCP port 已被其他服務或容器佔用。",
505
+ "suggestion": "請更換 synology-app.yaml/compose.yaml 的 published host port;同一 Package Identity 的既有容器會在升級或重裝時放行。"
506
+ },
507
+ "CATALOG_INSTALL_FAILED": {
508
+ "code": "CATALOG_INSTALL_FAILED",
509
+ "description": "NAS Package Center 安裝套件失敗。",
510
+ "suggestion": "請至 DSM Package Center 檢查安裝日誌或手動嘗試安裝。"
511
+ },
512
+ "DEPLOY_PARAM_UNDECLARED": {
513
+ "code": "DEPLOY_PARAM_UNDECLARED",
514
+ "description": "deploy --param 提供了契約未宣告的 Install Parameter。",
515
+ "suggestion": "請只傳 synology-app.yaml install 中宣告的 string 或 boolean 名稱。"
516
+ },
517
+ "DEPLOY_PARAM_TYPE_INVALID": {
518
+ "code": "DEPLOY_PARAM_TYPE_INVALID",
519
+ "description": "deploy --param 的值不符合契約宣告的 string 或 boolean 型別。",
520
+ "suggestion": "string 請傳非空字串;boolean 請只傳 true 或 false。"
521
+ },
522
+ "DEPLOY_POSIX_ALL_SHARES_LOOKUP_FAILED": {
523
+ "code": "DEPLOY_POSIX_ALL_SHARES_LOOKUP_FAILED",
524
+ "description": "無法以管理員 session 列出部署當下的 Shared Folder 清單。",
525
+ "suggestion": "請確認 DSM 管理員 session 可呼叫 SYNO.Core.Share list,或用 --param NAME=... 明確提供清單。"
526
+ },
527
+ "DSM_DEPENDENCY_CONFLICT": {
528
+ "code": "DSM_DEPENDENCY_CONFLICT",
529
+ "description": "DSM 複合安裝請求因執行中的依賴套件而拒絕。",
530
+ "suggestion": "請先停止列出的依賴套件再重試升級。"
531
+ },
532
+ "DSM_COMPOUND_FAILED": {
533
+ "code": "DSM_COMPOUND_FAILED",
534
+ "description": "DSM 複合安裝請求的子步驟失敗。",
535
+ "suggestion": "請檢查回應中的 api、method、errorCode 與 DSM Package Center 日誌後重試。"
536
+ },
537
+ "DSM_REQUEST_FAILED": {
538
+ "code": "DSM_REQUEST_FAILED",
539
+ "description": "DSM SYNO.Entry.Request 複合請求失敗。",
540
+ "suggestion": "請檢查 DSM session、請求參數與 Package Center 日誌後重試。"
541
+ },
542
+ "NOT_INSTALLED": {
543
+ "code": "NOT_INSTALLED",
544
+ "description": "套件尚未在目標 NAS 上安裝部署。",
545
+ "suggestion": "請先執行 synopkgland deploy --host <nas> 安裝套件。"
546
+ },
547
+ "STANDALONE_MANIFEST_MISSING": {
548
+ "code": "STANDALONE_MANIFEST_MISSING",
549
+ "description": "找不到 dsm-package.yaml。",
550
+ "suggestion": "請在專案根目錄執行,或以 synopkgland init -t native-go 建立專案。"
551
+ },
552
+ "STANDALONE_MANIFEST_YAML": {
553
+ "code": "STANDALONE_MANIFEST_YAML",
554
+ "description": "dsm-package.yaml 不是合法的 YAML 物件。",
555
+ "suggestion": "請修正 dsm-package.yaml 的 YAML 語法。"
556
+ },
557
+ "STANDALONE_FIELD_UNKNOWN": {
558
+ "code": "STANDALONE_FIELD_UNKNOWN",
559
+ "description": "dsm-package.yaml 含有不支援的欄位。",
560
+ "suggestion": "請移除該欄位;Standalone Package 不接受自訂 lifecycle scripts 或 DSM conf。"
561
+ },
562
+ "STANDALONE_SCHEMA_INVALID": {
563
+ "code": "STANDALONE_SCHEMA_INVALID",
564
+ "description": "dsm-package.yaml 的 schema 版本不受支援。",
565
+ "suggestion": "請將 schema 設為 1。"
566
+ },
567
+ "STANDALONE_PRIVILEGE_UNSUPPORTED": {
568
+ "code": "STANDALONE_PRIVILEGE_UNSUPPORTED",
569
+ "description": "privilege 只能是 none(只以 package 帳號執行)或 root(另加管理員核准的 root 操作)。",
570
+ "suggestion": "請改為 privilege: none,或用 privilege: root 搭配 root/<名稱>.sh。"
571
+ },
572
+ "STANDALONE_ROOT_OPS_MISSING": {
573
+ "code": "STANDALONE_ROOT_OPS_MISSING",
574
+ "description": "privilege: root 但沒有任何 root 操作。",
575
+ "suggestion": "請在 root/ 放至少一個 <名稱>.sh,或改為 privilege: none。"
576
+ },
577
+ "STANDALONE_INTEGRATION_INVALID": {
578
+ "code": "STANDALONE_INTEGRATION_INVALID",
579
+ "description": "每包 helper 的 integration 宣告不合法。",
580
+ "suggestion": "使用 native-go、privilege: root、protocol: 1 和 workers map;不要自訂 helper_ 操作。"
581
+ },
582
+ "HELPER_WORKER_UNSAFE": {
583
+ "code": "HELPER_WORKER_UNSAFE",
584
+ "description": "worker inventory 檔案不在專案內或不是一般檔案。",
585
+ "suggestion": "使用專案內的一般檔案,不接受 symlink。"
586
+ },
587
+ "HELPER_WORKERS_TOO_LARGE": {
588
+ "code": "HELPER_WORKERS_TOO_LARGE",
589
+ "description": "worker inventory payload 超過 1 MiB。",
590
+ "suggestion": "減少 worker inventory 檔案大小。"
591
+ },
592
+ "HELPER_TASK_TOO_LARGE": {
593
+ "code": "HELPER_TASK_TOO_LARGE",
594
+ "description": "helper task 超過 4095 bytes 保守限制。",
595
+ "suggestion": "縮短固定 literal;不要內嵌 binary 或將授權改為可寫 script 路徑。"
596
+ },
597
+ "HELPER_METADATA_TOO_LARGE": {
598
+ "code": "HELPER_METADATA_TOO_LARGE",
599
+ "description": "helper scheduler metadata 超過 8191 bytes 限制。",
600
+ "suggestion": "減少 metadata 並核對 DSM readback 的 exact script。"
601
+ },
602
+ "HELPER_GO_REQUIRED": {
603
+ "code": "HELPER_GO_REQUIRED",
604
+ "description": "目前 integration 需要 Go backend。",
605
+ "suggestion": "使用現有 native-go 模板。"
606
+ },
607
+ "HELPER_BUILD_FAILED": {
608
+ "code": "HELPER_BUILD_FAILED",
609
+ "description": "Go helper 編譯失敗。",
610
+ "suggestion": "檢查 Go toolchain 與 backend/cmd/helper 編譯錯誤。"
611
+ },
612
+ "HELPER_ARTIFACT_REQUIRED": {
613
+ "code": "HELPER_ARTIFACT_REQUIRED",
614
+ "description": "integration SPK 缺少已建置的 helper artifact。",
615
+ "suggestion": "使用現有 buildStandalone pipeline 建置完整 helper 與 immutable inventory。"
616
+ },
617
+ "STANDALONE_ROOT_OP_INVALID": {
618
+ "code": "STANDALONE_ROOT_OP_INVALID",
619
+ "description": "root/ 內有不合法的 root 操作檔案。",
620
+ "suggestion": "每個檔案必須是 root/<小寫名稱>.sh 一般檔案、以 #!/bin/sh 開頭、16 KiB 以內。"
621
+ },
622
+ "STANDALONE_ROOT_OPS_UNUSED": {
623
+ "code": "STANDALONE_ROOT_OPS_UNUSED",
624
+ "description": "專案有 root/ 資料夾,但 privilege 不是 root。",
625
+ "suggestion": "要使用 root 操作請設 privilege: root;不需要就刪除 root/。"
626
+ },
627
+ "STANDALONE_PACKAGE_INVALID": {
628
+ "code": "STANDALONE_PACKAGE_INVALID",
629
+ "description": "package 名稱不合法。",
630
+ "suggestion": "請使用英文字母開頭、只含英數字的 2–64 字名稱,例如 PhotoTagger。"
631
+ },
632
+ "STANDALONE_VERSION_INVALID": {
633
+ "code": "STANDALONE_VERSION_INVALID",
634
+ "description": "version 不是數字版本。",
635
+ "suggestion": "請使用 1.2.0 這類版本,build 號碼另外填在 build。"
636
+ },
637
+ "STANDALONE_BUILD_INVALID": {
638
+ "code": "STANDALONE_BUILD_INVALID",
639
+ "description": "build 不是 1–9999 的整數。",
640
+ "suggestion": "請將 build 設為 1–9999 的整數,每次發出 SPK 時遞增。"
641
+ },
642
+ "STANDALONE_OS_MIN_VER_INVALID": {
643
+ "code": "STANDALONE_OS_MIN_VER_INVALID",
644
+ "description": "os_min_ver 格式不正確。",
645
+ "suggestion": "請使用 <major>.<minor>-<build>,例如 7.2-64570。"
646
+ },
647
+ "STANDALONE_TEXT_INVALID": {
648
+ "code": "STANDALONE_TEXT_INVALID",
649
+ "description": "顯示文字欄位不合法。",
650
+ "suggestion": "請使用單行、非空且不含 \" 或 \\ 的文字。"
651
+ },
652
+ "STANDALONE_ARCHES_INVALID": {
653
+ "code": "STANDALONE_ARCHES_INVALID",
654
+ "description": "arches 不合法。",
655
+ "suggestion": "請列出不重複的 x86_64 或 aarch64,至少一個。"
656
+ },
657
+ "STANDALONE_ARCH_NOT_DECLARED": {
658
+ "code": "STANDALONE_ARCH_NOT_DECLARED",
659
+ "description": "要求建置的架構不在 arches 內。",
660
+ "suggestion": "請把該架構加入 dsm-package.yaml 的 arches,或改用已宣告的 --arch。"
661
+ },
662
+ "STANDALONE_BACKEND_INVALID": {
663
+ "code": "STANDALONE_BACKEND_INVALID",
664
+ "description": "backend 設定不合法。",
665
+ "suggestion": "backend 需恰好包含 go(dir 與 ./ 開頭的 main)或 binary(以架構為 key)其中之一。"
666
+ },
667
+ "STANDALONE_BINARY_ARCH_MISSING": {
668
+ "code": "STANDALONE_BINARY_ARCH_MISSING",
669
+ "description": "arches 宣告的架構沒有對應的 backend.binary 執行檔。",
670
+ "suggestion": "請在 backend.binary 補上該架構的執行檔,或從 arches 移除它。"
671
+ },
672
+ "STANDALONE_BINARY_MISSING": {
673
+ "code": "STANDALONE_BINARY_MISSING",
674
+ "description": "找不到 backend 執行檔。",
675
+ "suggestion": "請確認 backend.binary 指向的檔案存在。"
676
+ },
677
+ "STANDALONE_BINARY_NOT_REGULAR": {
678
+ "code": "STANDALONE_BINARY_NOT_REGULAR",
679
+ "description": "backend 執行檔不是一般檔案。",
680
+ "suggestion": "請改用實際檔案,不可是 symlink、目錄或特殊檔案。"
681
+ },
682
+ "STANDALONE_BINARY_TOO_LARGE": {
683
+ "code": "STANDALONE_BINARY_TOO_LARGE",
684
+ "description": "backend 執行檔超過 256 MiB。",
685
+ "suggestion": "請縮小執行檔(例如 -ldflags \"-s -w\")。"
686
+ },
687
+ "STANDALONE_BINARY_NOT_ELF": {
688
+ "code": "STANDALONE_BINARY_NOT_ELF",
689
+ "description": "backend 執行檔不是 64-bit little-endian Linux ELF。",
690
+ "suggestion": "請提供為 Linux 編譯的 x86_64 或 aarch64 執行檔。"
691
+ },
692
+ "STANDALONE_BINARY_ARCH_MISMATCH": {
693
+ "code": "STANDALONE_BINARY_ARCH_MISMATCH",
694
+ "description": "backend 執行檔的 CPU 架構與目標不符。",
695
+ "suggestion": "請為該架構重新編譯,或修正 backend.binary 的對應。"
696
+ },
697
+ "STANDALONE_BINARY_DYNAMIC": {
698
+ "code": "STANDALONE_BINARY_DYNAMIC",
699
+ "description": "backend 執行檔是動態連結。",
700
+ "suggestion": "請靜態連結(Go 用 CGO_ENABLED=0),DSM 各機型的 libc 版本不同。"
701
+ },
702
+ "STANDALONE_PATH_INVALID": {
703
+ "code": "STANDALONE_PATH_INVALID",
704
+ "description": "路徑欄位不是專案內的相對路徑。",
705
+ "suggestion": "請使用相對於專案根目錄的路徑。"
706
+ },
707
+ "STANDALONE_PATH_OUTSIDE_PROJECT": {
708
+ "code": "STANDALONE_PATH_OUTSIDE_PROJECT",
709
+ "description": "路徑指向專案目錄之外。",
710
+ "suggestion": "請把檔案放在專案目錄內(symlink 解析後也必須在專案內)。"
711
+ },
712
+ "STANDALONE_UI_INVALID": {
713
+ "code": "STANDALONE_UI_INVALID",
714
+ "description": "ui 設定不合法。",
715
+ "suggestion": "請提供 ui.dir。"
716
+ },
717
+ "STANDALONE_UI_BUILD_INVALID": {
718
+ "code": "STANDALONE_UI_BUILD_INVALID",
719
+ "description": "ui.build 設定不合法。",
720
+ "suggestion": "ui.build.command 必須是 argv 字串陣列(不經 shell),例如 [npm, run, build]。"
721
+ },
722
+ "STANDALONE_IDENTITY_BUILD_FAILED": {
723
+ "code": "STANDALONE_IDENTITY_BUILD_FAILED",
724
+ "description": "選用的 Better Auth bundle 建置失敗。",
725
+ "suggestion": "在 node/ 執行 npm ci 與 npm run build,確認 Node 22 以上。"
726
+ },
727
+ "STANDALONE_IDENTITY_PAYLOAD_INVALID": {
728
+ "code": "STANDALONE_IDENTITY_PAYLOAD_INVALID",
729
+ "description": "Better Auth bundle 不是專案內的有界一般檔案。",
730
+ "suggestion": "重新建置 node/dist/app.mjs,移除 symlink 並確認大小。"
731
+ },
732
+ "STANDALONE_UI_BUILD_FAILED": {
733
+ "code": "STANDALONE_UI_BUILD_FAILED",
734
+ "description": "UI build 指令失敗。",
735
+ "suggestion": "請在 ui.build.cwd 手動執行該指令並修正錯誤。"
736
+ },
737
+ "STANDALONE_UI_ENTRY_MISSING": {
738
+ "code": "STANDALONE_UI_ENTRY_MISSING",
739
+ "description": "UI 目錄缺少 app.js 或 app.css。",
740
+ "suggestion": "請讓 ui.dir(或 UI build 輸出)包含 app.js 與 app.css。"
741
+ },
742
+ "STANDALONE_UI_SYMLINK": {
743
+ "code": "STANDALONE_UI_SYMLINK",
744
+ "description": "UI 目錄含有 symlink。",
745
+ "suggestion": "請以實際檔案取代 symlink。"
746
+ },
747
+ "STANDALONE_UI_SPECIAL_FILE": {
748
+ "code": "STANDALONE_UI_SPECIAL_FILE",
749
+ "description": "UI 目錄含有特殊檔案。",
750
+ "suggestion": "UI 目錄只能有一般檔案與目錄。"
751
+ },
752
+ "STANDALONE_UI_TOO_LARGE": {
753
+ "code": "STANDALONE_UI_TOO_LARGE",
754
+ "description": "UI 檔案總大小超過 64 MiB。",
755
+ "suggestion": "請縮小 UI 資產。"
756
+ },
757
+ "STANDALONE_GO_MISSING": {
758
+ "code": "STANDALONE_GO_MISSING",
759
+ "description": "找不到 go 指令。",
760
+ "suggestion": "請安裝 Go 1.24 以上版本(https://go.dev/dl/),或改用 backend.binary 打包既有執行檔。"
761
+ },
762
+ "STANDALONE_GO_BUILD_FAILED": {
763
+ "code": "STANDALONE_GO_BUILD_FAILED",
764
+ "description": "go build 失敗。",
765
+ "suggestion": "請在 backend 目錄執行 go build ./... 並修正錯誤。"
766
+ },
767
+ "STANDALONE_I18N_INVALID": {
768
+ "code": "STANDALONE_I18N_INVALID",
769
+ "description": "dsm-package.yaml 的 i18n 設定不合法。",
770
+ "suggestion": "i18n 只接受 messages、glossary 與 info;info 以 zh-TW、ja 等支援語言為 key(英文寫在頂層)。"
771
+ },
772
+ "STANDALONE_I18N_MESSAGES_MISSING": {
773
+ "code": "STANDALONE_I18N_MESSAGES_MISSING",
774
+ "description": "i18n.messages 目錄缺少 en.json。",
775
+ "suggestion": "請加入 en.json;它是所有語言的後備文字與 key 清單。"
776
+ },
777
+ "STANDALONE_I18N_LOCALE_UNSUPPORTED": {
778
+ "code": "STANDALONE_I18N_LOCALE_UNSUPPORTED",
779
+ "description": "訊息檔的語言不在支援的九種語言內。",
780
+ "suggestion": "請使用 en、zh-TW、zh-CN、ja、ko、de、fr、es、it;其他 DSM 語言會顯示英文。"
781
+ },
782
+ "STANDALONE_I18N_CATALOG_INVALID": {
783
+ "code": "STANDALONE_I18N_CATALOG_INVALID",
784
+ "description": "訊息檔不是扁平的 key → 文字 JSON 物件。",
785
+ "suggestion": "請改成 { \"greeting.save\": \"Save\" } 這種格式。"
786
+ },
787
+ "STANDALONE_I18N_KEYS_MISMATCH": {
788
+ "code": "STANDALONE_I18N_KEYS_MISMATCH",
789
+ "description": "某語言的訊息 key 與 en.json 不同。",
790
+ "suggestion": "請讓每個語言檔都恰好有 en.json 的所有 key。"
791
+ },
792
+ "STANDALONE_I18N_PLACEHOLDER_MISMATCH": {
793
+ "code": "STANDALONE_I18N_PLACEHOLDER_MISMATCH",
794
+ "description": "翻譯少了或多了 {placeholder}。",
795
+ "suggestion": "請保留 en.json 文字中的每個 {name} 佔位符。"
796
+ },
797
+ "STANDALONE_I18N_GLOSSARY_INVALID": {
798
+ "code": "STANDALONE_I18N_GLOSSARY_INVALID",
799
+ "description": "用語表格式錯誤,或指向不存在的訊息 key。",
800
+ "suggestion": "請修正 glossary.json 的 terms(id、text、keys)。"
801
+ },
802
+ "STANDALONE_I18N_GLOSSARY_MISMATCH": {
803
+ "code": "STANDALONE_I18N_GLOSSARY_MISMATCH",
804
+ "description": "訊息沒有使用用語表中的 Synology 官方用語。",
805
+ "suggestion": "請改用 glossary.json 中該語言的用語,與 DSM 介面保持一致。"
806
+ },
807
+ "DEPLOY_VERSION_INVALID": {
808
+ "code": "DEPLOY_VERSION_INVALID",
809
+ "description": "套件版本無效或低於已安裝版本。",
810
+ "suggestion": "設定更高的有效 version/build 再部署。"
811
+ }
864
812
  };
865
813
  export function getErrorCode(code) {
866
814
  return ERROR_REGISTRY[code];