@synopackageland/cli 0.3.10 → 0.4.1

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 (641) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -9
  3. package/dist/bin.js +1 -2
  4. package/dist/build-spk/generator.d.ts +0 -3
  5. package/dist/build-spk/generator.js +138 -287
  6. package/dist/build-spk/native-lifecycle.js +0 -3
  7. package/dist/build-spk/native-payload.js +0 -1
  8. package/dist/build-spk/notices.d.ts +5 -0
  9. package/dist/build-spk/notices.js +60 -0
  10. package/dist/cli.js +178 -151
  11. package/dist/compose/analyze.d.ts +1 -2
  12. package/dist/compose/analyze.js +5 -48
  13. package/dist/contract/unsupported-types.d.ts +10 -0
  14. package/dist/contract/unsupported-types.js +49 -0
  15. package/dist/contract/validate.js +25 -2
  16. package/dist/contract/web-launch.js +0 -2
  17. package/dist/deploy/deploy.d.ts +1 -4
  18. package/dist/deploy/deploy.js +45 -156
  19. package/dist/deploy/homes-values.js +1 -1
  20. package/dist/deploy/plan.d.ts +18 -0
  21. package/dist/deploy/plan.js +54 -0
  22. package/dist/deploy/spk-version.d.ts +2 -14
  23. package/dist/deploy/spk-version.js +25 -111
  24. package/dist/dev.d.ts +1 -3
  25. package/dist/dev.js +14 -28
  26. package/dist/error-registry.js +830 -862
  27. package/dist/host/dsm-client.js +12 -272
  28. package/dist/host/dsm-port-profile.d.ts +0 -1
  29. package/dist/host/dsm-port-profile.js +0 -2
  30. package/dist/host/types.d.ts +1 -83
  31. package/dist/index.d.ts +0 -9
  32. package/dist/index.js +0 -6
  33. package/dist/info.d.ts +0 -1
  34. package/dist/info.js +3 -10
  35. package/dist/init.d.ts +15 -1
  36. package/dist/init.js +128 -12
  37. package/dist/log.js +2 -3
  38. package/dist/native/validate.js +0 -1
  39. package/dist/standalone/binary.d.ts +9 -0
  40. package/dist/standalone/binary.js +67 -0
  41. package/dist/standalone/build.d.ts +25 -0
  42. package/dist/standalone/build.js +110 -0
  43. package/dist/standalone/daemon.d.ts +23 -0
  44. package/dist/standalone/daemon.js +114 -0
  45. package/dist/standalone/dsm-window.d.ts +26 -0
  46. package/dist/standalone/dsm-window.js +291 -0
  47. package/dist/standalone/helper-inventory.d.ts +16 -0
  48. package/dist/standalone/helper-inventory.js +2 -0
  49. package/dist/standalone/helper.d.ts +21 -0
  50. package/dist/standalone/helper.js +105 -0
  51. package/dist/standalone/host-adapter.d.ts +5 -0
  52. package/dist/standalone/host-adapter.js +148 -0
  53. package/dist/standalone/host-platform.d.ts +13 -0
  54. package/dist/standalone/host-platform.js +42 -0
  55. package/dist/standalone/host-types.d.ts +49 -0
  56. package/dist/standalone/host-types.js +1 -0
  57. package/dist/standalone/i18n.d.ts +28 -0
  58. package/dist/standalone/i18n.js +161 -0
  59. package/dist/standalone/inspect-helper.d.ts +6 -0
  60. package/dist/standalone/inspect-helper.js +88 -0
  61. package/dist/standalone/inspect-spk.d.ts +23 -0
  62. package/dist/standalone/inspect-spk.js +209 -0
  63. package/dist/standalone/lifecycle-helper.d.ts +2 -0
  64. package/dist/standalone/lifecycle-helper.js +12 -0
  65. package/dist/standalone/lifecycle.d.ts +3 -0
  66. package/dist/standalone/lifecycle.js +53 -0
  67. package/dist/standalone/manifest.d.ts +73 -0
  68. package/dist/standalone/manifest.js +279 -0
  69. package/dist/standalone/reopen-events.d.ts +2 -0
  70. package/dist/standalone/reopen-events.js +28 -0
  71. package/dist/standalone/root-messages.d.ts +7 -0
  72. package/dist/standalone/root-messages.js +259 -0
  73. package/dist/standalone/root-ops.d.ts +42 -0
  74. package/dist/standalone/root-ops.js +101 -0
  75. package/dist/standalone/root-window.d.ts +36 -0
  76. package/dist/standalone/root-window.js +302 -0
  77. package/dist/standalone/spk.d.ts +23 -0
  78. package/dist/standalone/spk.js +192 -0
  79. package/dist/template-paths.d.ts +2 -0
  80. package/dist/template-paths.js +9 -0
  81. package/dist/templates/_daemon/fixture_linux_test.go +15 -0
  82. package/dist/templates/_daemon/fixture_other_test.go +7 -0
  83. package/dist/templates/_daemon/go.mod +3 -0
  84. package/dist/templates/_daemon/main.go +608 -0
  85. package/dist/templates/_daemon/main_test.go +242 -0
  86. package/dist/templates/_daemon/process_linux.go +55 -0
  87. package/dist/templates/_daemon/process_linux_test.go +161 -0
  88. package/dist/templates/_daemon/process_other.go +14 -0
  89. package/dist/templates/_daemon/testdata/child.go +41 -0
  90. package/dist/templates/_shared/GO-LICENSE +27 -0
  91. package/dist/templates/_shared/GO-PATENTS +22 -0
  92. package/dist/templates/_shared/LICENSES/TEMPLATE.txt +21 -0
  93. package/dist/templates/_shared/notice-overrides/index.json +14 -0
  94. package/dist/templates/_shared/notice-overrides/utils-0.4.2-LICENSE +21 -0
  95. package/dist/templates/_shared/notice-overrides/utils-0.5.0-LICENSE +21 -0
  96. package/dist/templates/_shared/third-party-notices.mjs +51 -0
  97. package/dist/templates/binary/synology-app.yaml +7 -0
  98. package/dist/templates/hello-files/compose.yaml +0 -1
  99. package/dist/templates/hello-web/compose.yaml +13 -10
  100. package/dist/templates/hello-web/html/app.js +1 -23
  101. package/dist/templates/hello-web/html/index.html +1 -3
  102. package/dist/templates/hello-web-page/compose.yaml +13 -10
  103. package/dist/templates/hello-web-page/html/app.js +1 -23
  104. package/dist/templates/hello-web-page/html/index.html +1 -3
  105. package/dist/templates/native-go/README.md +324 -0
  106. package/dist/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +59 -0
  107. package/dist/templates/native-go/backend/cmd/app/main.go +49 -0
  108. package/dist/templates/native-go/backend/cmd/dsm-readonly-probe/main_linux.go +46 -0
  109. package/dist/templates/native-go/backend/cmd/helper/main.go +38 -0
  110. package/dist/templates/native-go/backend/go.mod +7 -0
  111. package/dist/templates/native-go/backend/go.sum +4 -0
  112. package/dist/templates/native-go/backend/internal/api/binary.go +154 -0
  113. package/dist/templates/native-go/backend/internal/api/binary_test.go +165 -0
  114. package/dist/templates/native-go/backend/internal/api/errors.go +33 -0
  115. package/dist/templates/native-go/backend/internal/api/registry.go +104 -0
  116. package/dist/templates/native-go/backend/internal/api/registry_test.go +329 -0
  117. package/dist/templates/native-go/backend/internal/api/server.go +159 -0
  118. package/dist/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +121 -0
  119. package/dist/templates/native-go/backend/internal/app/nas_refusal_test.go +46 -0
  120. package/dist/templates/native-go/backend/internal/app/root_none.go +9 -0
  121. package/dist/templates/native-go/backend/internal/app/routes.go +138 -0
  122. package/dist/templates/native-go/backend/internal/app/routes_test.go +172 -0
  123. package/dist/templates/native-go/backend/internal/dsm/auth.go +118 -0
  124. package/dist/templates/native-go/backend/internal/dsm/auth_test.go +139 -0
  125. package/dist/templates/native-go/backend/internal/dsmprobe/collector_linux.go +335 -0
  126. package/dist/templates/native-go/backend/internal/dsmprobe/collector_linux_test.go +41 -0
  127. package/dist/templates/native-go/backend/internal/dsmprobe/protocol.go +179 -0
  128. package/dist/templates/native-go/backend/internal/dsmprobe/protocol_test.go +29 -0
  129. package/dist/templates/native-go/backend/internal/helper/cohort.go +393 -0
  130. package/dist/templates/native-go/backend/internal/helper/cohort_publication.go +18 -0
  131. package/dist/templates/native-go/backend/internal/helper/cohort_publication_test.go +105 -0
  132. package/dist/templates/native-go/backend/internal/helper/cohort_test.go +372 -0
  133. package/dist/templates/native-go/backend/internal/helper/control.go +424 -0
  134. package/dist/templates/native-go/backend/internal/helper/control_test.go +250 -0
  135. package/dist/templates/native-go/backend/internal/helper/data_contract.go +242 -0
  136. package/dist/templates/native-go/backend/internal/helper/data_contract_test.go +51 -0
  137. package/dist/templates/native-go/backend/internal/helper/data_decode.go +184 -0
  138. package/dist/templates/native-go/backend/internal/helper/data_decode_pointer_test.go +30 -0
  139. package/dist/templates/native-go/backend/internal/helper/data_protocol.go +416 -0
  140. package/dist/templates/native-go/backend/internal/helper/data_protocol_test.go +449 -0
  141. package/dist/templates/native-go/backend/internal/helper/dsm_acl_linux.go +139 -0
  142. package/dist/templates/native-go/backend/internal/helper/dsm_acl_linux_test.go +121 -0
  143. package/dist/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux.go +95 -0
  144. package/dist/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux_test.go +56 -0
  145. package/dist/templates/native-go/backend/internal/helper/dsm_bridge_linux.go +144 -0
  146. package/dist/templates/native-go/backend/internal/helper/dsm_bridge_linux_test.go +89 -0
  147. package/dist/templates/native-go/backend/internal/helper/dsm_home_linux.go +107 -0
  148. package/dist/templates/native-go/backend/internal/helper/dsm_home_linux_test.go +82 -0
  149. package/dist/templates/native-go/backend/internal/helper/dsm_probe_transport_linux.go +151 -0
  150. package/dist/templates/native-go/backend/internal/helper/dsm_probe_transport_linux_test.go +66 -0
  151. package/dist/templates/native-go/backend/internal/helper/grant_authority.go +516 -0
  152. package/dist/templates/native-go/backend/internal/helper/grant_authority_contract.go +88 -0
  153. package/dist/templates/native-go/backend/internal/helper/grant_authority_test.go +510 -0
  154. package/dist/templates/native-go/backend/internal/helper/grant_cohort.go +389 -0
  155. package/dist/templates/native-go/backend/internal/helper/grant_cohort_test.go +239 -0
  156. package/dist/templates/native-go/backend/internal/helper/grant_delivery.go +49 -0
  157. package/dist/templates/native-go/backend/internal/helper/grant_delivery_methods.go +273 -0
  158. package/dist/templates/native-go/backend/internal/helper/grant_delivery_test.go +322 -0
  159. package/dist/templates/native-go/backend/internal/helper/grant_operation_contract.go +47 -0
  160. package/dist/templates/native-go/backend/internal/helper/grant_readonly_test.go +180 -0
  161. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux.go +415 -0
  162. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +468 -0
  163. package/dist/templates/native-go/backend/internal/helper/grant_rpc.go +147 -0
  164. package/dist/templates/native-go/backend/internal/helper/grant_rpc_test.go +51 -0
  165. package/dist/templates/native-go/backend/internal/helper/grant_snapshot.go +75 -0
  166. package/dist/templates/native-go/backend/internal/helper/grant_supervisor_linux.go +134 -0
  167. package/dist/templates/native-go/backend/internal/helper/grant_supervisor_linux_test.go +254 -0
  168. package/dist/templates/native-go/backend/internal/helper/lease.go +112 -0
  169. package/dist/templates/native-go/backend/internal/helper/lease_linux.go +44 -0
  170. package/dist/templates/native-go/backend/internal/helper/lease_other.go +8 -0
  171. package/dist/templates/native-go/backend/internal/helper/lifecycle.go +234 -0
  172. package/dist/templates/native-go/backend/internal/helper/lifecycle_test.go +473 -0
  173. package/dist/templates/native-go/backend/internal/helper/managed_pilot.go +284 -0
  174. package/dist/templates/native-go/backend/internal/helper/managed_pilot_repository_linux.go +74 -0
  175. package/dist/templates/native-go/backend/internal/helper/managed_pilot_repository_linux_test.go +40 -0
  176. package/dist/templates/native-go/backend/internal/helper/managed_pilot_test.go +210 -0
  177. package/dist/templates/native-go/backend/internal/helper/nas_shipped_refusal_linux_test.go +97 -0
  178. package/dist/templates/native-go/backend/internal/helper/native_discovery.go +79 -0
  179. package/dist/templates/native-go/backend/internal/helper/native_identity.go +89 -0
  180. package/dist/templates/native-go/backend/internal/helper/native_provider.go +159 -0
  181. package/dist/templates/native-go/backend/internal/helper/native_provider_test.go +421 -0
  182. package/dist/templates/native-go/backend/internal/helper/observation.go +204 -0
  183. package/dist/templates/native-go/backend/internal/helper/observation_health_test.go +115 -0
  184. package/dist/templates/native-go/backend/internal/helper/observation_reload_budget_test.go +117 -0
  185. package/dist/templates/native-go/backend/internal/helper/observation_test.go +196 -0
  186. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic.go +109 -0
  187. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux.go +76 -0
  188. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +124 -0
  189. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_test.go +98 -0
  190. package/dist/templates/native-go/backend/internal/helper/operation_bootstrap_linux.go +193 -0
  191. package/dist/templates/native-go/backend/internal/helper/operation_credentials_linux.go +56 -0
  192. package/dist/templates/native-go/backend/internal/helper/operation_linux.go +480 -0
  193. package/dist/templates/native-go/backend/internal/helper/operation_linux_test.go +528 -0
  194. package/dist/templates/native-go/backend/internal/helper/peer_linux.go +44 -0
  195. package/dist/templates/native-go/backend/internal/helper/peer_other.go +7 -0
  196. package/dist/templates/native-go/backend/internal/helper/process_linux.go +177 -0
  197. package/dist/templates/native-go/backend/internal/helper/process_other.go +5 -0
  198. package/dist/templates/native-go/backend/internal/helper/publication_test.go +178 -0
  199. package/dist/templates/native-go/backend/internal/helper/read_stream_cohort_linux_test.go +156 -0
  200. package/dist/templates/native-go/backend/internal/helper/read_transfer.go +40 -0
  201. package/dist/templates/native-go/backend/internal/helper/read_transfer_linux.go +109 -0
  202. package/dist/templates/native-go/backend/internal/helper/read_transfer_linux_test.go +118 -0
  203. package/dist/templates/native-go/backend/internal/helper/read_transfer_test.go +177 -0
  204. package/dist/templates/native-go/backend/internal/helper/readonly.go +105 -0
  205. package/dist/templates/native-go/backend/internal/helper/readonly_admission.go +85 -0
  206. package/dist/templates/native-go/backend/internal/helper/readonly_cohort_linux_test.go +253 -0
  207. package/dist/templates/native-go/backend/internal/helper/readonly_linux_test.go +378 -0
  208. package/dist/templates/native-go/backend/internal/helper/readonly_mount_linux.go +65 -0
  209. package/dist/templates/native-go/backend/internal/helper/readonly_mount_proxy_linux.go +113 -0
  210. package/dist/templates/native-go/backend/internal/helper/readonly_operations_linux.go +168 -0
  211. package/dist/templates/native-go/backend/internal/helper/readonly_resolver_linux.go +241 -0
  212. package/dist/templates/native-go/backend/internal/helper/readonly_test.go +40 -0
  213. package/dist/templates/native-go/backend/internal/helper/relaxed_identity.go +252 -0
  214. package/dist/templates/native-go/backend/internal/helper/relaxed_identity_contract.go +105 -0
  215. package/dist/templates/native-go/backend/internal/helper/relaxed_identity_test.go +406 -0
  216. package/dist/templates/native-go/backend/internal/helper/relaxed_invalidation.go +200 -0
  217. package/dist/templates/native-go/backend/internal/helper/repair.go +132 -0
  218. package/dist/templates/native-go/backend/internal/helper/repair_test.go +271 -0
  219. package/dist/templates/native-go/backend/internal/helper/s1r_actor_acl_linux_test.go +303 -0
  220. package/dist/templates/native-go/backend/internal/helper/s1r_actor_fixture_linux_test.go +184 -0
  221. package/dist/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +231 -0
  222. package/dist/templates/native-go/backend/internal/helper/s1r_fixture_contract_linux_test.go +18 -0
  223. package/dist/templates/native-go/backend/internal/helper/server_linux.go +124 -0
  224. package/dist/templates/native-go/backend/internal/helper/status.go +334 -0
  225. package/dist/templates/native-go/backend/internal/helper/status_test.go +288 -0
  226. package/dist/templates/native-go/backend/internal/helper/supervision.go +107 -0
  227. package/dist/templates/native-go/backend/internal/helper/supervision_test.go +124 -0
  228. package/dist/templates/native-go/backend/internal/helper/supervisor_frame.go +76 -0
  229. package/dist/templates/native-go/backend/internal/helper/supervisor_frame_linux_test.go +69 -0
  230. package/dist/templates/native-go/backend/internal/helper/supervisor_frame_test.go +107 -0
  231. package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +363 -0
  232. package/dist/templates/native-go/backend/internal/helper/supervisor_linux_test.go +913 -0
  233. package/dist/templates/native-go/backend/internal/helper/supervisor_socket_eof_test.go +74 -0
  234. package/dist/templates/native-go/backend/internal/helper/supervisor_socket_test.go +45 -0
  235. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/create.json +23 -0
  236. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/frames.json +67 -0
  237. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/grant-store.json +52 -0
  238. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/intent.json +20 -0
  239. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/list.json +20 -0
  240. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/publish.json +20 -0
  241. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/read.json +22 -0
  242. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/stat.json +22 -0
  243. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/write-stream.json +22 -0
  244. package/dist/templates/native-go/backend/internal/helper/unit_connection.go +75 -0
  245. package/dist/templates/native-go/backend/internal/helper/unit_connection_linux_test.go +135 -0
  246. package/dist/templates/native-go/backend/internal/helper/unit_connection_test.go +133 -0
  247. package/dist/templates/native-go/backend/internal/helper/unit_frame_test.go +32 -0
  248. package/dist/templates/native-go/backend/internal/helper/unit_linux.go +364 -0
  249. package/dist/templates/native-go/backend/internal/helper/unit_linux_test.go +46 -0
  250. package/dist/templates/native-go/backend/internal/helper/unit_mechanisms_linux_test.go +217 -0
  251. package/dist/templates/native-go/backend/internal/helper/unit_padding_linux_test.go +178 -0
  252. package/dist/templates/native-go/backend/internal/helper/unit_query_linux.go +111 -0
  253. package/dist/templates/native-go/backend/internal/helper/unit_reload_linux_test.go +372 -0
  254. package/dist/templates/native-go/backend/internal/helper/unit_reload_sequence_linux_test.go +232 -0
  255. package/dist/templates/native-go/backend/internal/helper/write.go +77 -0
  256. package/dist/templates/native-go/backend/internal/helper/write_admission.go +260 -0
  257. package/dist/templates/native-go/backend/internal/helper/write_admission_test.go +135 -0
  258. package/dist/templates/native-go/backend/internal/helper/write_cohort_linux_test.go +218 -0
  259. package/dist/templates/native-go/backend/internal/helper/write_files_linux.go +202 -0
  260. package/dist/templates/native-go/backend/internal/helper/write_files_linux_test.go +199 -0
  261. package/dist/templates/native-go/backend/internal/helper/write_intent_linux.go +116 -0
  262. package/dist/templates/native-go/backend/internal/helper/write_intent_linux_test.go +74 -0
  263. package/dist/templates/native-go/backend/internal/helper/write_operation_linux.go +245 -0
  264. package/dist/templates/native-go/backend/internal/helper/write_test.go +53 -0
  265. package/dist/templates/native-go/dsm-package.yaml +58 -0
  266. package/dist/templates/native-go/gitignore +1 -0
  267. package/dist/templates/native-go/i18n/glossary.json +662 -0
  268. package/dist/templates/native-go/i18n/messages/de.json +28 -0
  269. package/dist/templates/native-go/i18n/messages/en.json +28 -0
  270. package/dist/templates/native-go/i18n/messages/es.json +28 -0
  271. package/dist/templates/native-go/i18n/messages/fr.json +28 -0
  272. package/dist/templates/native-go/i18n/messages/it.json +28 -0
  273. package/dist/templates/native-go/i18n/messages/ja.json +28 -0
  274. package/dist/templates/native-go/i18n/messages/ko.json +28 -0
  275. package/dist/templates/native-go/i18n/messages/zh-CN.json +28 -0
  276. package/dist/templates/native-go/i18n/messages/zh-TW.json +28 -0
  277. package/dist/templates/native-go/ui/app.css +35 -0
  278. package/dist/templates/native-go/ui/app.js +101 -0
  279. package/dist/templates/native-go-better-auth/backend/internal/app/identity.go +208 -0
  280. package/dist/templates/native-go-better-auth/backend/internal/app/identity_test.go +113 -0
  281. package/dist/templates/native-go-better-auth/node/app.mjs +72 -0
  282. package/dist/templates/native-go-better-auth/node/build.mjs +4 -0
  283. package/dist/templates/native-go-better-auth/node/package-lock.json +862 -0
  284. package/dist/templates/native-go-better-auth/node/package.json +1 -0
  285. package/dist/templates/native-go-better-auth/node/test/auth.test.mjs +31 -0
  286. package/dist/templates/native-go-integration/backend/internal/app/identity_none.go +6 -0
  287. package/dist/templates/native-go-integration/backend/internal/app/personal.go +203 -0
  288. package/dist/templates/native-go-integration/backend/internal/app/personal_test.go +119 -0
  289. package/dist/templates/native-go-root/backend/internal/app/root.go +107 -0
  290. package/dist/templates/native-go-root/backend/internal/app/root_test.go +124 -0
  291. package/dist/templates/native-go-root/root/whoami.sh +6 -0
  292. package/dist/templates/native-go-vue/README.md +224 -0
  293. package/dist/templates/native-go-vue/frontend/DESIGN.md +78 -0
  294. package/dist/templates/native-go-vue/frontend/package-lock.json +2410 -0
  295. package/dist/templates/native-go-vue/frontend/package.json +6 -0
  296. package/dist/templates/native-go-vue/frontend/src/App.vue +159 -0
  297. package/dist/templates/native-go-vue/frontend/src/context.ts +56 -0
  298. package/dist/templates/native-go-vue/frontend/src/main.ts +29 -0
  299. package/dist/templates/native-go-vue/frontend/src/nas/NasGrantSettings.vue +74 -0
  300. package/dist/templates/native-go-vue/frontend/src/nas/NasPathPicker.vue +106 -0
  301. package/dist/templates/native-go-vue/frontend/src/nas/NasUnavailable.vue +20 -0
  302. package/dist/templates/native-go-vue/frontend/src/nas/i18n/de.json +74 -0
  303. package/dist/templates/native-go-vue/frontend/src/nas/i18n/en.json +74 -0
  304. package/dist/templates/native-go-vue/frontend/src/nas/i18n/es.json +74 -0
  305. package/dist/templates/native-go-vue/frontend/src/nas/i18n/fr.json +74 -0
  306. package/dist/templates/native-go-vue/frontend/src/nas/i18n/it.json +74 -0
  307. package/dist/templates/native-go-vue/frontend/src/nas/i18n/ja.json +74 -0
  308. package/dist/templates/native-go-vue/frontend/src/nas/i18n/ko.json +74 -0
  309. package/dist/templates/native-go-vue/frontend/src/nas/i18n/zh-CN.json +74 -0
  310. package/dist/templates/native-go-vue/frontend/src/nas/i18n/zh-TW.json +74 -0
  311. package/dist/templates/native-go-vue/frontend/src/nas/i18n.ts +38 -0
  312. package/dist/templates/native-go-vue/frontend/src/nas/mock-provider.ts +119 -0
  313. package/dist/templates/native-go-vue/frontend/src/nas/provider.ts +59 -0
  314. package/dist/templates/native-go-vue/frontend/src/nas/use-request.ts +27 -0
  315. package/dist/templates/native-go-vue/frontend/src/style.css +31 -0
  316. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +190 -0
  317. package/dist/templates/native-go-vue/frontend/test/nas-provider.test.ts +81 -0
  318. package/dist/templates/native-go-vue/frontend/test/nas-request.test.ts +21 -0
  319. package/dist/templates/native-go-vue/frontend/test/nas-ui.test.ts +261 -0
  320. package/dist/templates/native-go-vue/frontend/tsconfig.json +1 -0
  321. package/dist/templates/native-go-vue/frontend/vite.config.ts +10 -0
  322. package/dist/templates/native-go-vue/gitignore +2 -0
  323. package/dist/types.d.ts +1 -1
  324. package/dist/validate.js +11 -7
  325. package/package.json +5 -8
  326. package/schema/synology-app.schema.json +36 -37
  327. package/skills/SKILL.md +4 -48
  328. package/skills/reference/create.md +11 -83
  329. package/skills/reference/deploy.md +7 -78
  330. package/skills/reference/diagnose.md +4 -101
  331. package/skills/reference/files.md +5 -41
  332. package/skills/reference/identity.md +3 -29
  333. package/skills/reference/wrap.md +0 -2
  334. package/templates/_daemon/fixture_linux_test.go +15 -0
  335. package/templates/_daemon/fixture_other_test.go +7 -0
  336. package/templates/_daemon/go.mod +3 -0
  337. package/templates/_daemon/main.go +608 -0
  338. package/templates/_daemon/main_test.go +242 -0
  339. package/templates/_daemon/process_linux.go +55 -0
  340. package/templates/_daemon/process_linux_test.go +161 -0
  341. package/templates/_daemon/process_other.go +14 -0
  342. package/templates/_daemon/testdata/child.go +41 -0
  343. package/templates/_shared/GO-LICENSE +27 -0
  344. package/templates/_shared/GO-PATENTS +22 -0
  345. package/templates/_shared/LICENSES/TEMPLATE.txt +21 -0
  346. package/templates/_shared/notice-overrides/index.json +14 -0
  347. package/templates/_shared/notice-overrides/utils-0.4.2-LICENSE +21 -0
  348. package/templates/_shared/notice-overrides/utils-0.5.0-LICENSE +21 -0
  349. package/templates/_shared/third-party-notices.mjs +51 -0
  350. package/templates/binary/synology-app.yaml +7 -0
  351. package/templates/hello-files/compose.yaml +0 -1
  352. package/templates/hello-web/compose.yaml +13 -10
  353. package/templates/hello-web/html/app.js +1 -23
  354. package/templates/hello-web/html/index.html +1 -3
  355. package/templates/hello-web-page/compose.yaml +13 -10
  356. package/templates/hello-web-page/html/app.js +1 -23
  357. package/templates/hello-web-page/html/index.html +1 -3
  358. package/templates/native-go/README.md +324 -0
  359. package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +59 -0
  360. package/templates/native-go/backend/cmd/app/main.go +49 -0
  361. package/templates/native-go/backend/cmd/dsm-readonly-probe/main_linux.go +46 -0
  362. package/templates/native-go/backend/cmd/helper/main.go +38 -0
  363. package/templates/native-go/backend/go.mod +7 -0
  364. package/templates/native-go/backend/go.sum +4 -0
  365. package/templates/native-go/backend/internal/api/binary.go +154 -0
  366. package/templates/native-go/backend/internal/api/binary_test.go +165 -0
  367. package/templates/native-go/backend/internal/api/errors.go +33 -0
  368. package/templates/native-go/backend/internal/api/registry.go +104 -0
  369. package/templates/native-go/backend/internal/api/registry_test.go +329 -0
  370. package/templates/native-go/backend/internal/api/server.go +159 -0
  371. package/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +121 -0
  372. package/templates/native-go/backend/internal/app/nas_refusal_test.go +46 -0
  373. package/templates/native-go/backend/internal/app/root_none.go +9 -0
  374. package/templates/native-go/backend/internal/app/routes.go +138 -0
  375. package/templates/native-go/backend/internal/app/routes_test.go +172 -0
  376. package/templates/native-go/backend/internal/dsm/auth.go +118 -0
  377. package/templates/native-go/backend/internal/dsm/auth_test.go +139 -0
  378. package/templates/native-go/backend/internal/dsmprobe/collector_linux.go +335 -0
  379. package/templates/native-go/backend/internal/dsmprobe/collector_linux_test.go +41 -0
  380. package/templates/native-go/backend/internal/dsmprobe/protocol.go +179 -0
  381. package/templates/native-go/backend/internal/dsmprobe/protocol_test.go +29 -0
  382. package/templates/native-go/backend/internal/helper/cohort.go +393 -0
  383. package/templates/native-go/backend/internal/helper/cohort_publication.go +18 -0
  384. package/templates/native-go/backend/internal/helper/cohort_publication_test.go +105 -0
  385. package/templates/native-go/backend/internal/helper/cohort_test.go +372 -0
  386. package/templates/native-go/backend/internal/helper/control.go +424 -0
  387. package/templates/native-go/backend/internal/helper/control_test.go +250 -0
  388. package/templates/native-go/backend/internal/helper/data_contract.go +242 -0
  389. package/templates/native-go/backend/internal/helper/data_contract_test.go +51 -0
  390. package/templates/native-go/backend/internal/helper/data_decode.go +184 -0
  391. package/templates/native-go/backend/internal/helper/data_decode_pointer_test.go +30 -0
  392. package/templates/native-go/backend/internal/helper/data_protocol.go +416 -0
  393. package/templates/native-go/backend/internal/helper/data_protocol_test.go +449 -0
  394. package/templates/native-go/backend/internal/helper/dsm_acl_linux.go +139 -0
  395. package/templates/native-go/backend/internal/helper/dsm_acl_linux_test.go +121 -0
  396. package/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux.go +95 -0
  397. package/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux_test.go +56 -0
  398. package/templates/native-go/backend/internal/helper/dsm_bridge_linux.go +144 -0
  399. package/templates/native-go/backend/internal/helper/dsm_bridge_linux_test.go +89 -0
  400. package/templates/native-go/backend/internal/helper/dsm_home_linux.go +107 -0
  401. package/templates/native-go/backend/internal/helper/dsm_home_linux_test.go +82 -0
  402. package/templates/native-go/backend/internal/helper/dsm_probe_transport_linux.go +151 -0
  403. package/templates/native-go/backend/internal/helper/dsm_probe_transport_linux_test.go +66 -0
  404. package/templates/native-go/backend/internal/helper/grant_authority.go +516 -0
  405. package/templates/native-go/backend/internal/helper/grant_authority_contract.go +88 -0
  406. package/templates/native-go/backend/internal/helper/grant_authority_test.go +510 -0
  407. package/templates/native-go/backend/internal/helper/grant_cohort.go +389 -0
  408. package/templates/native-go/backend/internal/helper/grant_cohort_test.go +239 -0
  409. package/templates/native-go/backend/internal/helper/grant_delivery.go +49 -0
  410. package/templates/native-go/backend/internal/helper/grant_delivery_methods.go +273 -0
  411. package/templates/native-go/backend/internal/helper/grant_delivery_test.go +322 -0
  412. package/templates/native-go/backend/internal/helper/grant_operation_contract.go +47 -0
  413. package/templates/native-go/backend/internal/helper/grant_readonly_test.go +180 -0
  414. package/templates/native-go/backend/internal/helper/grant_repository_linux.go +415 -0
  415. package/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +468 -0
  416. package/templates/native-go/backend/internal/helper/grant_rpc.go +147 -0
  417. package/templates/native-go/backend/internal/helper/grant_rpc_test.go +51 -0
  418. package/templates/native-go/backend/internal/helper/grant_snapshot.go +75 -0
  419. package/templates/native-go/backend/internal/helper/grant_supervisor_linux.go +134 -0
  420. package/templates/native-go/backend/internal/helper/grant_supervisor_linux_test.go +254 -0
  421. package/templates/native-go/backend/internal/helper/lease.go +112 -0
  422. package/templates/native-go/backend/internal/helper/lease_linux.go +44 -0
  423. package/templates/native-go/backend/internal/helper/lease_other.go +8 -0
  424. package/templates/native-go/backend/internal/helper/lifecycle.go +234 -0
  425. package/templates/native-go/backend/internal/helper/lifecycle_test.go +473 -0
  426. package/templates/native-go/backend/internal/helper/managed_pilot.go +284 -0
  427. package/templates/native-go/backend/internal/helper/managed_pilot_repository_linux.go +74 -0
  428. package/templates/native-go/backend/internal/helper/managed_pilot_repository_linux_test.go +40 -0
  429. package/templates/native-go/backend/internal/helper/managed_pilot_test.go +210 -0
  430. package/templates/native-go/backend/internal/helper/nas_shipped_refusal_linux_test.go +97 -0
  431. package/templates/native-go/backend/internal/helper/native_discovery.go +79 -0
  432. package/templates/native-go/backend/internal/helper/native_identity.go +89 -0
  433. package/templates/native-go/backend/internal/helper/native_provider.go +159 -0
  434. package/templates/native-go/backend/internal/helper/native_provider_test.go +421 -0
  435. package/templates/native-go/backend/internal/helper/observation.go +204 -0
  436. package/templates/native-go/backend/internal/helper/observation_health_test.go +115 -0
  437. package/templates/native-go/backend/internal/helper/observation_reload_budget_test.go +117 -0
  438. package/templates/native-go/backend/internal/helper/observation_test.go +196 -0
  439. package/templates/native-go/backend/internal/helper/observer_diagnostic.go +109 -0
  440. package/templates/native-go/backend/internal/helper/observer_diagnostic_linux.go +76 -0
  441. package/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +124 -0
  442. package/templates/native-go/backend/internal/helper/observer_diagnostic_test.go +98 -0
  443. package/templates/native-go/backend/internal/helper/operation_bootstrap_linux.go +193 -0
  444. package/templates/native-go/backend/internal/helper/operation_credentials_linux.go +56 -0
  445. package/templates/native-go/backend/internal/helper/operation_linux.go +480 -0
  446. package/templates/native-go/backend/internal/helper/operation_linux_test.go +528 -0
  447. package/templates/native-go/backend/internal/helper/peer_linux.go +44 -0
  448. package/templates/native-go/backend/internal/helper/peer_other.go +7 -0
  449. package/templates/native-go/backend/internal/helper/process_linux.go +177 -0
  450. package/templates/native-go/backend/internal/helper/process_other.go +5 -0
  451. package/templates/native-go/backend/internal/helper/publication_test.go +178 -0
  452. package/templates/native-go/backend/internal/helper/read_stream_cohort_linux_test.go +156 -0
  453. package/templates/native-go/backend/internal/helper/read_transfer.go +40 -0
  454. package/templates/native-go/backend/internal/helper/read_transfer_linux.go +109 -0
  455. package/templates/native-go/backend/internal/helper/read_transfer_linux_test.go +118 -0
  456. package/templates/native-go/backend/internal/helper/read_transfer_test.go +177 -0
  457. package/templates/native-go/backend/internal/helper/readonly.go +105 -0
  458. package/templates/native-go/backend/internal/helper/readonly_admission.go +85 -0
  459. package/templates/native-go/backend/internal/helper/readonly_cohort_linux_test.go +253 -0
  460. package/templates/native-go/backend/internal/helper/readonly_linux_test.go +378 -0
  461. package/templates/native-go/backend/internal/helper/readonly_mount_linux.go +65 -0
  462. package/templates/native-go/backend/internal/helper/readonly_mount_proxy_linux.go +113 -0
  463. package/templates/native-go/backend/internal/helper/readonly_operations_linux.go +168 -0
  464. package/templates/native-go/backend/internal/helper/readonly_resolver_linux.go +241 -0
  465. package/templates/native-go/backend/internal/helper/readonly_test.go +40 -0
  466. package/templates/native-go/backend/internal/helper/relaxed_identity.go +252 -0
  467. package/templates/native-go/backend/internal/helper/relaxed_identity_contract.go +105 -0
  468. package/templates/native-go/backend/internal/helper/relaxed_identity_test.go +406 -0
  469. package/templates/native-go/backend/internal/helper/relaxed_invalidation.go +200 -0
  470. package/templates/native-go/backend/internal/helper/repair.go +132 -0
  471. package/templates/native-go/backend/internal/helper/repair_test.go +271 -0
  472. package/templates/native-go/backend/internal/helper/s1r_actor_acl_linux_test.go +303 -0
  473. package/templates/native-go/backend/internal/helper/s1r_actor_fixture_linux_test.go +184 -0
  474. package/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +231 -0
  475. package/templates/native-go/backend/internal/helper/s1r_fixture_contract_linux_test.go +18 -0
  476. package/templates/native-go/backend/internal/helper/server_linux.go +124 -0
  477. package/templates/native-go/backend/internal/helper/status.go +334 -0
  478. package/templates/native-go/backend/internal/helper/status_test.go +288 -0
  479. package/templates/native-go/backend/internal/helper/supervision.go +107 -0
  480. package/templates/native-go/backend/internal/helper/supervision_test.go +124 -0
  481. package/templates/native-go/backend/internal/helper/supervisor_frame.go +76 -0
  482. package/templates/native-go/backend/internal/helper/supervisor_frame_linux_test.go +69 -0
  483. package/templates/native-go/backend/internal/helper/supervisor_frame_test.go +107 -0
  484. package/templates/native-go/backend/internal/helper/supervisor_linux.go +363 -0
  485. package/templates/native-go/backend/internal/helper/supervisor_linux_test.go +913 -0
  486. package/templates/native-go/backend/internal/helper/supervisor_socket_eof_test.go +74 -0
  487. package/templates/native-go/backend/internal/helper/supervisor_socket_test.go +45 -0
  488. package/templates/native-go/backend/internal/helper/testdata/protocol2/create.json +23 -0
  489. package/templates/native-go/backend/internal/helper/testdata/protocol2/frames.json +67 -0
  490. package/templates/native-go/backend/internal/helper/testdata/protocol2/grant-store.json +52 -0
  491. package/templates/native-go/backend/internal/helper/testdata/protocol2/intent.json +20 -0
  492. package/templates/native-go/backend/internal/helper/testdata/protocol2/list.json +20 -0
  493. package/templates/native-go/backend/internal/helper/testdata/protocol2/publish.json +20 -0
  494. package/templates/native-go/backend/internal/helper/testdata/protocol2/read.json +22 -0
  495. package/templates/native-go/backend/internal/helper/testdata/protocol2/stat.json +22 -0
  496. package/templates/native-go/backend/internal/helper/testdata/protocol2/write-stream.json +22 -0
  497. package/templates/native-go/backend/internal/helper/unit_connection.go +75 -0
  498. package/templates/native-go/backend/internal/helper/unit_connection_linux_test.go +135 -0
  499. package/templates/native-go/backend/internal/helper/unit_connection_test.go +133 -0
  500. package/templates/native-go/backend/internal/helper/unit_frame_test.go +32 -0
  501. package/templates/native-go/backend/internal/helper/unit_linux.go +364 -0
  502. package/templates/native-go/backend/internal/helper/unit_linux_test.go +46 -0
  503. package/templates/native-go/backend/internal/helper/unit_mechanisms_linux_test.go +217 -0
  504. package/templates/native-go/backend/internal/helper/unit_padding_linux_test.go +178 -0
  505. package/templates/native-go/backend/internal/helper/unit_query_linux.go +111 -0
  506. package/templates/native-go/backend/internal/helper/unit_reload_linux_test.go +372 -0
  507. package/templates/native-go/backend/internal/helper/unit_reload_sequence_linux_test.go +232 -0
  508. package/templates/native-go/backend/internal/helper/write.go +77 -0
  509. package/templates/native-go/backend/internal/helper/write_admission.go +260 -0
  510. package/templates/native-go/backend/internal/helper/write_admission_test.go +135 -0
  511. package/templates/native-go/backend/internal/helper/write_cohort_linux_test.go +218 -0
  512. package/templates/native-go/backend/internal/helper/write_files_linux.go +202 -0
  513. package/templates/native-go/backend/internal/helper/write_files_linux_test.go +199 -0
  514. package/templates/native-go/backend/internal/helper/write_intent_linux.go +116 -0
  515. package/templates/native-go/backend/internal/helper/write_intent_linux_test.go +74 -0
  516. package/templates/native-go/backend/internal/helper/write_operation_linux.go +245 -0
  517. package/templates/native-go/backend/internal/helper/write_test.go +53 -0
  518. package/templates/native-go/dsm-package.yaml +58 -0
  519. package/templates/native-go/gitignore +1 -0
  520. package/templates/native-go/i18n/glossary.json +662 -0
  521. package/templates/native-go/i18n/messages/de.json +28 -0
  522. package/templates/native-go/i18n/messages/en.json +28 -0
  523. package/templates/native-go/i18n/messages/es.json +28 -0
  524. package/templates/native-go/i18n/messages/fr.json +28 -0
  525. package/templates/native-go/i18n/messages/it.json +28 -0
  526. package/templates/native-go/i18n/messages/ja.json +28 -0
  527. package/templates/native-go/i18n/messages/ko.json +28 -0
  528. package/templates/native-go/i18n/messages/zh-CN.json +28 -0
  529. package/templates/native-go/i18n/messages/zh-TW.json +28 -0
  530. package/templates/native-go/ui/app.css +35 -0
  531. package/templates/native-go/ui/app.js +101 -0
  532. package/templates/native-go-better-auth/backend/internal/app/identity.go +208 -0
  533. package/templates/native-go-better-auth/backend/internal/app/identity_test.go +113 -0
  534. package/templates/native-go-better-auth/node/app.mjs +72 -0
  535. package/templates/native-go-better-auth/node/build.mjs +4 -0
  536. package/templates/native-go-better-auth/node/package-lock.json +862 -0
  537. package/templates/native-go-better-auth/node/package.json +1 -0
  538. package/templates/native-go-better-auth/node/test/auth.test.mjs +31 -0
  539. package/templates/native-go-integration/backend/internal/app/identity_none.go +6 -0
  540. package/templates/native-go-integration/backend/internal/app/personal.go +203 -0
  541. package/templates/native-go-integration/backend/internal/app/personal_test.go +119 -0
  542. package/templates/native-go-root/backend/internal/app/root.go +107 -0
  543. package/templates/native-go-root/backend/internal/app/root_test.go +124 -0
  544. package/templates/native-go-root/root/whoami.sh +6 -0
  545. package/templates/native-go-vue/README.md +224 -0
  546. package/templates/native-go-vue/frontend/DESIGN.md +78 -0
  547. package/templates/native-go-vue/frontend/package-lock.json +2410 -0
  548. package/templates/native-go-vue/frontend/package.json +6 -0
  549. package/templates/native-go-vue/frontend/src/App.vue +159 -0
  550. package/templates/native-go-vue/frontend/src/context.ts +56 -0
  551. package/templates/native-go-vue/frontend/src/main.ts +29 -0
  552. package/templates/native-go-vue/frontend/src/nas/NasGrantSettings.vue +74 -0
  553. package/templates/native-go-vue/frontend/src/nas/NasPathPicker.vue +106 -0
  554. package/templates/native-go-vue/frontend/src/nas/NasUnavailable.vue +20 -0
  555. package/templates/native-go-vue/frontend/src/nas/i18n/de.json +74 -0
  556. package/templates/native-go-vue/frontend/src/nas/i18n/en.json +74 -0
  557. package/templates/native-go-vue/frontend/src/nas/i18n/es.json +74 -0
  558. package/templates/native-go-vue/frontend/src/nas/i18n/fr.json +74 -0
  559. package/templates/native-go-vue/frontend/src/nas/i18n/it.json +74 -0
  560. package/templates/native-go-vue/frontend/src/nas/i18n/ja.json +74 -0
  561. package/templates/native-go-vue/frontend/src/nas/i18n/ko.json +74 -0
  562. package/templates/native-go-vue/frontend/src/nas/i18n/zh-CN.json +74 -0
  563. package/templates/native-go-vue/frontend/src/nas/i18n/zh-TW.json +74 -0
  564. package/templates/native-go-vue/frontend/src/nas/i18n.ts +38 -0
  565. package/templates/native-go-vue/frontend/src/nas/mock-provider.ts +119 -0
  566. package/templates/native-go-vue/frontend/src/nas/provider.ts +59 -0
  567. package/templates/native-go-vue/frontend/src/nas/use-request.ts +27 -0
  568. package/templates/native-go-vue/frontend/src/style.css +31 -0
  569. package/templates/native-go-vue/frontend/test/apps.test.ts +190 -0
  570. package/templates/native-go-vue/frontend/test/nas-provider.test.ts +81 -0
  571. package/templates/native-go-vue/frontend/test/nas-request.test.ts +21 -0
  572. package/templates/native-go-vue/frontend/test/nas-ui.test.ts +261 -0
  573. package/templates/native-go-vue/frontend/tsconfig.json +1 -0
  574. package/templates/native-go-vue/frontend/vite.config.ts +10 -0
  575. package/templates/native-go-vue/gitignore +2 -0
  576. package/dist/attestation/app-package.d.ts +0 -86
  577. package/dist/attestation/app-package.js +0 -206
  578. package/dist/attestation/install-on-host.d.ts +0 -14
  579. package/dist/attestation/install-on-host.js +0 -52
  580. package/dist/attestation/keyring.d.ts +0 -21
  581. package/dist/attestation/keyring.js +0 -168
  582. package/dist/attestation/platform-service.d.ts +0 -70
  583. package/dist/attestation/platform-service.js +0 -250
  584. package/dist/build-spk/broker-glue.d.ts +0 -16
  585. package/dist/build-spk/broker-glue.js +0 -40
  586. package/dist/deploy/catalog-publish.d.ts +0 -3
  587. package/dist/deploy/catalog-publish.js +0 -7
  588. package/dist/doctor.d.ts +0 -22
  589. package/dist/doctor.js +0 -822
  590. package/dist/error-collector.d.ts +0 -2
  591. package/dist/error-collector.js +0 -46
  592. package/dist/host/broker-paths.d.ts +0 -1
  593. package/dist/host/broker-paths.js +0 -1
  594. package/dist/host/broker-upgrade-preflight.d.ts +0 -61
  595. package/dist/host/broker-upgrade-preflight.js +0 -156
  596. package/dist/host/digests.d.ts +0 -5
  597. package/dist/host/digests.js +0 -63
  598. package/dist/host/fake-nas.d.ts +0 -49
  599. package/dist/host/fake-nas.js +0 -193
  600. package/dist/mock-broker/bootstrap.d.ts +0 -2
  601. package/dist/mock-broker/bootstrap.js +0 -8
  602. package/dist/mock-broker/files.d.ts +0 -60
  603. package/dist/mock-broker/files.js +0 -408
  604. package/dist/mock-broker/oidc.d.ts +0 -31
  605. package/dist/mock-broker/oidc.js +0 -161
  606. package/dist/mock-broker/path.d.ts +0 -9
  607. package/dist/mock-broker/path.js +0 -50
  608. package/dist/mock-broker/server.d.ts +0 -19
  609. package/dist/mock-broker/server.js +0 -350
  610. package/dist/publish/build-ledger.d.ts +0 -22
  611. package/dist/publish/build-ledger.js +0 -26
  612. package/dist/publish/community-path.d.ts +0 -6
  613. package/dist/publish/community-path.js +0 -41
  614. package/dist/publish/curated-release.d.ts +0 -78
  615. package/dist/publish/curated-release.js +0 -883
  616. package/dist/publish/file-build-ledger.d.ts +0 -18
  617. package/dist/publish/file-build-ledger.js +0 -268
  618. package/dist/publish/github-pr.d.ts +0 -25
  619. package/dist/publish/github-pr.js +0 -85
  620. package/dist/publish/github-repo.d.ts +0 -8
  621. package/dist/publish/github-repo.js +0 -21
  622. package/dist/publish/platform-service-release.d.ts +0 -60
  623. package/dist/publish/platform-service-release.js +0 -333
  624. package/dist/publish/preflight.d.ts +0 -24
  625. package/dist/publish/preflight.js +0 -138
  626. package/dist/publish/publish.d.ts +0 -27
  627. package/dist/publish/publish.js +0 -136
  628. package/dist/publish/sync-definition.d.ts +0 -4
  629. package/dist/publish/sync-definition.js +0 -48
  630. package/dist/release-bin.d.ts +0 -2
  631. package/dist/release-bin.js +0 -23
  632. package/dist/templates/hello-web/html/sdk.js +0 -68
  633. package/dist/templates/hello-web-page/html/sdk.js +0 -68
  634. package/dist/templates/native/synology-app.yaml +0 -7
  635. package/dist/test-host.d.ts +0 -15
  636. package/dist/test-host.js +0 -37
  637. package/templates/hello-web/html/sdk.js +0 -68
  638. package/templates/hello-web-page/html/sdk.js +0 -68
  639. package/templates/native/synology-app.yaml +0 -7
  640. /package/dist/templates/{native → binary}/native.yaml +0 -0
  641. /package/templates/{native → binary}/native.yaml +0 -0
@@ -12,32 +12,19 @@ import { validateProject } from "../validate.js";
12
12
  import { writeDsmWindowIcons, writePackageCenterIcons } from "./dsm-icons.js";
13
13
  import { infoArchValue } from "./dsm-arch.js";
14
14
  import { createReproducibleTar } from "./reproducible-archive.js";
15
+ import { copyProjectNotices } from "./notices.js";
15
16
  import { renderDeleteAppDataBlock } from "./delete-app-data.js";
16
- import { BROKER_INSTALLER_VARS, BROKER_SOCKET_REQUIRED_SCRIPT, renderBrokerStatusProbe, } from "./broker-glue.js";
17
17
  import { loadNative } from "../native/load.js";
18
18
  import { materializeNativePayload } from "./native-payload.js";
19
- import { renderNativePrivilege, renderNativeStartStopStatus, renderNativePostuninst, } from "./native-lifecycle.js";
19
+ import { renderNativePostinst, renderNativePrivilege, renderNativeStartStopStatus, renderNativePostuninst, renderNativePreuninst, } from "./native-lifecycle.js";
20
20
  import { renderHeadlessResourceMarker, renderResourceConfig, renderResourceWorkerStartStopStatus, } from "./resource-worker.js";
21
21
  const FILE_MODE = 0o644;
22
22
  const SCRIPT_MODE = 0o755;
23
- function hasInterpolation(value) {
24
- if (typeof value === "string") {
25
- return /\$\{([^}]+)\}/.test(value);
26
- }
27
- if (Array.isArray(value)) {
28
- return value.some(hasInterpolation);
29
- }
30
- if (value && typeof value === "object") {
31
- return Object.values(value).some(hasInterpolation);
32
- }
33
- return false;
34
- }
35
23
  const INSTALL_UIFILE = "install_uifile";
36
24
  const UPGRADE_UIFILE = "upgrade_uifile";
37
25
  const UNINSTALL_UIFILE = "uninstall_uifile";
38
26
  const HEADLESS_PROBE_VOLUME = "./.synopkgland:/run/synopkgland:ro";
39
27
  const HEADLESS_PROBE_README = "Reserved bind target for package-user headless status probing.\n";
40
- export const EMBEDDED_ATTESTATION_RELATIVE_PATH = ".synopkgland/attestation.jwt";
41
28
  const SCRIPT_NAMES = [
42
29
  "preinst",
43
30
  "postinst",
@@ -48,9 +35,6 @@ const SCRIPT_NAMES = [
48
35
  "start-stop-status",
49
36
  ];
50
37
  export async function buildSpk(options) {
51
- if (options.embeddedAttestationToken !== undefined && options.embeddedAttestationToken.length === 0) {
52
- return { ok: false, errors: ["EMBEDDED_ATTESTATION_TOKEN_EMPTY"] };
53
- }
54
38
  const validation = validateProject(options.project);
55
39
  if (!validation.ok) {
56
40
  return {
@@ -123,12 +107,6 @@ export async function buildSpk(options) {
123
107
  }
124
108
  copyFileSync(options.project.contractPath, join(packageDir, "synology-app.yaml"));
125
109
  copyFileSync(nativePath, join(packageDir, "native.yaml"));
126
- if (options.embeddedAttestationToken !== undefined) {
127
- const attestationPath = join(packageDir, EMBEDDED_ATTESTATION_RELATIVE_PATH);
128
- mkdirSync(join(packageDir, ".synopkgland"), { recursive: true });
129
- writeFileSync(attestationPath, options.embeddedAttestationToken, "utf8");
130
- chmodSync(attestationPath, FILE_MODE);
131
- }
132
110
  chmodSync(join(staging, "INFO"), FILE_MODE);
133
111
  chmodSync(join(staging, "privilege"), FILE_MODE);
134
112
  chmodSync(join(staging, "WIZARD_UIFILES", INSTALL_UIFILE), FILE_MODE);
@@ -138,6 +116,7 @@ export async function buildSpk(options) {
138
116
  chmodSync(join(packageDir, "native.yaml"), FILE_MODE);
139
117
  const outputPath = options.outputPath ??
140
118
  join(options.project.root, `${String(contract.package)}-${options.archFamily}.spk`);
119
+ copyProjectNotices(options.project.root, packageDir);
141
120
  await createDeterministicSpk(staging, outputPath);
142
121
  return { ok: true, outputPath, errors: [] };
143
122
  }
@@ -152,7 +131,10 @@ export async function buildSpk(options) {
152
131
  if (route && route.errors.length > 0) {
153
132
  return { ok: false, errors: route.errors.map((error) => error.code) };
154
133
  }
155
- const rwEligibility = route?.eligibility;
134
+ if (!route || route.route === "reject") {
135
+ return { ok: false, errors: ["COMPOSE_ROUTE_UNSUPPORTED"] };
136
+ }
137
+ const rwEligibility = route.eligibility;
156
138
  const isDynamicRoute = route?.route === "dynamic";
157
139
  const isResourceWorkerRoute = route?.route === "static-zero-config" ||
158
140
  isDynamicRoute;
@@ -186,7 +168,7 @@ export async function buildSpk(options) {
186
168
  mkdirSync(resourceProjectDir, { recursive: true });
187
169
  const dsmUserParam = collectInstallParameters(contract).find((p) => p.param.type === "dsm_user");
188
170
  let composeContent;
189
- if (dsmUserParam || rwEligibility?.headless === true || hasOidcCompat(contract)) {
171
+ if (dsmUserParam || rwEligibility?.headless === true) {
190
172
  const rawYaml = readFileSync(options.project.composePath, "utf8");
191
173
  const doc = parseDocument(rawYaml);
192
174
  const services = doc.get("services");
@@ -198,28 +180,6 @@ export async function buildSpk(options) {
198
180
  doc.setIn(["services", sName, "user"], userVal);
199
181
  }
200
182
  }
201
- if (hasOidcCompat(contract) && services && typeof services === "object" && typeof services.toJSON === "function") {
202
- const rawServices = services.toJSON();
203
- for (const [sName, sValue] of Object.entries(rawServices)) {
204
- if (sValue && typeof sValue === "object" && hasInterpolation(sValue)) {
205
- const str = JSON.stringify(sValue);
206
- if (str.includes("SYNOPKGLAND_OIDC_ISSUER")) {
207
- const serviceDoc = doc.getIn(["services", sName]);
208
- const existingExtraHosts = serviceDoc?.get?.("extra_hosts");
209
- const hostGatewayMapping = "${SYNOPKGLAND_OIDC_ISSUER_HOST}:host-gateway";
210
- if (!existingExtraHosts) {
211
- doc.setIn(["services", sName, "extra_hosts"], [hostGatewayMapping]);
212
- }
213
- else if (Array.isArray(existingExtraHosts.toJSON?.())) {
214
- const arr = existingExtraHosts.toJSON();
215
- if (!arr.includes(hostGatewayMapping)) {
216
- doc.setIn(["services", sName, "extra_hosts"], [...arr, hostGatewayMapping]);
217
- }
218
- }
219
- }
220
- }
221
- }
222
- }
223
183
  if (rwEligibility?.headless === true) {
224
184
  injectHeadlessProbeVolume(doc);
225
185
  }
@@ -241,11 +201,6 @@ export async function buildSpk(options) {
241
201
  writeFileSync(join(probePayloadDir, "README"), HEADLESS_PROBE_README, "utf8");
242
202
  chmodSync(join(probePayloadDir, "README"), FILE_MODE);
243
203
  }
244
- const routeMarkerDir = join(staging, "package", ".synopkgland");
245
- mkdirSync(routeMarkerDir, { recursive: true });
246
- const routeMarker = join(routeMarkerDir, "route");
247
- writeFileSync(routeMarker, "package-only", "utf8");
248
- chmodSync(routeMarker, FILE_MODE);
249
204
  }
250
205
  const htmlDir = join(options.project.root, "html");
251
206
  if (existsSync(htmlDir)) {
@@ -254,12 +209,6 @@ export async function buildSpk(options) {
254
209
  cpSync(htmlDir, join(staging, "package", "compose", "html"), { recursive: true });
255
210
  }
256
211
  }
257
- if (options.embeddedAttestationToken !== undefined) {
258
- const attestationPath = join(staging, "package", EMBEDDED_ATTESTATION_RELATIVE_PATH);
259
- mkdirSync(join(staging, "package", ".synopkgland"), { recursive: true });
260
- writeFileSync(attestationPath, options.embeddedAttestationToken, "utf8");
261
- chmodSync(attestationPath, FILE_MODE);
262
- }
263
212
  if (contract.adminport !== undefined && resolvedWebLaunch(contract) === "dsm-window") {
264
213
  const uiDir = join(staging, "package", "ui");
265
214
  mkdirSync(uiDir, { recursive: true });
@@ -277,6 +226,7 @@ export async function buildSpk(options) {
277
226
  chmodSync(join(staging, "package", "ui", "config"), FILE_MODE);
278
227
  }
279
228
  const outputPath = options.outputPath ?? join(options.project.root, `${String(contract.package)}.spk`);
229
+ copyProjectNotices(options.project.root, join(staging, 'package'));
280
230
  await createDeterministicSpk(staging, outputPath);
281
231
  return { ok: true, outputPath, errors: [] };
282
232
  }
@@ -312,12 +262,6 @@ function renderInfo(contract, archFamily, isResourceWorker = false) {
312
262
  add("install_dep_packages", "WebStation");
313
263
  }
314
264
  }
315
- else {
316
- // synopkg's Container Manager dep gate reports "not ready" even when CM is
317
- // running. Depend on Broker only; Broker's adapter.probe() checks CM at
318
- // App install time (CM_CAPABILITY_MISSING).
319
- add("install_dep_packages", "SynoPkgLandService>=0.1.0-0016");
320
- }
321
265
  add("startable", "yes");
322
266
  const launch = resolvedWebLaunch(contract);
323
267
  if (contract.adminprotocol) {
@@ -354,47 +298,15 @@ function renderPrivilege() {
354
298
  },
355
299
  }, null, 2)}\n`;
356
300
  }
357
- const SHARED_FOLDER_MOUNT_CONSENT = "此 App 會用你在這台 NAS 選的資料夾;整顆應用都看得到。Shared Folder Mount 是整個 App Instance 的 container access:能打開這個 App 的使用者,容器裡的程式都看得到該 Share,即使該使用者在 File Station 看不到。這不是逐使用者 DSM ACL。要依登入者權限讀寫 NAS 檔案,必須另外核准廣域 files.* 並走 File Gateway。";
358
- const HOMES_MOUNT_CONSENT = "此 App 會使用這台 NAS 已啟用的 User Home;整顆應用的容器都看得到,容器路徑由 Compose 決定。這不是逐使用者 DSM ACL;要依登入者權限讀寫 NAS 檔案,必須另外核准廣域 files.* 並走 File Gateway。";
359
- const POSIX_ALL_SHARES_MAX_WARNING = "掛載這台 NAS 目前列出的每一個共用資料夾。容器內可讀(或讀寫,依 Compose 模式)所有這些資料夾的檔案。安裝後新建的共用資料夾不會自動加入。由管理員決定是否安裝。";
301
+ const SHARED_FOLDER_MOUNT_CONSENT = "此 App 會用你在這台 NAS 選的資料夾;整顆應用都看得到。Shared Folder Mount 是整個 App Instance 的 container access:能打開這個 App 的使用者,容器裡的程式都看得到該 Share,即使該使用者在 File Station 看不到。這不是逐使用者 DSM ACL。檔案權限取決於容器服務帳號;App 必須自行實作使用者授權。";
302
+ const HOMES_MOUNT_CONSENT = "此 App 會使用這台 NAS 已啟用的 User Home;整顆應用的容器都看得到,容器路徑由 Compose 決定。這不是逐使用者 DSM ACL;檔案權限取決於容器服務帳號;App 必須自行實作使用者授權。";
303
+ const POSIX_ALL_SHARES_MAX_WARNING = "此 App 會使用安裝當下這台 NAS 的全部 Shared Folder(App-wide,不依個別 DSM ACL);容器內可讀(或讀寫,依 Compose 模式)所有這些資料夾的檔案。安裝後新建的共用資料夾不會自動加入。Package Center 無法提供安裝當下的 Shared Folder 清單快照;要以全部 Share 安裝,請用 CLI `synopkgland deploy`,由 CLI 以管理員權限列舉全部 Share 並寫入快照。由管理員決定是否安裝。";
304
+ const POSIX_ALL_SHARES_UPGRADE_NOTICE = "升級會保留既有快照(安裝當下由 CLI 列舉的全部 Shared Folder);變更掛載範圍只能由 CLI 明確提供(`synopkgland deploy`)。Package Center 升級不會改動現有快照。";
360
305
  const DSM_USER_RUN_AS_CONSENT = "寫進 Share 的新檔在 File Station 顯示為你選的那位 DSM 使用者。點開此 App 的人共用這個磁碟身分,不是逐登入 ACL。";
361
306
  const DSM_USER_UPGRADE_CONSENT = "升級時更換 Container Run-as 不會 chown Share 上的舊檔;只有升級後寫入的新檔才會使用新的磁碟身分。";
307
+ const UPGRADE_VALUE_REUSE_DESC = "留空=沿用目前設定";
362
308
  const SHARED_FOLDER_RW_UPGRADE_CONSENT = "此版本把 Share 掛載改為讀寫;容器可讀取並寫入你選的 Share,不再是唯讀。";
363
309
  const APP_OWN_SPACE_CONSENT = "此 App 只用 App 自己的空間。";
364
- const OIDC_COMPAT_CONSENT = "此 App 可用你的 DSM 帳號登入;如果這台 NAS 尚未啟用相容模式,App 會使用自己的登入。登入不等於 File Station ACL。";
365
- function hasOidcCompat(contract) {
366
- const integration = contract.integration;
367
- if (!integration || typeof integration !== "object") {
368
- return false;
369
- }
370
- const identity = integration.identity;
371
- if (!identity || typeof identity !== "object") {
372
- return false;
373
- }
374
- const oidcCompat = identity.oidc_compat;
375
- return Boolean(oidcCompat && typeof oidcCompat === "object");
376
- }
377
- function renderFilesCapability(contract) {
378
- const permissions = contract.permissions;
379
- const files = permissions?.files;
380
- if (!files) {
381
- return null;
382
- }
383
- const parts = [];
384
- if (files.read) {
385
- parts.push("讀取檔案");
386
- }
387
- if (files.write) {
388
- parts.push("寫入檔案");
389
- }
390
- if (files.delete) {
391
- parts.push("刪除檔案");
392
- }
393
- if (parts.length === 0) {
394
- return null;
395
- }
396
- return `此 App 需要以下檔案能力:${parts.join("、")}。這是每位登入者的 DSM ACL,經 File Gateway。`;
397
- }
398
310
  function volumeSources(compose) {
399
311
  return volumeMounts(compose).map((mount) => mount.source);
400
312
  }
@@ -484,17 +396,11 @@ function renderInstallWizard(contract, compose) {
484
396
  const hasSharedFolder = params.some((item) => item.param.type === "shared_folder");
485
397
  const hasHomes = params.some((item) => item.param.type === "homes");
486
398
  const hasDsmUser = params.some((item) => item.param.type === "dsm_user");
487
- const capabilityText = renderFilesCapability(contract);
488
399
  if (compose && scanComposePrivilege(compose).length > 0) {
489
400
  items.push({
490
401
  desc: PRIVILEGE_MAX_WARNING,
491
402
  });
492
403
  }
493
- if (hasOidcCompat(contract)) {
494
- items.push({
495
- desc: OIDC_COMPAT_CONSENT,
496
- });
497
- }
498
404
  if (hasSharedFolder) {
499
405
  items.push({
500
406
  desc: SHARED_FOLDER_MOUNT_CONSENT,
@@ -510,15 +416,7 @@ function renderInstallWizard(contract, compose) {
510
416
  desc: DSM_USER_RUN_AS_CONSENT,
511
417
  });
512
418
  }
513
- if (capabilityText) {
514
- items.push({
515
- desc: capabilityText,
516
- });
517
- }
518
- // No compose at all is the native branch: the binary gets PKGVAR and nothing
519
- // else, so it earns the same line. Requiring a compose left native wizards
520
- // empty, which DSM rejects as an invalid package.
521
- if (!hasSharedFolder && !capabilityText && (!compose || composeUsesOnlyAppSpace(compose))) {
419
+ if (!hasSharedFolder && (!compose || composeUsesOnlyAppSpace(compose))) {
522
420
  items.push({
523
421
  desc: APP_OWN_SPACE_CONSENT,
524
422
  });
@@ -584,36 +482,19 @@ function renderInstallWizard(contract, compose) {
584
482
  continue;
585
483
  }
586
484
  if (param.type === "posix_all_shares") {
485
+ // A47 (install side): DSM's declarative wizard only ever renders a
486
+ // single-select combo here, so the former multiSelect control silently
487
+ // mounted exactly one Share instead of every Share. Package Center can
488
+ // therefore never carry the full Share list, and there is no honest
489
+ // control to render -- so this branch produces only an informational
490
+ // textblock. The full snapshot arrives exclusively via CLI
491
+ // extra_values (`synopkgland deploy`), which the preinst materializer
492
+ // expands. No subitem key is emitted, so the install uifile contains no
493
+ // ALL_SHARES and no CHANGE_ALL_SHARES.
587
494
  items.push({
588
495
  type: "textblock",
589
496
  desc: POSIX_ALL_SHARES_MAX_WARNING,
590
497
  });
591
- items.push({
592
- type: "combobox",
593
- multiSelect: true,
594
- desc: `POSIX all shares: ${name}`,
595
- subitems: [{
596
- key: name,
597
- desc: name,
598
- displayField: "name",
599
- valueField: "name",
600
- multiSelect: true,
601
- editable: false,
602
- forceSelection: true,
603
- autoSelect: false,
604
- mode: "remote",
605
- api_store: {
606
- api: "SYNO.Core.Share",
607
- method: "list",
608
- version: 1,
609
- baseParams: { limit: -1, offset: 0 },
610
- root: "shares",
611
- idProperty: "name",
612
- fields: ["name"],
613
- },
614
- validator: { allowBlank: false },
615
- }],
616
- });
617
498
  continue;
618
499
  }
619
500
  if (param.type === "dsm_user") {
@@ -651,6 +532,75 @@ function renderInstallWizard(contract, compose) {
651
532
  function renderUpgradeWizard(contract, compose) {
652
533
  const installWizard = renderInstallWizard(contract, compose);
653
534
  const params = collectInstallParameters(contract);
535
+ // Every type whose value must survive an upgrade the administrator did not
536
+ // deliberately change. Two mechanisms are needed because DSM renders them
537
+ // differently: a control that can be left blank just allows blank, while one
538
+ // that always carries a value needs an explicit "change this" gate.
539
+ // - dsm_user : measurably comes up blank, so allowBlank is enough
540
+ // - string : blank once the new version's default is withheld (A44)
541
+ // - shared_folder : DSM prefills the first store row
542
+ // - boolean : a checkbox has no blank state at all
543
+ // posix_all_shares is intentionally absent: it renders as a textblock with
544
+ // no subitem, so there is nothing to blank or gate on the upgrade wizard.
545
+ // Its value can only arrive via CLI extra_values, and the preinst
546
+ // change-gate shell (`upgrade_change_enabled`, `CHANGE_<name>`) still
547
+ // governs that path, reusing the canonical snapshot on an untouched upgrade.
548
+ const upgradeReuseTypes = new Map(params
549
+ .filter(({ param }) => param.type === "shared_folder" ||
550
+ param.type === "dsm_user" ||
551
+ param.type === "string" ||
552
+ param.type === "boolean")
553
+ .map(({ name, param }) => [name, param.type]));
554
+ const needsChangeGate = (type) => type === "shared_folder" || type === "boolean";
555
+ const upgradeItems = installWizard[0].items.flatMap((item) => {
556
+ if (!Array.isArray(item.subitems)) {
557
+ return [item];
558
+ }
559
+ const reuseKeys = [];
560
+ const subitems = item.subitems.map((subitem) => {
561
+ if (!subitem || typeof subitem !== "object") {
562
+ return subitem;
563
+ }
564
+ const record = subitem;
565
+ if (typeof record.key !== "string" || !upgradeReuseTypes.has(record.key)) {
566
+ return subitem;
567
+ }
568
+ reuseKeys.push(record.key);
569
+ const reused = {
570
+ ...record,
571
+ validator: { allowBlank: true },
572
+ };
573
+ // Withholding the default is what makes an untouched upgrade blank, and
574
+ // blank is what lets preinst fall through to the canonical .env value.
575
+ // Install keeps the default -- only this upgrade copy drops it.
576
+ delete reused.defaultValue;
577
+ return reused;
578
+ });
579
+ if (reuseKeys.length === 0) {
580
+ return [item];
581
+ }
582
+ const control = {
583
+ ...item,
584
+ desc: `${String(item.desc ?? "")}(${UPGRADE_VALUE_REUSE_DESC})`,
585
+ subitems,
586
+ };
587
+ const changeControls = reuseKeys
588
+ .filter((key) => needsChangeGate(upgradeReuseTypes.get(key)))
589
+ .map((key) => {
590
+ const type = upgradeReuseTypes.get(key);
591
+ const label = type === "shared_folder" ? "Shared Folder" : key;
592
+ return {
593
+ type: "multiselect",
594
+ desc: `變更 ${label}(不勾=沿用目前設定)`,
595
+ subitems: [{
596
+ key: `CHANGE_${key}`,
597
+ desc: `變更 ${label}`,
598
+ defaultValue: false,
599
+ }],
600
+ };
601
+ });
602
+ return [...changeControls, control];
603
+ });
654
604
  const sharedFolderNames = params
655
605
  .filter((item) => item.param.type === "shared_folder")
656
606
  .map((item) => item.name);
@@ -661,6 +611,14 @@ function renderUpgradeWizard(contract, compose) {
661
611
  volumeMounts(compose).some((mount) => !mount.readOnly &&
662
612
  sharedFolderNames.some((name) => mount.source === `\${${name}}` || mount.source.startsWith(`\${${name}}/`)));
663
613
  const upgradeConsent = [];
614
+ const posixAllSharesNames = params
615
+ .filter((item) => item.param.type === "posix_all_shares")
616
+ .map((item) => item.name);
617
+ if (posixAllSharesNames.length > 0) {
618
+ upgradeConsent.push({
619
+ desc: POSIX_ALL_SHARES_UPGRADE_NOTICE,
620
+ });
621
+ }
664
622
  if (hasReadWriteSharedFolder) {
665
623
  upgradeConsent.push({
666
624
  desc: SHARED_FOLDER_RW_UPGRADE_CONSENT,
@@ -675,11 +633,12 @@ function renderUpgradeWizard(contract, compose) {
675
633
  return [{
676
634
  ...installWizard[0],
677
635
  step_title: "升級設定",
636
+ items: upgradeItems,
678
637
  }];
679
638
  }
680
- const firstControl = installWizard[0].items.findIndex((item) => item.subitems !== undefined);
681
- const insertAt = firstControl === -1 ? installWizard[0].items.length : firstControl;
682
- const items = [...installWizard[0].items];
639
+ const firstControl = upgradeItems.findIndex((item) => item.subitems !== undefined);
640
+ const insertAt = firstControl === -1 ? upgradeItems.length : firstControl;
641
+ const items = [...upgradeItems];
683
642
  items.splice(insertAt, 0, ...upgradeConsent);
684
643
  return [{
685
644
  ...installWizard[0],
@@ -708,7 +667,6 @@ function renderUninstallWizard() {
708
667
  ],
709
668
  }];
710
669
  }
711
- const LEGACY_BROKER_STATE_REGISTRY_CODE = "COMPOSE_LEGACY_BROKER_STATE_PRESENT";
712
670
  function renderDynamicPreinstMaterializer(contract) {
713
671
  const allParams = collectInstallParameters(contract);
714
672
  const scalarParams = allParams.filter(({ param }) => param.type === "string" || param.type === "boolean");
@@ -721,18 +679,6 @@ function renderDynamicPreinstMaterializer(contract) {
721
679
  "umask 077",
722
680
  "# D3/D5.4 package-only carrier; values are wizard answers, canonical values, or defaults.",
723
681
  "die() { echo \"dynamic route materialization failed: $1\" >&2; exit 1; }",
724
- `# registry-code="${LEGACY_BROKER_STATE_REGISTRY_CODE}"`,
725
- 'APPDATA="${SYNOPKG_PKGDEST_VOL:?}/@appdata/${SYNOPKG_PKGNAME:?}"',
726
- 'if [ -d "$APPDATA" ]; then',
727
- ' broker_uid="$(id -u SynoPkgLandService 2>/dev/null || true)"',
728
- ' if [ -n "$broker_uid" ]; then',
729
- ' for item in "$APPDATA"/* "$APPDATA"/.[!.]* "$APPDATA"/..?*; do',
730
- ' [ -e "$item" ] || continue',
731
- ' item_uid="$(stat -c %u "$item" 2>/dev/null || true)"',
732
- ' [ "$item_uid" = "$broker_uid" ] && die "MIGRATION_UNSUPPORTED: ${SYNOPKG_PKGNAME} 曾由 Broker installer 安裝;dynamic 路線不支援就地遷移,請以新的 Package Identity 安裝或先完整卸載並清除 App Data"',
733
- " done",
734
- " fi",
735
- "fi",
736
682
  'T="${SYNOPKG_PKGINST_TEMP_DIR:?}"',
737
683
  'STATUS="${SYNOPKG_PKG_STATUS:?}"',
738
684
  'PROJECT="$T/compose"',
@@ -776,6 +722,16 @@ function renderDynamicPreinstMaterializer(contract) {
776
722
  " esac",
777
723
  "}",
778
724
  ];
725
+ // Emitted whenever anything reads a CHANGE_ gate. Boolean parameters (A44) use
726
+ // it too, and a package with only booleans has no Share resolvers -- leaving it
727
+ // behind that condition made `! upgrade_change_enabled ...` a missing command,
728
+ // which is true, so the gate silently always reused the canonical value.
729
+ const usesUpgradeChangeGate = sharedFolderParams.length > 0 ||
730
+ posixAllSharesParams.length > 0 ||
731
+ collectInstallParameters(contract).some(({ param }) => param.type === "boolean");
732
+ if (usesUpgradeChangeGate) {
733
+ lines.push("upgrade_change_enabled() {", " normalized=\"$(printf '%s' \"$1\" | LC_ALL=C tr '[:upper:]' '[:lower:]')\"", " case \"$normalized\" in", " true|1|yes|on) return 0 ;;", " *) return 1 ;;", " esac", "}");
734
+ }
779
735
  if (sharedFolderParams.length > 0 || posixAllSharesParams.length > 0) {
780
736
  lines.push("resolve_shared_folder() {", " share_name=\"$1\"", " case \"$share_name\" in", " */*|*..*) die \"invalid share name $share_name\" ;;", " '') die \"share name is empty\" ;;", " esac", " mounts_file=\"${D54_MOUNTS_FILE:-/proc/mounts}\"", " if [ ! -r \"$mounts_file\" ] && [ -r \"/etc/mtab\" ]; then", " mounts_file=\"/etc/mtab\"", " fi", " if [ ! -r \"$mounts_file\" ]; then", " die \"cannot read mount points from $mounts_file\"", " fi", " vols=\"$(awk '$2 ~ /^\\/volume[0-9]+$/ {print $2}' \"$mounts_file\" | sort -u)\"", ' if [ -z "$vols" ]; then', " vols=\"$(awk '{print $2}' \"$mounts_file\" | sort -u)\"", " fi", " matched=\"\"", " count=0", " for v in $vols; do", " if [ -d \"$v/$share_name\" ]; then", " matched=\"$v/$share_name\"", " count=$((count + 1))", " fi", " done", " if [ \"$count\" -eq 0 ]; then", " die \"share $share_name not found on any volume\"", " elif [ \"$count\" -gt 1 ]; then", " die \"share $share_name matched multiple volumes\"", " fi", " printf '%s' \"$matched\"", "}");
781
737
  }
@@ -785,14 +741,6 @@ function renderDynamicPreinstMaterializer(contract) {
785
741
  if (dsmUserParam) {
786
742
  lines.push("resolve_dsm_user() {", " user_name=\"$1\"", " case \"$user_name\" in", " */*|*..*|*[[:cntrl:]]*) die \"invalid user name $user_name\" ;;", " '') die \"user name is empty\" ;;", " esac", " u_uid=\"$(id -u -- \"$user_name\" 2>/dev/null || true)\"", " case \"$u_uid\" in", " ''|*[!0-9]*) die \"resolved uid for $user_name is not a valid integer\" ;;", " 0) die \"resolved uid for $user_name cannot be 0 (root)\" ;;", " esac", " u_gid=\"$(id -g -- \"$user_name\" 2>/dev/null || true)\"", " case \"$u_gid\" in", " ''|*[!0-9]*) die \"resolved gid for $user_name is not a valid integer\" ;;", " esac", " # id -G returns all group ids including primary", " raw_groups=\"$(id -G -- \"$user_name\" 2>/dev/null || true)\"", " # filter out primary gid, deduplicate, keep numeric only", " supp_groups=\"\"", " for g in $raw_groups; do", " case \"$g\" in", " ''|*[!0-9]*) continue ;;", " esac", " if [ \"$g\" != \"$u_gid\" ]; then", " already=0", " for sg in $supp_groups; do", " if [ \"$sg\" = \"$g\" ]; then", " already=1", " break", " fi", " done", " if [ \"$already\" -eq 0 ]; then", " supp_groups=\"${supp_groups}${supp_groups:+ }$g\"", " fi", " fi", " done", " printf '%s %s %s' \"$u_uid\" \"$u_gid\" \"$supp_groups\"", "}", "rewrite_group_add() {", " p_name=\"$1\"", " g_list=\"$2\"", " compose_file=\"$3\"", " [ -f \"$compose_file\" ] || die \"compose file missing at $compose_file\"", " [ ! -L \"$compose_file\" ] || die \"compose file is a symlink\"", " tmp_compose=\"$(mktemp \"${compose_file}.tmp.XXXXXX\")\"", " awk -v param=\"$p_name\" -v g_list=\"$g_list\" '", " BEGIN {", " n = split(g_list, g_arr, \" \")", " }", " {", " regex = \"^[ \\t]*# synopkgland:group_add \" param \"$\"", " if ($0 ~ regex) {", " match($0, /^[ \\t]*/)", " indent = substr($0, RSTART, RLENGTH)", " if (n > 0) {", " print indent \"group_add:\"", " for (i = 1; i <= n; i++) {", " print indent \" - ${\" param \"_GROUP_\" i \"}\"", " }", " }", " } else {", " print $0", " }", " }", " ' \"$compose_file\" > \"$tmp_compose\" || die \"failed to rewrite group_add in $compose_file\"", " mv \"$tmp_compose\" \"$compose_file\" || die \"failed to replace $compose_file\"", "}");
787
743
  }
788
- if (hasOidcCompat(contract)) {
789
- const identity = contract.integration?.identity;
790
- const redirectPath = identity?.oidc_compat?.redirect_path ?? "";
791
- const adminProtocol = contract.adminprotocol ?? "http";
792
- const adminPort = Number(contract.adminport ?? 0);
793
- const escapedRedirectPath = redirectPath.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
794
- lines.push("oidc_register() {", " # DSM compose does not create missing bind sources: the secrets dir must exist even when compat is off.", " (umask 077 && mkdir -p \"$PROJECT/secrets\" && chmod 700 \"$PROJECT/secrets\") || die \"failed to create $PROJECT/secrets\"", " OIDC_ISSUER=\"\"", " OIDC_ISSUER_HOST=\"oidc.invalid\"", " OIDC_CLIENT_ID=\"\"", " OIDC_CLIENT_SECRET=\"\"", " identity_file=\"${SYNOPKGLAND_IDENTITY_FILE:-/var/packages/SynoPkgLandService/var/identity.json}\"", " if [ ! -r \"$identity_file\" ]; then", " identity_file=\"/volume1/@appdata/SynoPkgLandService/identity.json\"", " fi", " if [ ! -r \"$identity_file\" ]; then", " # Identity endpoint not found -> Broker not installed -> skip as 404", " rm -f \"$PROJECT/secrets/SYNOPKGLAND_OIDC_CLIENT_SECRET\"", " return 0", " fi", " base_url=\"$(python3 -c 'import json, sys; data=json.load(open(sys.argv[1])); print(data.get(\"baseUrl\", \"\"))' \"$identity_file\" 2>/dev/null || true)\"", " if [ -z \"$base_url\" ]; then", " rm -f \"$PROJECT/secrets/SYNOPKGLAND_OIDC_CLIENT_SECRET\"", " return 0", " fi", " attestation_file=\"$T/.synopkgland/attestation.jwt\"", " if [ ! -f \"$attestation_file\" ]; then", " rm -f \"$PROJECT/secrets/SYNOPKGLAND_OIDC_CLIENT_SECRET\"", " return 0", " fi", " attestation_token=\"$(cat \"$attestation_file\")\"", " phase=\"install\"", " case \"$STATUS\" in", " UPGRADE) phase=\"upgrade\" ;;", " *) phase=\"install\" ;;", " esac", " req_body=\"$(python3 -c 'import json, sys; print(json.dumps({\"protocolVersion\": 1, \"attestation\": sys.argv[1], \"packageIdentity\": sys.argv[2], \"packageVersion\": sys.argv[3], \"redirectPath\": sys.argv[4], \"adminProtocol\": sys.argv[5], \"adminPort\": int(sys.argv[6]), \"phase\": sys.argv[7]}))' \"$attestation_token\" \"${SYNOPKG_PKGNAME:?}\" \"${SYNOPKG_PKGVER:?}\" \"" + escapedRedirectPath + "\" \"" + String(adminProtocol) + "\" \"" + String(adminPort) + "\" \"$phase\")\"", " resp_file=\"$(mktemp \"$T/oidc_resp.XXXXXX\")\"", " http_code=\"$(curl -s -S --connect-timeout 5 --max-time 30 -o \"$resp_file\" -w '%{http_code}' -X POST -H 'Content-Type: application/json' --data-binary \"$req_body\" \"${base_url}/internal/v1/oidc/register\" 2>/dev/null || true)\"", " case \"$http_code\" in [0-9][0-9][0-9]) ;; *) http_code=\"000\" ;; esac", " if [ \"$http_code\" = \"200\" ]; then", " parsed_res=\"$(python3 -c 'import json, sys; d=json.load(open(sys.argv[1])); print(d.get(\"issuer\", \"\")); print(d.get(\"issuerHost\", \"\")); print(d.get(\"clientId\", \"\")); print(d.get(\"clientSecret\", \"\"))' \"$resp_file\" 2>/dev/null || true)\"", " rm -f \"$resp_file\"", " OIDC_ISSUER=\"$(printf '%s\\n' \"$parsed_res\" | sed -n '1p')\"", " OIDC_ISSUER_HOST=\"$(printf '%s\\n' \"$parsed_res\" | sed -n '2p')\"", " OIDC_CLIENT_ID=\"$(printf '%s\\n' \"$parsed_res\" | sed -n '3p')\"", " OIDC_CLIENT_SECRET=\"$(printf '%s\\n' \"$parsed_res\" | sed -n '4p')\"", " (umask 077 && mkdir -p \"$PROJECT/secrets\" && printf '%s' \"$OIDC_CLIENT_SECRET\" > \"$PROJECT/secrets/SYNOPKGLAND_OIDC_CLIENT_SECRET\")", " elif [ \"$http_code\" = \"404\" ] || [ \"$http_code\" = \"000\" ]; then", " rm -f \"$resp_file\"", " rm -f \"$PROJECT/secrets/SYNOPKGLAND_OIDC_CLIENT_SECRET\"", " OIDC_ISSUER=\"\"", " OIDC_ISSUER_HOST=\"oidc.invalid\"", " OIDC_CLIENT_ID=\"\"", " else", " rm -f \"$resp_file\"", " die \"OIDC_REGISTER_FAILED $http_code\"", " fi", "}", "oidc_register");
795
- }
796
744
  lines.push('tmp="$(mktemp "$PROJECT/.env.tmp.XXXXXX")"', 'chmod 600 "$tmp"', '[ "$(stat -c %a "$tmp")" = "600" ] || die "temporary env mode is not 0600"', '[ "$(stat -c %u "$tmp")" = "$(id -u)" ] || die "temporary env owner is not the package user"', "trap 'rm -f \"$tmp\"' EXIT HUP INT TERM", "{");
797
745
  const valueVars = [];
798
746
  for (const { name, param } of scalarParams) {
@@ -804,16 +752,27 @@ function renderDynamicPreinstMaterializer(contract) {
804
752
  : type === "boolean"
805
753
  ? "false"
806
754
  : "";
807
- lines.push(` if [ "\${${name}+x}" = x ]; then`, ` ${valueVar}="\${${name}}"`, ' elif [ "$STATUS" = "UPGRADE" ] && [ -f "$CANONICAL_ENV" ] && [ ! -L "$CANONICAL_ENV" ] && ' +
755
+ // A44: on UPGRADE the wizard always submits something for these controls, so
756
+ // "was it submitted" cannot mean "did the administrator choose it". A blank
757
+ // string, or a boolean whose CHANGE_ gate is unchecked, means "keep what is
758
+ // installed" -- otherwise the new version's default would silently replace a
759
+ // value chosen at install time. INSTALL is unaffected: STATUS is not UPGRADE,
760
+ // so the reuse branch is skipped and the default still applies.
761
+ const reuseGuard = type === "boolean"
762
+ ? `! upgrade_change_enabled "\${CHANGE_${name}:-}"`
763
+ : `[ -z "\${${name}:-}" ]`;
764
+ lines.push(` if [ "$STATUS" = "UPGRADE" ] && ${reuseGuard} && [ -f "$CANONICAL_ENV" ] && ` +
765
+ `[ ! -L "$CANONICAL_ENV" ] && ${valueVar}="$(read_env_value "$CANONICAL_ENV" "${name}")"; then`, " :", ` elif [ "\${${name}+x}" = x ]; then`, ` ${valueVar}="\${${name}}"`, ' elif [ "$STATUS" = "UPGRADE" ] && [ -f "$CANONICAL_ENV" ] && [ ! -L "$CANONICAL_ENV" ] && ' +
808
766
  `${valueVar}="$(read_env_value "$CANONICAL_ENV" "${name}")"; then`, " :", " else", " " + valueVar + "=" + shellQuote(fallback), " fi");
809
767
  }
810
768
  const shareVars = [];
811
769
  for (const { name } of sharedFolderParams) {
812
770
  const rawVar = "D54_RAW_SHARE_" + name;
813
771
  const pathVar = "D54_RESOLVED_PATH_" + name;
772
+ const changeVar = "CHANGE_" + name;
814
773
  shareVars.push({ name, pathVar });
815
- lines.push(` if [ "\${${name}+x}" = x ]; then`, ` ${rawVar}="\${${name}}"`, ' elif [ "$STATUS" = "UPGRADE" ] && [ -f "$CANONICAL_ENV" ] && [ ! -L "$CANONICAL_ENV" ] && ' +
816
- `${rawVar}="$(read_env_value "$CANONICAL_ENV" "${name}")"; then`, " :", " else", ` die "missing required shared folder parameter ${name}"`, " fi", ` case "$${rawVar}" in`, " /*) " + pathVar + "=\"$" + rawVar + "\" ;;", " *) " + pathVar + "=\"$(resolve_shared_folder \"$" + rawVar + "\")\" ;;", " esac");
774
+ lines.push(` if [ "$STATUS" = "UPGRADE" ] && upgrade_change_enabled "\${${changeVar}:-}"; then`, ` if [ "\${${name}+x}" = x ] && [ -n "\${${name}}" ]; then`, ` ${rawVar}="\${${name}}"`, " else", ` die "missing required shared folder parameter ${name}"`, " fi", ' elif [ "$STATUS" = "UPGRADE" ] && [ -f "$CANONICAL_ENV" ] && [ ! -L "$CANONICAL_ENV" ] && ' +
775
+ `${rawVar}="$(read_env_value "$CANONICAL_ENV" "${name}")"; then`, " :", ' elif [ "$STATUS" = "UPGRADE" ]; then', ` die "missing canonical shared folder parameter ${name}"`, ` elif [ "\${${name}+x}" = x ]; then`, ` ${rawVar}="\${${name}}"`, " else", ` die "missing required shared folder parameter ${name}"`, " fi", ` case "$${rawVar}" in`, " /*) " + pathVar + "=\"$" + rawVar + "\" ;;", " *) " + pathVar + "=\"$(resolve_shared_folder \"$" + rawVar + "\")\" ;;", " esac");
817
776
  }
818
777
  const posixVars = [];
819
778
  for (const { name } of posixAllSharesParams) {
@@ -821,22 +780,18 @@ function renderDynamicPreinstMaterializer(contract) {
821
780
  const namesVar = "D54_POSIX_NAMES_" + name;
822
781
  const pathsVar = "D54_POSIX_PATHS_" + name;
823
782
  const countVar = "D54_POSIX_COUNT_" + name;
783
+ const changeVar = "CHANGE_" + name;
824
784
  posixVars.push({ name, namesVar, pathsVar, countVar });
825
- lines.push(` if [ "\${${name}+x}" = x ]; then`, ` ${rawVar}="\${${name}}"`, ' elif [ "$STATUS" = "UPGRADE" ] && [ -f "$CANONICAL_ENV" ] && [ ! -L "$CANONICAL_ENV" ] && ' +
826
- `${rawVar}="$(read_env_value "$CANONICAL_ENV" "${name}")"; then`, " :", " else", ` die "missing required POSIX all-shares parameter ${name}"`, " fi", ` posix_info="$(resolve_posix_all_shares "$${rawVar}")"`, ` ${namesVar}="$(printf '%s\\n' "$posix_info" | sed -n '1p')"`, ` ${pathsVar}="$(printf '%s\\n' "$posix_info" | sed -n '2p')"`, ` ${countVar}="$(printf '%s\\n' "$posix_info" | sed -n '3p')"`, ` rewrite_posix_all_shares "${name}" "$${namesVar}" "$${pathsVar}" "$PROJECT/docker-compose.yml"`);
785
+ lines.push(` if [ "$STATUS" = "UPGRADE" ] && upgrade_change_enabled "\${${changeVar}:-}"; then`, ` if [ "\${${name}+x}" = x ] && [ -n "\${${name}}" ]; then`, ` ${rawVar}="\${${name}}"`, " else", ` die "missing required POSIX all-shares parameter ${name}"`, " fi", ' elif [ "$STATUS" = "UPGRADE" ] && [ -f "$CANONICAL_ENV" ] && [ ! -L "$CANONICAL_ENV" ] && ' +
786
+ `${rawVar}="$(read_env_value "$CANONICAL_ENV" "${name}")"; then`, " :", ' elif [ "$STATUS" = "UPGRADE" ]; then', ` die "missing canonical POSIX all-shares parameter ${name}"`, ` elif [ "\${${name}+x}" = x ]; then`, ` ${rawVar}="\${${name}}"`, " else", ` die "missing required POSIX all-shares parameter ${name}"`, " fi", ` posix_info="$(resolve_posix_all_shares "$${rawVar}")"`, ` ${namesVar}="$(printf '%s\\n' "$posix_info" | sed -n '1p')"`, ` ${pathsVar}="$(printf '%s\\n' "$posix_info" | sed -n '2p')"`, ` ${countVar}="$(printf '%s\\n' "$posix_info" | sed -n '3p')"`, ` rewrite_posix_all_shares "${name}" "$${namesVar}" "$${pathsVar}" "$PROJECT/docker-compose.yml"`);
827
787
  }
828
788
  if (dsmUserParam) {
829
789
  const name = dsmUserParam.name;
830
790
  const rawUserVar = "D54_RAW_USER_" + name;
831
- lines.push(` if [ "\${${name}+x}" = x ]; then`, ` ${rawUserVar}="\${${name}}"`, ' elif [ "$STATUS" = "UPGRADE" ] && [ -f "$CANONICAL_ENV" ] && [ ! -L "$CANONICAL_ENV" ] && ' +
832
- `${rawUserVar}="$(read_env_value "$CANONICAL_ENV" "${name}")"; then`, " :", " else", ` die "missing required dsm user parameter ${name}"`, " fi", ` resolved_user_info="$(resolve_dsm_user "$${rawUserVar}")"`, " set -- $resolved_user_info", ` ${name}_UID="$1"`, ` ${name}_GID="$2"`, " shift 2 || true", ` ${name}_GROUPS="$*"`, ` rewrite_group_add "${name}" "$${name}_GROUPS" "$PROJECT/docker-compose.yml"`);
833
- }
834
- if (hasOidcCompat(contract)) {
835
- lines.push(' append_env "SYNOPKG_PKGVAR" "$PLATFORM_PKGVAR"', ' append_env "SYNO_APP_SECRETS_DIR" "${SYNOPKG_PKGDEST_VOL:?}/@appstore/${SYNOPKG_PKGNAME:?}/compose/secrets"', ' append_env "SYNOPKGLAND_OIDC_ISSUER" "$OIDC_ISSUER"', ' append_env "SYNOPKGLAND_OIDC_ISSUER_HOST" "$OIDC_ISSUER_HOST"', ' append_env "SYNOPKGLAND_OIDC_CLIENT_ID" "$OIDC_CLIENT_ID"');
836
- }
837
- else {
838
- lines.push(' append_env "SYNOPKG_PKGVAR" "$PLATFORM_PKGVAR"', ' append_env "SYNO_APP_SECRETS_DIR" "$PLATFORM_SECRETS"');
791
+ lines.push(` if [ "\${${name}+x}" = x ] && [ -n "\${${name}}" ]; then`, ` ${rawUserVar}="\${${name}}"`, ' elif [ "$STATUS" = "UPGRADE" ] && [ -f "$CANONICAL_ENV" ] && [ ! -L "$CANONICAL_ENV" ] && ' +
792
+ `${rawUserVar}="$(read_env_value "$CANONICAL_ENV" "${name}")"; then`, " :", ` elif [ "\${${name}+x}" = x ]; then`, ` ${rawUserVar}="\${${name}}"`, " else", ` die "missing required dsm user parameter ${name}"`, " fi", ` resolved_user_info="$(resolve_dsm_user "$${rawUserVar}")"`, " set -- $resolved_user_info", ` ${name}_UID="$1"`, ` ${name}_GID="$2"`, " shift 2 || true", ` ${name}_GROUPS="$*"`, ` rewrite_group_add "${name}" "$${name}_GROUPS" "$PROJECT/docker-compose.yml"`);
839
793
  }
794
+ lines.push(' append_env "SYNOPKG_PKGVAR" "$PLATFORM_PKGVAR"', ' append_env "SYNO_APP_SECRETS_DIR" "$PLATFORM_SECRETS"');
840
795
  for (const { name, valueVar, type } of valueVars) {
841
796
  lines.push(` append_env "${name}" "$${valueVar}" "${type}"`);
842
797
  }
@@ -910,29 +865,11 @@ function renderManagedScript(name, contract, nativeContext, isResourceWorker = f
910
865
  if (name === "start-stop-status") {
911
866
  return renderNativeStartStopStatus(lifecycleInput);
912
867
  }
913
- if (name === "preinst" || name === "preupgrade") {
914
- return BROKER_SOCKET_REQUIRED_SCRIPT;
915
- }
916
868
  if (name === "postinst" || name === "postupgrade") {
917
- const installerScript = renderInstallerCallScript(contract, name === "postupgrade" ? "update" : "install");
918
- // The service process needs its scratch directory before it can start,
919
- // and the installer call is the script's exit status, so widen the
920
- // existing mkdir rather than appending after it.
921
- return installerScript.replace('mkdir -p "${SYNOPKG_PKGVAR}" "${SYNOPKG_PKGHOME}/secrets"', 'mkdir -p "${SYNOPKG_PKGVAR}" "${SYNOPKG_PKGVAR}/tmp" "${SYNOPKG_PKGHOME}/secrets"');
869
+ return renderNativePostinst(lifecycleInput);
922
870
  }
923
871
  if (name === "preuninst") {
924
- // Compose installer uninstall (with UPGRADE early exit) + stop native process
925
- const installerScript = renderInstallerCallScript(contract, "uninstall").replace("set -eu\n", 'set -eu\nif [ "${SYNOPKG_PKG_STATUS:-}" = "UPGRADE" ]; then\n exit 0\nfi\n');
926
- // Stop the process BEFORE deregistering: `set -eu` aborts the script if
927
- // the installer fails, so a stop appended after it would never run. The
928
- // stop itself is best effort -- DSM already calls `start-stop-status
929
- // stop` directly (N0), and a non-zero preuninst blocks uninstall.
930
- const preuninstStopBlock = `CONTROL="/var/packages/\${SYNOPKG_PKGNAME:-${contract.package}}/scripts/start-stop-status"
931
- if [ -x "$CONTROL" ]; then
932
- "$CONTROL" stop 2>/dev/null || true
933
- fi
934
- `;
935
- return installerScript.replace('"$INSTALLER"', `${preuninstStopBlock}"$INSTALLER"`);
872
+ return renderNativePreuninst(lifecycleInput);
936
873
  }
937
874
  if (name === "postuninst") {
938
875
  return renderNativePostuninst(lifecycleInput);
@@ -967,93 +904,7 @@ ${projectRoot}${renderDeleteAppDataBlock(deleteRoots)}exit 0
967
904
  }
968
905
  return `#!/bin/sh\nexit 0\n`;
969
906
  }
970
- if (name === "start-stop-status") {
971
- return `#!/bin/sh
972
- ${BROKER_INSTALLER_VARS}
973
- case "$1" in
974
- start) exit 0 ;;
975
- stop) exit 0 ;;
976
- status)
977
- ${renderBrokerStatusProbe(String(contract.package))}
978
- exit 0
979
- ;;
980
- *) exit 1 ;;
981
- esac
982
- `;
983
- }
984
- if (name === "preinst" || name === "preupgrade") {
985
- return BROKER_SOCKET_REQUIRED_SCRIPT;
986
- }
987
- if (name === "postinst" || name === "postupgrade") {
988
- return renderInstallerCallScript(contract, name === "postupgrade" ? "update" : "install");
989
- }
990
- if (name === "preuninst") {
991
- return renderInstallerCallScript(contract, "uninstall").replace("set -eu\n", 'set -eu\nif [ "${SYNOPKG_PKG_STATUS:-}" = "UPGRADE" ]; then\n exit 0\nfi\n');
992
- }
993
- if (name === "postuninst") {
994
- return `#!/bin/sh
995
- set -eu
996
- PKGVAR="\${SYNOPKG_PKGVAR}"
997
- PKGHOME="\${SYNOPKG_PKGHOME}"
998
- SECRETS="\${PKGHOME}/secrets"
999
- ${renderDeleteAppDataBlock(["PKGVAR", "SECRETS"])}exit 0
1000
- `;
1001
- }
1002
- return `#!/bin/sh
1003
- exit 0
1004
- `;
1005
- }
1006
- function renderInstallerCallScript(contract, phase) {
1007
- const params = collectInstallParameters(contract);
1008
- const secrets = params.filter((item) => item.param.type === "secret");
1009
- const nonSecrets = params.filter((item) => item.param.type !== "secret");
1010
- const lines = [
1011
- "#!/bin/sh",
1012
- "set -eu",
1013
- 'INSTALLER="${BROKER_INSTALLER:-/var/packages/SynoPkgLandService/target/bin/synopkgland-installer}"',
1014
- 'SOCKET="${BROKER_SOCKET:-/var/packages/SynoPkgLandService/var/installer.sock}"',
1015
- `PACKAGE_ROOT="/var/packages/${contract.package}"`,
1016
- 'ATTEMPT_ID="${SYNOPKG_PKGNAME}-${SYNOPKG_PKGVER}-$$"',
1017
- 'WORK="$(mktemp -d /tmp/synopkgland-install.XXXXXX)"',
1018
- 'chmod 700 "$WORK"',
1019
- "cleanup() { rm -rf \"$WORK\"; }",
1020
- "trap cleanup EXIT",
1021
- 'mkdir -p "${SYNOPKG_PKGVAR}" "${SYNOPKG_PKGHOME}/secrets"',
1022
- 'chmod 770 "${SYNOPKG_PKGVAR}" "${SYNOPKG_PKGHOME}" "${SYNOPKG_PKGHOME}/secrets" 2>/dev/null || true',
1023
- 'chgrp synopkgs "${SYNOPKG_PKGVAR}" "${SYNOPKG_PKGHOME}" "${SYNOPKG_PKGHOME}/secrets" 2>/dev/null || true',
1024
- 'VARS=""',
1025
- 'SECRET_FILES=""',
1026
- ];
1027
- for (const { name, param } of secrets) {
1028
- if (param.generate === true) {
1029
- continue;
1030
- }
1031
- lines.push(`if [ -n "\${${name}+x}" ]; then`);
1032
- lines.push(" umask 077");
1033
- lines.push(` printf '%s' "\$${name}" > "$WORK/${name}"`);
1034
- lines.push(` unset ${name}`);
1035
- lines.push(` SECRET_FILES="$SECRET_FILES --secret-file ${name}=$WORK/${name}"`);
1036
- lines.push("fi");
1037
- }
1038
- for (const { name } of nonSecrets) {
1039
- lines.push(`if [ -n "\${${name}+x}" ]; then`);
1040
- lines.push(` VARS="$VARS --var ${name}=\$${name}"`);
1041
- lines.push("fi");
1042
- }
1043
- const generateFlags = secrets
1044
- .filter((item) => item.param.generate === true)
1045
- .map((item) => `--generate-secret ${item.name}`)
1046
- .join(" ");
1047
- lines.push(`"$INSTALLER" --socket "$SOCKET" --phase ${phase} --attempt-id "$ATTEMPT_ID" \\`);
1048
- lines.push(` --package-identity "${contract.package}" --package-version "\${SYNOPKG_PKGVER}" \\`);
1049
- lines.push(' --package-path "$PACKAGE_ROOT/target" --bundle-path "$PACKAGE_ROOT/target" \\');
1050
- lines.push(' --pkg-var "$PACKAGE_ROOT/var" --pkg-home "$PACKAGE_ROOT/home" \\');
1051
- if (generateFlags) {
1052
- lines.push(` ${generateFlags} \\`);
1053
- }
1054
- lines.push(' $VARS $SECRET_FILES');
1055
- lines.push("exit $?");
1056
- return `${lines.join("\n")}\n`;
907
+ throw new Error("Unsupported container route");
1057
908
  }
1058
909
  async function createDeterministicSpk(stagingDir, outputPath) {
1059
910
  const payloadDir = join(stagingDir, "package");