@synopackageland/cli 0.6.1 → 0.7.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 (640) hide show
  1. package/CHANGELOG.md +846 -0
  2. package/README.md +81 -89
  3. package/dist/add.d.ts +4 -1
  4. package/dist/add.js +45 -17
  5. package/dist/build-spk/delegate-scope.d.ts +6 -0
  6. package/dist/build-spk/delegate-scope.js +34 -0
  7. package/dist/build-spk/dsm-arch.d.ts +7 -1
  8. package/dist/build-spk/dsm-arch.js +24 -28
  9. package/dist/build-spk/dsm-platforms.json +42 -0
  10. package/dist/build-spk/dsm-version.d.ts +11 -0
  11. package/dist/build-spk/dsm-version.js +17 -0
  12. package/dist/build-spk/gateway.js +8 -4
  13. package/dist/build-spk/generator.js +30 -5
  14. package/dist/build-spk/go-toolchain.d.ts +20 -0
  15. package/dist/build-spk/go-toolchain.js +44 -0
  16. package/dist/build-spk/notices.js +4 -1
  17. package/dist/build-spk/resource-worker.js +3 -0
  18. package/dist/build-spk/wizard-messages.d.ts +66 -0
  19. package/dist/build-spk/wizard-messages.js +75 -9
  20. package/dist/cli.js +28 -14
  21. package/dist/contract/schema-validate.js +8 -0
  22. package/dist/contract/validate.js +30 -0
  23. package/dist/deploy/deploy.d.ts +1 -1
  24. package/dist/deploy/deploy.js +8 -0
  25. package/dist/deploy/native-install-values.d.ts +17 -0
  26. package/dist/deploy/native-install-values.js +32 -0
  27. package/dist/deploy/plan.d.ts +6 -2
  28. package/dist/deploy/plan.js +58 -7
  29. package/dist/deploy/spk-version.js +1 -1
  30. package/dist/error-registry.js +54 -20
  31. package/dist/host/dsm-client.d.ts +8 -4
  32. package/dist/host/dsm-client.js +63 -21
  33. package/dist/host/dsm-http.js +24 -2
  34. package/dist/host/types.d.ts +3 -1
  35. package/dist/info.js +45 -10
  36. package/dist/init.d.ts +3 -0
  37. package/dist/init.js +50 -19
  38. package/dist/package-metadata.d.ts +21 -0
  39. package/dist/package-metadata.js +101 -0
  40. package/dist/portal/alias.d.ts +25 -0
  41. package/dist/portal/alias.js +48 -0
  42. package/dist/portal/package.d.ts +33 -0
  43. package/dist/portal/package.js +116 -0
  44. package/dist/runtime/delegate-contract.d.ts +79 -0
  45. package/dist/runtime/delegate-contract.js +27 -0
  46. package/dist/runtime/dsm-version.d.ts +6 -0
  47. package/dist/runtime/dsm-version.js +8 -0
  48. package/dist/runtime/executor-build.js +10 -6
  49. package/dist/runtime/executor-inspect.d.ts +3 -0
  50. package/dist/runtime/executor-inspect.js +11 -5
  51. package/dist/runtime/executor-policy.d.ts +12 -0
  52. package/dist/runtime/executor-policy.js +43 -3
  53. package/dist/runtime/executor-scope-task.d.ts +4 -0
  54. package/dist/runtime/executor-scope-task.js +21 -0
  55. package/dist/runtime/executor-tasks.d.ts +2 -1
  56. package/dist/runtime/executor-tasks.js +4 -4
  57. package/dist/skill.js +1 -0
  58. package/dist/standalone/api-permissions.d.ts +10 -0
  59. package/dist/standalone/api-permissions.js +19 -2
  60. package/dist/standalone/background.d.ts +16 -0
  61. package/dist/standalone/background.js +69 -2
  62. package/dist/standalone/binary.d.ts +1 -1
  63. package/dist/standalone/binary.js +22 -8
  64. package/dist/standalone/build.d.ts +1 -1
  65. package/dist/standalone/build.js +38 -8
  66. package/dist/standalone/daemon.d.ts +1 -0
  67. package/dist/standalone/daemon.js +10 -5
  68. package/dist/standalone/dsm-window.d.ts +3 -1
  69. package/dist/standalone/dsm-window.js +78 -49
  70. package/dist/standalone/inspect-spk.d.ts +8 -0
  71. package/dist/standalone/inspect-spk.js +110 -27
  72. package/dist/standalone/lifecycle.js +86 -8
  73. package/dist/standalone/manifest.d.ts +13 -0
  74. package/dist/standalone/manifest.js +57 -8
  75. package/dist/standalone/native-authorization-window.d.ts +1 -1
  76. package/dist/standalone/native-authorization-window.js +9 -1
  77. package/dist/standalone/native-layout.d.ts +3 -0
  78. package/dist/standalone/native-layout.js +37 -5
  79. package/dist/standalone/native-root-window.d.ts +4 -2
  80. package/dist/standalone/native-root-window.js +33 -18
  81. package/dist/standalone/portal-window.d.ts +21 -0
  82. package/dist/standalone/portal-window.js +155 -0
  83. package/dist/standalone/portal.d.ts +4 -0
  84. package/dist/standalone/portal.js +4 -0
  85. package/dist/standalone/resource.d.ts +5 -3
  86. package/dist/standalone/resource.js +6 -3
  87. package/dist/standalone/root-window.d.ts +4 -1
  88. package/dist/standalone/root-window.js +193 -36
  89. package/dist/standalone/spk.d.ts +1 -1
  90. package/dist/standalone/spk.js +25 -7
  91. package/dist/templates/_daemon/go.mod +1 -1
  92. package/dist/templates/_daemon/main.go +6 -3
  93. package/dist/templates/_daemon/main_test.go +82 -9
  94. package/dist/templates/_daemon/testdata/child.go +3 -0
  95. package/dist/templates/_executor/README.md +130 -16
  96. package/dist/templates/_executor/anchor.go +156 -0
  97. package/dist/templates/_executor/anchor_test.go +161 -0
  98. package/dist/templates/_executor/apppriv_review_test.go +1 -1
  99. package/dist/templates/_executor/cancel_contract_test.go +236 -0
  100. package/dist/templates/_executor/copy.go +64 -0
  101. package/dist/templates/_executor/copy_test.go +88 -0
  102. package/dist/templates/_executor/digest_review_test.go +2 -2
  103. package/dist/templates/_executor/dsm.go +63 -13
  104. package/dist/templates/_executor/dsm_test.go +95 -1
  105. package/dist/templates/_executor/executor.go +260 -49
  106. package/dist/templates/_executor/executor_test.go +36 -6
  107. package/dist/templates/_executor/go.mod +2 -0
  108. package/dist/templates/_executor/identity.go +27 -1
  109. package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
  110. package/dist/templates/_executor/identity_linux.go +82 -0
  111. package/dist/templates/_executor/identity_security_test.go +43 -0
  112. package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  113. package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  114. package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
  115. package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  116. package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
  117. package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
  118. package/dist/templates/_executor/lifecycle_test.go +11 -0
  119. package/dist/templates/_executor/link_linux.go +28 -0
  120. package/dist/templates/_executor/long_running_test.go +530 -0
  121. package/dist/templates/_executor/main.go +83 -25
  122. package/dist/templates/_executor/managed.go +3 -3
  123. package/dist/templates/_executor/managed_test.go +3 -3
  124. package/dist/templates/_executor/move_linux.go +490 -0
  125. package/dist/templates/_executor/move_linux_test.go +460 -0
  126. package/dist/templates/_executor/move_validation.go +46 -0
  127. package/dist/templates/_executor/move_validation_test.go +187 -0
  128. package/dist/templates/_executor/operations.go +926 -0
  129. package/dist/templates/_executor/path_test.go +18 -0
  130. package/dist/templates/_executor/pid.go +37 -0
  131. package/dist/templates/_executor/pid_test.go +113 -0
  132. package/dist/templates/_executor/platform_linux.go +24 -173
  133. package/dist/templates/_executor/platform_linux_test.go +9 -65
  134. package/dist/templates/_executor/platform_other.go +38 -4
  135. package/dist/templates/_executor/process.go +3 -0
  136. package/dist/templates/_executor/purge_log.go +18 -0
  137. package/dist/templates/_executor/records.go +242 -0
  138. package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
  139. package/dist/templates/_executor/scope_client.go +37 -0
  140. package/dist/templates/_executor/scope_contract.go +12 -0
  141. package/dist/templates/_executor/selected_scope.go +146 -0
  142. package/dist/templates/_executor/selected_scope_test.go +186 -0
  143. package/dist/templates/_executor/status_disabled_test.go +33 -0
  144. package/dist/templates/_executor/store.go +4 -3
  145. package/dist/templates/_executor/supervise.go +109 -0
  146. package/dist/templates/_executor/supervise_test.go +130 -0
  147. package/dist/templates/_executor/task_race_review_test.go +1 -1
  148. package/dist/templates/_executor/tasks.go +52 -15
  149. package/dist/templates/_executor/tasks_dsm71_test.go +114 -0
  150. package/dist/templates/_executor/tasks_review_test.go +1 -1
  151. package/dist/templates/_executor/tasks_test.go +62 -5
  152. package/dist/templates/_executor/upgrade_watch_test.go +13 -5
  153. package/dist/templates/_executor/watch.go +8 -0
  154. package/dist/templates/_executor/watch_test.go +23 -2
  155. package/dist/templates/_executor/write_review_linux_test.go +4 -12
  156. package/dist/templates/_gateway/go.mod +2 -0
  157. package/dist/templates/_shared/AGENTS.md +129 -0
  158. package/dist/templates/binary/dsm-package.yaml +24 -0
  159. package/dist/templates/binary/i18n/messages/de.json +4 -0
  160. package/dist/templates/binary/i18n/messages/en.json +4 -0
  161. package/dist/templates/binary/i18n/messages/es.json +4 -0
  162. package/dist/templates/binary/i18n/messages/fr.json +4 -0
  163. package/dist/templates/binary/i18n/messages/it.json +4 -0
  164. package/dist/templates/binary/i18n/messages/ja.json +4 -0
  165. package/dist/templates/binary/i18n/messages/ko.json +4 -0
  166. package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
  167. package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
  168. package/dist/templates/binary/ui/app.js +19 -4
  169. package/dist/templates/native-authorization/AuthorizationGate.vue +5 -3
  170. package/dist/templates/native-authorization/i18n/de.json +1 -0
  171. package/dist/templates/native-authorization/i18n/en.json +1 -0
  172. package/dist/templates/native-authorization/i18n/es.json +2 -1
  173. package/dist/templates/native-authorization/i18n/fr.json +1 -0
  174. package/dist/templates/native-authorization/i18n/it.json +11 -10
  175. package/dist/templates/native-authorization/i18n/ja.json +1 -0
  176. package/dist/templates/native-authorization/i18n/ko.json +10 -9
  177. package/dist/templates/native-authorization/i18n/zh-CN.json +6 -5
  178. package/dist/templates/native-authorization/i18n/zh-TW.json +6 -5
  179. package/dist/templates/native-go/README.md +43 -10
  180. package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
  181. package/dist/templates/native-go/backend/go.mod +1 -1
  182. package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
  183. package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  184. package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
  185. package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  186. package/dist/templates/native-go/backend/internal/api/server.go +18 -5
  187. package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  188. package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  189. package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
  190. package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
  191. package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
  192. package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
  193. package/dist/templates/native-go/backend/internal/background/store.go +16 -14
  194. package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
  195. package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  196. package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  197. package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  198. package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  199. package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  200. package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  201. package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
  202. package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  203. package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  204. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  205. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  206. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  207. package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  208. package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  209. package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  210. package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  211. package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  212. package/dist/templates/native-go/backend/internal/filestation/client.go +39 -3
  213. package/dist/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
  214. package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  215. package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
  216. package/dist/templates/native-go/backend/internal/identity/README.md +5 -1
  217. package/dist/templates/native-go/backend/internal/identity/dsm.go +24 -5
  218. package/dist/templates/native-go/backend/internal/identity/http.go +1 -1
  219. package/dist/templates/native-go/backend/internal/identity/identity_test.go +48 -1
  220. package/dist/templates/native-go/backend/internal/identity/service.go +1 -1
  221. package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
  222. package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  223. package/dist/templates/native-go/dsm-package.yaml +20 -1
  224. package/dist/templates/native-go/i18n/glossary.json +2 -1
  225. package/dist/templates/native-go/i18n/messages/de.json +1 -0
  226. package/dist/templates/native-go/i18n/messages/en.json +1 -0
  227. package/dist/templates/native-go/i18n/messages/es.json +1 -0
  228. package/dist/templates/native-go/i18n/messages/fr.json +1 -0
  229. package/dist/templates/native-go/i18n/messages/it.json +1 -0
  230. package/dist/templates/native-go/i18n/messages/ja.json +1 -0
  231. package/dist/templates/native-go/i18n/messages/ko.json +1 -0
  232. package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
  233. package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
  234. package/dist/templates/native-go/ui/app.css +10 -0
  235. package/dist/templates/native-go/ui/app.js +11 -1
  236. package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
  237. package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  238. package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  239. package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  240. package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  241. package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  242. package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  243. package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  244. package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  245. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  246. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  247. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  248. package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  249. package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  250. package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  251. package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  252. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  253. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  254. package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  255. package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  256. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  257. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  258. package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  259. package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  260. package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  261. package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  262. package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  263. package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  264. package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  265. package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  266. package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  267. package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  268. package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  269. package/dist/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
  270. package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  271. package/dist/templates/native-go-delegate/test.sh +1 -0
  272. package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  273. package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  274. package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  275. package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  276. package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  277. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  278. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  279. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  280. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  281. package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  282. package/dist/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
  283. package/dist/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
  284. package/dist/templates/native-go-vue/README.md +4 -0
  285. package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
  286. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  287. package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
  288. package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
  289. package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +54 -9
  290. package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  291. package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  292. package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  293. package/dist/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
  294. package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -2
  295. package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  296. package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  297. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +47 -0
  298. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
  299. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
  300. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
  301. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
  302. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
  303. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -0
  304. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  305. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  306. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  307. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  308. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  309. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  310. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  311. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  312. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  313. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +47 -0
  314. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -5
  315. package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  316. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  317. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  318. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  319. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  320. package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  321. package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  322. package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  323. package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  324. package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  325. package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  326. package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  327. package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  328. package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  329. package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  330. package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  331. package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  332. package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  333. package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  334. package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  335. package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  336. package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  337. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  338. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  339. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  340. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  341. package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  342. package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  343. package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  344. package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  345. package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  346. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  347. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  348. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  349. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  350. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  351. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  352. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  353. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  354. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  355. package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  356. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  357. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  358. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  359. package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  360. package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
  361. package/package.json +5 -1
  362. package/schema/package-metadata.schema.json +101 -0
  363. package/schema/synology-app.schema.json +112 -0
  364. package/skills/SKILL.md +106 -4
  365. package/skills/reference/create.md +101 -2
  366. package/skills/reference/deploy.md +2 -2
  367. package/skills/reference/files.md +113 -2
  368. package/skills/reference/identity.md +70 -1
  369. package/skills/reference/portal.md +17 -0
  370. package/skills/reference/ui-vue.md +12 -0
  371. package/templates/_daemon/go.mod +1 -1
  372. package/templates/_daemon/main.go +6 -3
  373. package/templates/_daemon/main_test.go +82 -9
  374. package/templates/_daemon/testdata/child.go +3 -0
  375. package/templates/_executor/README.md +130 -16
  376. package/templates/_executor/anchor.go +156 -0
  377. package/templates/_executor/anchor_test.go +161 -0
  378. package/templates/_executor/apppriv_review_test.go +1 -1
  379. package/templates/_executor/cancel_contract_test.go +236 -0
  380. package/templates/_executor/copy.go +64 -0
  381. package/templates/_executor/copy_test.go +88 -0
  382. package/templates/_executor/digest_review_test.go +2 -2
  383. package/templates/_executor/dsm.go +63 -13
  384. package/templates/_executor/dsm_test.go +95 -1
  385. package/templates/_executor/executor.go +260 -49
  386. package/templates/_executor/executor_test.go +36 -6
  387. package/templates/_executor/go.mod +2 -0
  388. package/templates/_executor/identity.go +27 -1
  389. package/templates/_executor/identity_kernel_linux_test.go +60 -0
  390. package/templates/_executor/identity_linux.go +82 -0
  391. package/templates/_executor/identity_security_test.go +43 -0
  392. package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  393. package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  394. package/templates/_executor/internal/taskscript/boot.sh +9 -9
  395. package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  396. package/templates/_executor/internal/taskscript/control.sh +15 -10
  397. package/templates/_executor/internal/taskscript/tasks.go +5 -3
  398. package/templates/_executor/lifecycle_test.go +11 -0
  399. package/templates/_executor/link_linux.go +28 -0
  400. package/templates/_executor/long_running_test.go +530 -0
  401. package/templates/_executor/main.go +83 -25
  402. package/templates/_executor/managed.go +3 -3
  403. package/templates/_executor/managed_test.go +3 -3
  404. package/templates/_executor/move_linux.go +490 -0
  405. package/templates/_executor/move_linux_test.go +460 -0
  406. package/templates/_executor/move_validation.go +46 -0
  407. package/templates/_executor/move_validation_test.go +187 -0
  408. package/templates/_executor/operations.go +926 -0
  409. package/templates/_executor/path_test.go +18 -0
  410. package/templates/_executor/pid.go +37 -0
  411. package/templates/_executor/pid_test.go +113 -0
  412. package/templates/_executor/platform_linux.go +24 -173
  413. package/templates/_executor/platform_linux_test.go +9 -65
  414. package/templates/_executor/platform_other.go +38 -4
  415. package/templates/_executor/process.go +3 -0
  416. package/templates/_executor/purge_log.go +18 -0
  417. package/templates/_executor/records.go +242 -0
  418. package/templates/_executor/scope_cancel_contract_test.go +91 -0
  419. package/templates/_executor/scope_client.go +37 -0
  420. package/templates/_executor/scope_contract.go +12 -0
  421. package/templates/_executor/selected_scope.go +146 -0
  422. package/templates/_executor/selected_scope_test.go +186 -0
  423. package/templates/_executor/status_disabled_test.go +33 -0
  424. package/templates/_executor/store.go +4 -3
  425. package/templates/_executor/supervise.go +109 -0
  426. package/templates/_executor/supervise_test.go +130 -0
  427. package/templates/_executor/task_race_review_test.go +1 -1
  428. package/templates/_executor/tasks.go +52 -15
  429. package/templates/_executor/tasks_dsm71_test.go +114 -0
  430. package/templates/_executor/tasks_review_test.go +1 -1
  431. package/templates/_executor/tasks_test.go +62 -5
  432. package/templates/_executor/upgrade_watch_test.go +13 -5
  433. package/templates/_executor/watch.go +8 -0
  434. package/templates/_executor/watch_test.go +23 -2
  435. package/templates/_executor/write_review_linux_test.go +4 -12
  436. package/templates/_gateway/go.mod +2 -0
  437. package/templates/_shared/AGENTS.md +129 -0
  438. package/templates/binary/dsm-package.yaml +24 -0
  439. package/templates/binary/i18n/messages/de.json +4 -0
  440. package/templates/binary/i18n/messages/en.json +4 -0
  441. package/templates/binary/i18n/messages/es.json +4 -0
  442. package/templates/binary/i18n/messages/fr.json +4 -0
  443. package/templates/binary/i18n/messages/it.json +4 -0
  444. package/templates/binary/i18n/messages/ja.json +4 -0
  445. package/templates/binary/i18n/messages/ko.json +4 -0
  446. package/templates/binary/i18n/messages/zh-CN.json +4 -0
  447. package/templates/binary/i18n/messages/zh-TW.json +4 -0
  448. package/templates/binary/ui/app.js +19 -4
  449. package/templates/native-authorization/AuthorizationGate.vue +5 -3
  450. package/templates/native-authorization/i18n/de.json +1 -0
  451. package/templates/native-authorization/i18n/en.json +1 -0
  452. package/templates/native-authorization/i18n/es.json +2 -1
  453. package/templates/native-authorization/i18n/fr.json +1 -0
  454. package/templates/native-authorization/i18n/it.json +11 -10
  455. package/templates/native-authorization/i18n/ja.json +1 -0
  456. package/templates/native-authorization/i18n/ko.json +10 -9
  457. package/templates/native-authorization/i18n/zh-CN.json +6 -5
  458. package/templates/native-authorization/i18n/zh-TW.json +6 -5
  459. package/templates/native-go/README.md +43 -10
  460. package/templates/native-go/backend/cmd/app/main.go +27 -7
  461. package/templates/native-go/backend/go.mod +1 -1
  462. package/templates/native-go/backend/internal/api/entry_test.go +47 -0
  463. package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  464. package/templates/native-go/backend/internal/api/registry.go +11 -0
  465. package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  466. package/templates/native-go/backend/internal/api/server.go +18 -5
  467. package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  468. package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  469. package/templates/native-go/backend/internal/app/portal.go +30 -0
  470. package/templates/native-go/backend/internal/app/portal_test.go +55 -0
  471. package/templates/native-go/backend/internal/app/routes.go +8 -2
  472. package/templates/native-go/backend/internal/background/runner.go +1 -1
  473. package/templates/native-go/backend/internal/background/store.go +16 -14
  474. package/templates/native-go/backend/internal/dsm/admin.go +8 -2
  475. package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  476. package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  477. package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  478. package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  479. package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  480. package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  481. package/templates/native-go/backend/internal/dsm/entry.go +177 -0
  482. package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  483. package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  484. package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  485. package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  486. package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  487. package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  488. package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  489. package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  490. package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  491. package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  492. package/templates/native-go/backend/internal/filestation/client.go +39 -3
  493. package/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
  494. package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  495. package/templates/native-go/backend/internal/filestation/service.go +1 -1
  496. package/templates/native-go/backend/internal/identity/README.md +5 -1
  497. package/templates/native-go/backend/internal/identity/dsm.go +24 -5
  498. package/templates/native-go/backend/internal/identity/http.go +1 -1
  499. package/templates/native-go/backend/internal/identity/identity_test.go +48 -1
  500. package/templates/native-go/backend/internal/identity/service.go +1 -1
  501. package/templates/native-go/backend/internal/portal/portal.go +138 -0
  502. package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  503. package/templates/native-go/dsm-package.yaml +20 -1
  504. package/templates/native-go/i18n/glossary.json +2 -1
  505. package/templates/native-go/i18n/messages/de.json +1 -0
  506. package/templates/native-go/i18n/messages/en.json +1 -0
  507. package/templates/native-go/i18n/messages/es.json +1 -0
  508. package/templates/native-go/i18n/messages/fr.json +1 -0
  509. package/templates/native-go/i18n/messages/it.json +1 -0
  510. package/templates/native-go/i18n/messages/ja.json +1 -0
  511. package/templates/native-go/i18n/messages/ko.json +1 -0
  512. package/templates/native-go/i18n/messages/zh-CN.json +1 -0
  513. package/templates/native-go/i18n/messages/zh-TW.json +1 -0
  514. package/templates/native-go/ui/app.css +10 -0
  515. package/templates/native-go/ui/app.js +11 -1
  516. package/templates/native-go-delegate/DELEGATE.md +126 -5
  517. package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  518. package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  519. package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  520. package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  521. package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  522. package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  523. package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  524. package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  525. package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  526. package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  527. package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  528. package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  529. package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  530. package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  531. package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  532. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  533. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  534. package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  535. package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  536. package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  537. package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  538. package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  539. package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  540. package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  541. package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  542. package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  543. package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  544. package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  545. package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  546. package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  547. package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  548. package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  549. package/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
  550. package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  551. package/templates/native-go-delegate/test.sh +1 -0
  552. package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  553. package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  554. package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  555. package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  556. package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  557. package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  558. package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  559. package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  560. package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  561. package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  562. package/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
  563. package/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
  564. package/templates/native-go-vue/README.md +4 -0
  565. package/templates/native-go-vue/frontend/package-lock.json +4 -4
  566. package/templates/native-go-vue/frontend/package.json +1 -1
  567. package/templates/native-go-vue/frontend/src/App.vue +18 -13
  568. package/templates/native-go-vue/frontend/src/context.ts +31 -0
  569. package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +54 -9
  570. package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  571. package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  572. package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  573. package/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
  574. package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -2
  575. package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  576. package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  577. package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +47 -0
  578. package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
  579. package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
  580. package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
  581. package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
  582. package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
  583. package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -0
  584. package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  585. package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  586. package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  587. package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  588. package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  589. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  590. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  591. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  592. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  593. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +47 -0
  594. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -5
  595. package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  596. package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  597. package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  598. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  599. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  600. package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  601. package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  602. package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  603. package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  604. package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  605. package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  606. package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  607. package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  608. package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  609. package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  610. package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  611. package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  612. package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  613. package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  614. package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  615. package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  616. package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  617. package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  618. package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  619. package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  620. package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  621. package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  622. package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  623. package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  624. package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  625. package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  626. package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  627. package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  628. package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  629. package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  630. package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  631. package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  632. package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  633. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  634. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  635. package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  636. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  637. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  638. package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  639. package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  640. package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
@@ -4,6 +4,8 @@ export const AUTHORIZATION_RUNTIME = `function createAuthorizationAccess(options
4
4
  function fail(code) { var error = new Error(code); error.code = code; return error; }
5
5
  function status() { return options.call("authorization.status").then(function (d) {
6
6
  if (!d || d.command !== "authorization" || d.schema_version !== 1 || ["ready","authorization_required","not_admin","session_expired","unavailable"].indexOf(d.state) < 0) throw fail("authorization_bad_response");
7
+ // upgrade_reapproval is a reason-only tombstone: it can only explain a pending request.
8
+ if (d.reason === "upgrade_reapproval" && d.state !== "authorization_required") throw fail("authorization_bad_response");
7
9
  return d;
8
10
  }); }
9
11
  function plan(method) { return options.call(method).then(function (p) {
@@ -12,9 +14,15 @@ export const AUTHORIZATION_RUNTIME = `function createAuthorizationAccess(options
12
14
  p.operations.forEach(function (op) { if (seen[op] || !options.tasks.some(function (t) { return t.op === op; })) throw fail("authorization_bad_response"); seen[op] = true; });
13
15
  return p;
14
16
  }); }
17
+ // The backend's grant decides: a task still waiting at the window's limit, or
18
+ // one signalled after it wrote the grant, has still authorized the package.
19
+ function settled(e) {
20
+ if (!e || (e.code !== "root_timeout" && e.code !== "root_task_failed")) throw e;
21
+ return status().then(function (d) { if (d.state !== "ready") throw e; });
22
+ }
15
23
  function exclusive(fn) { if (busy) return busy; busy = Promise.resolve().then(fn).then(function (s) { busy = null; return s; },function (e) { busy = null; throw e; });return busy; }
16
24
  function authorize(ops,run) { return ops.reduce(function (previous,op) { return previous.then(function () {
17
- return options.root.authorize(op).then(function (state) { if (state !== "ready") throw fail("root_cancelled"); return run ? options.root.run(op) : null; });
25
+ return options.root.authorize(op).then(function (state) { if (state !== "ready") throw fail("root_cancelled"); return run ? options.root.run(op).catch(settled) : null; });
18
26
  }); },Promise.resolve()); }
19
27
  return {canManage:function () {return !!options.user && options.user().admin === true;},status:status,request:function () { return exclusive(function () {
20
28
  return plan("authorization.request").then(function (p) { return authorize(p.operations,p.run === true); }).then(status,function (e) { if (e.code === "root_cancelled") return status();throw e; });
@@ -1,3 +1,4 @@
1
+ import { type PackageMetadata } from "../package-metadata.js";
1
2
  import type { CommandRunner } from './build.js';
2
3
  export declare const LAYOUT_ARCHES: {
3
4
  readonly x86_64: readonly [2, 62];
@@ -21,6 +22,7 @@ type Binary = {
21
22
  arches?: LayoutArch[];
22
23
  };
23
24
  export interface NativeLayout {
25
+ metadata?: PackageMetadata;
24
26
  root: string;
25
27
  package: string;
26
28
  version: string;
@@ -39,6 +41,7 @@ export interface NativeLayout {
39
41
  payload: string;
40
42
  metadata: string;
41
43
  binaries: Binary[];
44
+ anchors?: Record<string, string>;
42
45
  };
43
46
  native: {
44
47
  prepare?: Hook;
@@ -1,3 +1,4 @@
1
+ import { validateMetadata, metadataInfoFields } from "../package-metadata.js";
1
2
  /** Existing native products: the CLI owns archives/INFO, the project owns its layout. */
2
3
  import { createHash } from 'node:crypto';
3
4
  import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
@@ -36,6 +37,20 @@ function inside(root, path) {
36
37
  fail('path escapes project');
37
38
  return full;
38
39
  }
40
+ // Package Center writes INFO as root, so product root helpers can trust these
41
+ // payload digests across upgrades. The synopkgland_ prefix stays reserved.
42
+ function anchors(value) {
43
+ const a = object(value, Object.keys(value ?? {}));
44
+ if (Object.keys(a).length > 16)
45
+ fail('at most 16 INFO anchors');
46
+ for (const [key, path] of Object.entries(a)) {
47
+ if (!/^[a-z][a-z0-9_]{0,48}_sha256$/.test(key) || key.startsWith('synopkgland_'))
48
+ fail(`invalid INFO anchor key: ${key}`);
49
+ if (pathText(path).includes('{arch}'))
50
+ fail('INFO anchor path is relative to the architecture payload');
51
+ }
52
+ return a;
53
+ }
39
54
  function hook(value) {
40
55
  const h = object(value, ['command', 'cwd', 'env']);
41
56
  if (!Array.isArray(h.command) || !h.command.length || !h.command.every((x) => typeof x === 'string' && x.length > 0 && !x.includes('\0')))
@@ -56,13 +71,15 @@ export function isNativeLayout(root) {
56
71
  }
57
72
  export function loadNativeLayout(root) {
58
73
  try {
59
- const m = object(parse(readFileSync(join(root, 'dsm-package.yaml'), 'utf8')), ['schema', 'backend', 'package', 'version', 'build', 'displayname', 'description', 'maintainer', 'os_min_ver', 'privilege', 'arches', 'layout', 'native']);
74
+ const m = object(parse(readFileSync(join(root, 'dsm-package.yaml'), 'utf8')), ['schema', 'backend', 'package', 'version', 'build', 'displayname', 'description', 'maintainer', 'metadata', 'os_min_ver', 'privilege', 'arches', 'layout', 'native']);
60
75
  if (m.schema !== 2)
61
76
  fail('schema 2 required; migrate schema: 1 to schema: 2 and add backend: {kind: native}');
62
77
  const backend = object(m.backend, ['kind']);
63
78
  if (backend.kind !== 'native' || (m.privilege !== undefined && m.privilege !== 'none'))
64
79
  fail('backend.kind: native and package-only privilege required');
65
80
  m.privilege = 'none';
81
+ if (m.metadata !== undefined)
82
+ m.metadata = validateMetadata(m.metadata);
66
83
  if (existsSync(join(root, 'compose.yaml')))
67
84
  fail('compose.yaml and dsm-package.yaml are mutually exclusive');
68
85
  if (!/^[A-Za-z][A-Za-z0-9]{1,63}$/.test(text(m.package)) || !/^\d+(\.\d+){0,3}$/.test(text(m.version)) || !/^7\.\d+(\.\d+)?-\d+$/.test(text(m.os_min_ver)))
@@ -73,11 +90,13 @@ export function loadNativeLayout(root) {
73
90
  text(m[k]);
74
91
  if (!Array.isArray(m.arches) || !m.arches.length || new Set(m.arches).size !== m.arches.length || m.arches.some((a) => !Object.hasOwn(LAYOUT_ARCHES, a)))
75
92
  fail('invalid architecture list');
76
- const layout = object(m.layout, ['payload', 'metadata', 'binaries']);
93
+ const layout = object(m.layout, ['payload', 'metadata', 'binaries', 'anchors']);
77
94
  layout.payload = pathText(layout.payload);
78
95
  layout.metadata = pathText(layout.metadata);
79
96
  if (!Array.isArray(layout.binaries) || !layout.binaries.length)
80
97
  fail('binary assertions required');
98
+ if (layout.anchors !== undefined)
99
+ layout.anchors = anchors(layout.anchors);
81
100
  for (const b of layout.binaries) {
82
101
  object(b, ['path', 'linkage', 'arches']);
83
102
  pathText(b.path);
@@ -300,8 +319,11 @@ export async function buildNativeLayout(options) {
300
319
  await createReproducibleTar(target, join(stage, 'package.tgz'), { gzip: true });
301
320
  rmSync(target, { recursive: true });
302
321
  const fields = { package: m.package, version, arch, os_min_ver: m.os_min_ver, displayname: m.displayname, description: m.description, maintainer: m.maintainer, dsmuidir: 'ui', dsmappname: `SYNO.SDS.${m.package}.Instance`, startable: 'yes', thirdparty: 'yes', checksum: createHash('md5').update(readFileSync(join(stage, 'package.tgz'))).digest('hex') };
303
- writeFileSync(join(stage, 'INFO'), Object.entries(fields).map(([k, v]) => `${k}="${v}"\n`).join(''));
304
- writeFileSync(join(stage, 'native-layout.json'), JSON.stringify({ format: 1, arch, binaries: binaries.map(({ path, linkage }) => ({ path, linkage })), files }));
322
+ const info = [...Object.entries(fields), ...metadataInfoFields(m.metadata), ...anchorFields(m.layout.anchors ?? {}, files)];
323
+ if (new Set(info.map(([k]) => k)).size !== info.length)
324
+ fail('INFO anchor collides with an INFO field');
325
+ writeFileSync(join(stage, 'INFO'), info.map(([k, v]) => `${k}="${v.replace(/([\\"$`])/g, '\\$1')}"\n`).join(''));
326
+ writeFileSync(join(stage, 'native-layout.json'), JSON.stringify({ format: 1, arch, binaries: binaries.map(({ path, linkage }) => ({ path, linkage })), files, ...(m.layout.anchors ? { anchors: m.layout.anchors } : {}) }));
305
327
  const output = join(options.outDir ?? join(m.root, 'dist'), `${m.package}-${version}-${arch}.spk`);
306
328
  mkdirSync(dirname(output), { recursive: true });
307
329
  await createReproducibleTar(stage, output);
@@ -319,7 +341,7 @@ export function inspectNativeLayout(dir, payload, info) {
319
341
  try {
320
342
  if (!/^[A-Za-z][A-Za-z0-9]{1,63}$/.test(info.package ?? '') || !/^\d+(\.\d+){0,3}-\d+$/.test(info.version ?? '') || !/^7\.\d+(\.\d+)?-\d+$/.test(info.os_min_ver ?? ''))
321
343
  fail('invalid native INFO identity/version/DSM');
322
- const inv = object(JSON.parse(readFileSync(join(dir, 'native-layout.json'), 'utf8')), ['format', 'arch', 'binaries', 'files']);
344
+ const inv = object(JSON.parse(readFileSync(join(dir, 'native-layout.json'), 'utf8')), ['format', 'arch', 'binaries', 'files', 'anchors']);
323
345
  if (inv.format !== 1 || inv.arch !== info.arch || !Object.hasOwn(LAYOUT_ARCHES, inv.arch))
324
346
  fail('invalid native layout inventory');
325
347
  checkLayoutMetadata(dir, true, info.package);
@@ -337,9 +359,19 @@ export function inspectNativeLayout(dir, payload, info) {
337
359
  }
338
360
  if (createHash('md5').update(readFileSync(join(dir, 'package.tgz'))).digest('hex') !== info.checksum)
339
361
  fail('package checksum mismatch');
362
+ checkInfoAnchors(readFileSync(join(dir, 'INFO'), 'utf8'), inv.anchors === undefined ? {} : anchors(inv.anchors), actual);
340
363
  return [];
341
364
  }
342
365
  catch (e) {
343
366
  return [String(e)];
344
367
  }
345
368
  }
369
+ function anchorFields(declared, files) {
370
+ return Object.entries(declared).map(([key, path]) => [key, files.find(f => f.path === path)?.sha256 ?? fail(`INFO anchor file missing: ${path}`)]);
371
+ }
372
+ function checkInfoAnchors(info, declared, files) {
373
+ const lines = info.split('\n').filter(line => /^[a-z0-9_]+_sha256=/.test(line));
374
+ const expected = anchorFields(declared, files).map(([key, digest]) => `${key}="${digest}"`);
375
+ if (JSON.stringify(lines.sort()) !== JSON.stringify(expected.sort()))
376
+ fail('INFO anchors do not match the payload');
377
+ }
@@ -17,10 +17,12 @@ export interface RootTask {
17
17
  * with exactly the embedded script. The one-use token goes into that single
18
18
  * create call and is never kept.
19
19
  * - run: re-reads the task and runs it only if it is still exactly ours, then
20
- * waits for its history entry and asks the backend for the output. Repair
20
+ * waits for its history entry and asks the backend for the output. A queued
21
+ * or running task keeps the wait going, up to RUN_LIMIT_MS (loaded NAS took
22
+ * 4.5 minutes), and `options.progress({op, state, elapsedMs})` hears each poll. Repair
21
23
  * additionally requires fresh PasswordConfirm and another exact task check.
22
24
  * - an older version of our task is "outdated" and never runs; authorizing
23
25
  * again replaces it. A same-named task that is not ours is a "conflict" and
24
26
  * is never run, replaced or deleted.
25
27
  */
26
- export declare const ROOT_RUNTIME = "function createRootAccess(options) {\n var API = \"SYNO.Core.TaskScheduler\";\n var POLL_MS = 500, POLLS = 60;\n var byOp = {}, running = {};\n var legacy = null, probe = null;\n options.tasks.forEach(function (task) { byOp[task.op] = task; });\n\n function fail(code) {\n var error = new Error(code);\n error.code = code;\n return error;\n }\n function begin(op) {\n if (!Object.prototype.hasOwnProperty.call(byOp, op)) return Promise.reject(fail(\"root_unknown_op\"));\n if (options.user().admin !== true) return Promise.reject(fail(\"admin_required\"));\n return Promise.resolve(byOp[op]);\n }\n function readOutput(task) {\n return task.output ? options.call(\"root.output\", { op: task.op }) : Promise.resolve(null);\n }\n function isRootTask(summary) {\n return summary.owner === \"root\" && summary.real_owner === \"root\" && summary.enable === false && summary.type === \"script\";\n }\n function listTasks() {\n if (legacy === false) return options.send(API, \"list\", 3, { start: 0, limit: 500 });\n if (legacy === true) return legacyList();\n if (!probe) {\n probe = options.send(API, \"list\", 3, { start: 0, limit: 500 }).then(function (data) {\n legacy = false;\n return data;\n }, function (error) {\n if (!error || (error.code !== \"dsm_103\" && error.code !== 103)) {\n probe = null;\n throw error;\n }\n legacy = true;\n return legacyList();\n });\n }\n return probe;\n }\n function legacyList() {\n return options.send(API, \"list\", 2, { offset: 0, limit: 500 }).then(function (data) {\n // Refuse a truncated snapshot: a same-named task could lie outside it.\n if (!data || !Array.isArray(data.tasks) || data.tasks.length > 500\n || !(typeof data.total === \"number\" && isFinite(data.total) && Math.floor(data.total) === data.total) || data.total !== data.tasks.length) throw fail(\"root_bad_response\");\n return data;\n });\n }\n function readTask(ref) {\n return options.send(API, \"get\", legacy ? 3 : 4, ref);\n }\n function createTask(params) {\n return options.send(legacy ? API : API + \".Root\", \"create\", legacy ? 3 : 4, params);\n }\n function deleteTask(ref) {\n return options.send(API, \"delete\", 2, { tasks: [ref] });\n }\n function runTask(ref) {\n return options.send(API, \"run\", 2, { tasks: [ref] });\n }\n function find(task) {\n return listTasks().then(function (data) {\n if (!data || !Array.isArray(data.tasks)) throw fail(\"root_bad_response\");\n var named = data.tasks.filter(function (summary) { return summary && summary.name === task.name; });\n if (named.length === 0) return { state: \"missing\" };\n if (named.length > 1 || !isRootTask(named[0])) return { state: \"conflict\" };\n var ref = { id: named[0].id, real_owner: named[0].real_owner };\n return readTask(ref).then(function (detail) {\n var script = detail && detail.extra && detail.extra.script;\n if (!detail || String(detail.id) !== String(ref.id) || detail.name !== task.name\n || detail.owner !== \"root\" || detail.real_owner !== ref.real_owner || detail.enable !== false || detail.type !== \"script\" || typeof script !== \"string\") {\n return { state: \"conflict\" };\n }\n if (script === task.script) return { state: \"ready\", ref: ref };\n if (script.indexOf(task.header) === 0) return { state: \"outdated\", ref: ref };\n return { state: \"conflict\" };\n });\n });\n }\n function definition(task, user) {\n var hours = [];\n for (var h = 1; h <= 23; h++) hours.push(h);\n return {\n name: task.name,\n real_owner: user,\n owner: \"root\",\n enable: false,\n type: \"script\",\n schedule: {\n date_type: 0, week_day: \"0,1,2,3,4,5,6\", repeat_date: 1001, monthly_week: [], hour: 0, minute: 0,\n repeat_hour: 0, repeat_min: 0, last_work_hour: 0,\n repeat_min_store_config: [1, 5, 10, 15, 20, 30], repeat_hour_store_config: hours\n },\n extra: { notify_enable: false, script: task.script, notify_mail: \"\", notify_if_error: false }\n };\n }\n function newest(history) {\n if (!Array.isArray(history)) throw fail(\"root_bad_response\");\n return history.reduce(function (latest, entry) {\n return entry && (!latest || Number(entry.timestamp) > Number(latest.timestamp)) ? entry : latest;\n }, null);\n }\n function history(ref) {\n return options.send(API, \"get_history_status_list\", 1, { id: ref.id }).then(newest);\n }\n function waitForRun(ref, before, polls) {\n return history(ref).then(function (latest) {\n var finished = latest && (!before || latest.timestamp !== before.timestamp)\n && latest.exit_type !== \"running\" && latest.stop_time;\n if (finished) {\n if (latest.exit_code !== 0) throw fail(\"root_task_failed\");\n return;\n }\n if (polls <= 1) throw fail(\"root_timeout\");\n return options.wait(POLL_MS).then(function () { return waitForRun(ref, before, polls - 1); });\n });\n }\n\n function validTime(value) {\n if (typeof value !== \"string\" || !/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(value)) return false;\n var normalized = value.replace(\" \", \"T\") + \"Z\";\n var date = new Date(normalized);\n return !isNaN(date.getTime()) && date.toISOString().slice(0, 19) === normalized.slice(0, 19);\n }\n function bounded(call, deadline) {\n // A poll count alone cannot bound a stalled DSM callback. Discard late replies.\n return new Promise(function (resolve, reject) {\n var remaining = deadline - Date.now();\n if (remaining <= 0) { reject(fail(\"root_timeout\")); return; }\n var timer = setTimeout(function () { reject(fail(\"root_timeout\")); }, remaining);\n Promise.resolve().then(call).then(function (value) {\n clearTimeout(timer);\n if (Date.now() >= deadline) reject(fail(\"root_timeout\"));\n else resolve(value);\n }, function (error) { clearTimeout(timer); reject(error); });\n });\n }\n function legacyHistory(ref, deadline) {\n return bounded(function () { return options.send(API, \"view\", 1, { id: ref.id }); }, deadline).then(function (records) {\n // DSM 7.1 omits data entirely when a task has never run.\n if (records === undefined) records = [];\n if (!Array.isArray(records) || records.length > 500) throw fail(\"root_bad_response\");\n var seen = {};\n records.forEach(function (record) {\n if (!record || !validTime(record.start_time) || typeof record.stop_time !== \"string\"\n || (record.stop_time && (!validTime(record.stop_time) || record.stop_time < record.start_time))\n || typeof record.exit_type !== \"string\" || !(typeof record.exit_code === \"number\" && isFinite(record.exit_code) && Math.floor(record.exit_code) === record.exit_code)\n || seen[record.start_time]) throw fail(\"root_bad_response\");\n seen[record.start_time] = true;\n });\n return records;\n });\n }\n function waitForLegacyRun(ref, before, deadline, polls) {\n return legacyHistory(ref, deadline).then(function (records) {\n var previous = before.map(function (record) { return record.start_time; });\n var newestBefore = previous.slice().sort().pop();\n var fresh = records.filter(function (record) { return previous.indexOf(record.start_time) === -1; });\n if (fresh.length > 1) throw fail(\"root_bad_response\");\n var latest = fresh[0];\n if (latest && (!newestBefore || latest.start_time > newestBefore) && latest.stop_time) {\n if (latest.exit_code !== 0 || latest.exit_type !== \"normal\") throw fail(\"root_task_failed\");\n return;\n }\n if (polls <= 1 || Date.now() >= deadline) throw fail(\"root_timeout\");\n return options.wait(Math.min(POLL_MS, deadline - Date.now())).then(function () {\n return waitForLegacyRun(ref, before, deadline, polls - 1);\n });\n });\n }\n function execute(task, verified) {\n if (!legacy) {\n return history(verified.ref).then(function (before) {\n return runTask(verified.ref).then(function () { return waitForRun(verified.ref, before, POLLS); });\n });\n }\n var deadline = Date.now() + POLL_MS * POLLS;\n return legacyHistory(verified.ref, deadline).then(function (before) {\n if (before.some(function (record) { return !record.stop_time || record.exit_type === \"running\"; })) throw fail(\"root_not_ready\");\n // Mutating calls are sent exactly once, never retried with another profile.\n return bounded(function () { return runTask(verified.ref); }, deadline).then(function () {\n return waitForLegacyRun(verified.ref, before, deadline, POLLS);\n });\n }).then(function () {\n return bounded(function () { return find(task); }, deadline).then(function (after) {\n if (after.state !== \"ready\" || String(after.ref.id) !== String(verified.ref.id)) throw fail(\"root_verify_failed\");\n });\n });\n }\n function performRun(op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state !== \"ready\") throw fail(\"root_not_ready\");\n var consent = op === \"helper_repair\" ? options.confirmPassword() : Promise.resolve({ confirmed: true });\n return consent.then(function (confirmation) {\n if (!confirmation || confirmation.confirmed !== true) throw fail(\"root_cancelled\");\n return op === \"helper_repair\" ? begin(op).then(find) : found;\n }).then(function (verified) {\n if (verified.state !== \"ready\") throw fail(\"root_not_ready\");\n return execute(task, verified);\n });\n }).then(function () { return readOutput(task); });\n });\n }\n\n return {\n state: function (op) {\n return begin(op).then(find).then(function (found) { return found.state; });\n },\n authorize: function (op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state === \"ready\") return \"ready\";\n if (found.state === \"conflict\") throw fail(\"root_conflict\");\n return options.confirmPassword().then(function (confirmation) {\n if (!confirmation || confirmation.confirmed !== true) return \"cancelled\";\n if (!legacy && (typeof confirmation.token !== \"string\" || !confirmation.token)) throw fail(\"root_verify_failed\");\n var params = definition(task, options.user().name);\n if (!legacy) params.SynoConfirmPWToken = confirmation.token;\n // Re-read after the legacy client-side dialog before replacing a task.\n var checked = legacy ? begin(op).then(find) : Promise.resolve(found);\n return checked.then(function (current) {\n if (current.state === \"conflict\") throw fail(\"root_conflict\");\n if (current.state === \"ready\") return;\n var replaced = current.state === \"outdated\" ? deleteTask(current.ref) : Promise.resolve();\n return replaced.then(function () { return createTask(params); });\n }).then(function () {\n return find(task);\n }).then(function (after) {\n if (after.state !== \"ready\") throw fail(\"root_verify_failed\");\n return \"ready\";\n });\n });\n });\n });\n },\n run: function (op) {\n if (!Object.prototype.hasOwnProperty.call(byOp, op)) return Promise.reject(fail(\"root_unknown_op\"));\n if (options.user().admin !== true) return Promise.reject(fail(\"admin_required\"));\n if (running[op]) return running[op];\n var pending = performRun(op).then(function (value) {\n delete running[op];\n return value;\n }, function (error) { delete running[op]; throw error; });\n running[op] = pending;\n return pending;\n },\n remove: function (op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state === \"missing\") return \"missing\";\n if (found.state === \"conflict\") throw fail(\"root_conflict\");\n return deleteTask(found.ref).then(function () {\n return find(task);\n }).then(function (after) {\n if (after.state !== \"missing\") throw fail(\"root_verify_failed\");\n return \"missing\";\n });\n });\n });\n },\n output: function (op) {\n return begin(op).then(readOutput);\n }\n };\n}";
28
+ export declare const ROOT_RUNTIME: string;
@@ -1,3 +1,4 @@
1
+ import { versionUnsupported } from "../runtime/dsm-version.js";
1
2
  /**
2
3
  * `createRootAccess(options)` → `{ state, authorize, run, remove }`, plain
3
4
  * ES5 for DSM's desktop. Every DSM call goes through `options.send` (the
@@ -7,7 +8,9 @@
7
8
  * with exactly the embedded script. The one-use token goes into that single
8
9
  * create call and is never kept.
9
10
  * - run: re-reads the task and runs it only if it is still exactly ours, then
10
- * waits for its history entry and asks the backend for the output. Repair
11
+ * waits for its history entry and asks the backend for the output. A queued
12
+ * or running task keeps the wait going, up to RUN_LIMIT_MS (loaded NAS took
13
+ * 4.5 minutes), and `options.progress({op, state, elapsedMs})` hears each poll. Repair
11
14
  * additionally requires fresh PasswordConfirm and another exact task check.
12
15
  * - an older version of our task is "outdated" and never runs; authorizing
13
16
  * again replaces it. A same-named task that is not ours is a "conflict" and
@@ -15,11 +18,20 @@
15
18
  */
16
19
  export const ROOT_RUNTIME = `function createRootAccess(options) {
17
20
  var API = "SYNO.Core.TaskScheduler";
18
- var POLL_MS = 500, POLLS = 60;
21
+ var POLL_MS = 500, MAX_POLL_MS = 2000, RUN_LIMIT_MS = 10 * 60 * 1000;
19
22
  var byOp = {}, running = {};
20
23
  var legacy = null, probe = null;
24
+ var versionUnsupported = ${versionUnsupported.toString()};
21
25
  options.tasks.forEach(function (task) { byOp[task.op] = task; });
22
26
 
27
+ function now() { return options.now ? options.now() : Date.now(); }
28
+ function report(task, state, started) {
29
+ if (typeof options.progress !== "function") return;
30
+ try { options.progress({ op: task.op, state: state, elapsedMs: now() - started }); } catch (error) {}
31
+ }
32
+ function pause(interval, deadline) {
33
+ return options.wait(Math.max(0, Math.min(interval, deadline - now())));
34
+ }
23
35
  function fail(code) {
24
36
  var error = new Error(code);
25
37
  error.code = code;
@@ -44,7 +56,7 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
44
56
  legacy = false;
45
57
  return data;
46
58
  }, function (error) {
47
- if (!error || (error.code !== "dsm_103" && error.code !== 103)) {
59
+ if (!error || !versionUnsupported(error.code)) {
48
60
  probe = null;
49
61
  throw error;
50
62
  }
@@ -119,16 +131,18 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
119
131
  function history(ref) {
120
132
  return options.send(API, "get_history_status_list", 1, { id: ref.id }).then(newest);
121
133
  }
122
- function waitForRun(ref, before, polls) {
134
+ function waitForRun(task, ref, before, started, deadline, interval) {
123
135
  return history(ref).then(function (latest) {
124
- var finished = latest && (!before || latest.timestamp !== before.timestamp)
125
- && latest.exit_type !== "running" && latest.stop_time;
126
- if (finished) {
136
+ var fresh = latest && (!before || latest.timestamp !== before.timestamp);
137
+ if (fresh && latest.exit_type !== "running" && latest.stop_time) {
127
138
  if (latest.exit_code !== 0) throw fail("root_task_failed");
128
139
  return;
129
140
  }
130
- if (polls <= 1) throw fail("root_timeout");
131
- return options.wait(POLL_MS).then(function () { return waitForRun(ref, before, polls - 1); });
141
+ report(task, fresh ? "running" : "queued", started);
142
+ if (now() >= deadline) throw fail("root_timeout");
143
+ return pause(interval, deadline).then(function () {
144
+ return waitForRun(task, ref, before, started, deadline, Math.min(interval * 2, MAX_POLL_MS));
145
+ });
132
146
  });
133
147
  }
134
148
 
@@ -141,12 +155,12 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
141
155
  function bounded(call, deadline) {
142
156
  // A poll count alone cannot bound a stalled DSM callback. Discard late replies.
143
157
  return new Promise(function (resolve, reject) {
144
- var remaining = deadline - Date.now();
158
+ var remaining = deadline - now();
145
159
  if (remaining <= 0) { reject(fail("root_timeout")); return; }
146
160
  var timer = setTimeout(function () { reject(fail("root_timeout")); }, remaining);
147
161
  Promise.resolve().then(call).then(function (value) {
148
162
  clearTimeout(timer);
149
- if (Date.now() >= deadline) reject(fail("root_timeout"));
163
+ if (now() >= deadline) reject(fail("root_timeout"));
150
164
  else resolve(value);
151
165
  }, function (error) { clearTimeout(timer); reject(error); });
152
166
  });
@@ -167,7 +181,7 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
167
181
  return records;
168
182
  });
169
183
  }
170
- function waitForLegacyRun(ref, before, deadline, polls) {
184
+ function waitForLegacyRun(task, ref, before, started, deadline, interval) {
171
185
  return legacyHistory(ref, deadline).then(function (records) {
172
186
  var previous = before.map(function (record) { return record.start_time; });
173
187
  var newestBefore = previous.slice().sort().pop();
@@ -178,24 +192,25 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
178
192
  if (latest.exit_code !== 0 || latest.exit_type !== "normal") throw fail("root_task_failed");
179
193
  return;
180
194
  }
181
- if (polls <= 1 || Date.now() >= deadline) throw fail("root_timeout");
182
- return options.wait(Math.min(POLL_MS, deadline - Date.now())).then(function () {
183
- return waitForLegacyRun(ref, before, deadline, polls - 1);
195
+ report(task, latest ? "running" : "queued", started);
196
+ if (now() >= deadline) throw fail("root_timeout");
197
+ return pause(interval, deadline).then(function () {
198
+ return waitForLegacyRun(task, ref, before, started, deadline, Math.min(interval * 2, MAX_POLL_MS));
184
199
  });
185
200
  });
186
201
  }
187
202
  function execute(task, verified) {
203
+ var started = now(), deadline = started + RUN_LIMIT_MS;
188
204
  if (!legacy) {
189
205
  return history(verified.ref).then(function (before) {
190
- return runTask(verified.ref).then(function () { return waitForRun(verified.ref, before, POLLS); });
206
+ return runTask(verified.ref).then(function () { return waitForRun(task, verified.ref, before, started, deadline, POLL_MS); });
191
207
  });
192
208
  }
193
- var deadline = Date.now() + POLL_MS * POLLS;
194
209
  return legacyHistory(verified.ref, deadline).then(function (before) {
195
210
  if (before.some(function (record) { return !record.stop_time || record.exit_type === "running"; })) throw fail("root_not_ready");
196
211
  // Mutating calls are sent exactly once, never retried with another profile.
197
212
  return bounded(function () { return runTask(verified.ref); }, deadline).then(function () {
198
- return waitForLegacyRun(verified.ref, before, deadline, POLLS);
213
+ return waitForLegacyRun(task, verified.ref, before, started, deadline, POLL_MS);
199
214
  });
200
215
  }).then(function () {
201
216
  return bounded(function () { return find(task); }, deadline).then(function (after) {
@@ -0,0 +1,21 @@
1
+ type PortalLocale = "en" | "zh-TW" | "zh-CN" | "ja" | "ko" | "de" | "fr" | "es" | "it";
2
+ /** SDK-owned portal panel text, shared by the plain panel and the Vue template. */
3
+ export declare const PORTAL_MESSAGES: Record<string, Record<PortalLocale, string>>;
4
+ /**
5
+ * `createPortalAccess(options)` → `ctx.portal`, plain ES5 for DSM's desktop.
6
+ *
7
+ * An administrator reads and sets the alias with DSM's own
8
+ * SYNO.Core.AppPortal API in their own session, after SYNO.API.Info shows the
9
+ * API; DSM itself refuses everyone else (105). An ordinary user reads the
10
+ * alias only through the package backend's `portal.status`. Anything
11
+ * unexpected reads as `unavailable`; an administrator then gets only the
12
+ * Control Panel shortcut.
13
+ *
14
+ * `status()` resolves `{state, alias?, url?, canManage, controlPanel,
15
+ * defaultAlias}`; `apply(alias)` and `disable()` resolve the new status or
16
+ * reject `{code}`; `openControlPanel()` opens Login Portal > Applications.
17
+ * `messages` is the panel text in the window's locale; `mountPanel(element)`
18
+ * renders a plain panel for UIs without their own.
19
+ */
20
+ export declare const PORTAL_RUNTIME: string;
21
+ export {};
@@ -0,0 +1,155 @@
1
+ import { PORTAL_ALIAS_PATTERN, RESERVED_PORTAL_ALIASES } from "../portal/alias.js";
2
+ /** SDK-owned portal panel text, shared by the plain panel and the Vue template. */
3
+ export const PORTAL_MESSAGES = {
4
+ title: { en: "Application Portal", "zh-TW": "應用程式入口", "zh-CN": "应用程序门户", ja: "アプリケーションポータル", ko: "응용 프로그램 포털", de: "Anwendungsportal", fr: "Portail d'application", es: "Portal de aplicaciones", it: "Portale applicazioni" },
5
+ link: { en: "Direct link after DSM sign-in:", "zh-TW": "DSM 登入後的直接連結:", "zh-CN": "DSM 登录后的直接链接:", ja: "DSM サインイン後の直接リンク:", ko: "DSM 로그인 후 바로 가기 링크:", de: "Direkter Link nach der DSM-Anmeldung:", fr: "Lien direct après connexion à DSM :", es: "Enlace directo tras iniciar sesión en DSM:", it: "Link diretto dopo l'accesso a DSM:" },
6
+ inactive: { en: "Not active. Apply an alias to let users open this app directly after DSM sign-in.", "zh-TW": "尚未啟用。套用別名後,使用者可在 DSM 登入後直接開啟這個 App。", "zh-CN": "尚未启用。应用别名后,用户可在 DSM 登录后直接打开此应用。", ja: "無効です。エイリアスを適用すると、DSM サインイン後にこのアプリを直接開けます。", ko: "비활성 상태입니다. 별칭을 적용하면 DSM 로그인 후 이 앱을 바로 열 수 있습니다.", de: "Nicht aktiv. Wenden Sie einen Alias an, damit Benutzer diese App nach der DSM-Anmeldung direkt öffnen können.", fr: "Inactif. Appliquez un alias pour ouvrir cette application directement après connexion à DSM.", es: "Inactivo. Aplique un alias para abrir esta aplicación directamente tras iniciar sesión en DSM.", it: "Non attivo. Applica un alias per aprire questa app direttamente dopo l'accesso a DSM." },
7
+ askAdmin: { en: "Ask an administrator to set this up", "zh-TW": "請管理員設定", "zh-CN": "请管理员设置", ja: "管理者に設定を依頼してください", ko: "관리자에게 설정을 요청하세요", de: "Bitten Sie einen Administrator, dies einzurichten", fr: "Demandez à un administrateur de le configurer", es: "Pida a un administrador que lo configure", it: "Chiedi a un amministratore di configurarlo" },
8
+ alias: { en: "Alias", "zh-TW": "別名", "zh-CN": "别名", ja: "エイリアス", ko: "별칭", de: "Alias", fr: "Alias", es: "Alias", it: "Alias" },
9
+ apply: { en: "Apply", "zh-TW": "套用", "zh-CN": "应用", ja: "適用", ko: "적용", de: "Übernehmen", fr: "Appliquer", es: "Aplicar", it: "Applica" },
10
+ disable: { en: "Turn off", "zh-TW": "停用", "zh-CN": "停用", ja: "無効にする", ko: "끄기", de: "Ausschalten", fr: "Désactiver", es: "Desactivar", it: "Disattiva" },
11
+ advanced: { en: "Advanced settings in Control Panel", "zh-TW": "在控制台進行進階設定", "zh-CN": "在控制面板中进行高级设置", ja: "コントロールパネルの詳細設定", ko: "제어판의 고급 설정", de: "Erweiterte Einstellungen in der Systemsteuerung", fr: "Paramètres avancés dans le Panneau de configuration", es: "Ajustes avanzados en el Panel de control", it: "Impostazioni avanzate nel Pannello di controllo" },
12
+ controlPanel: { en: "Open Control Panel Application Portal", "zh-TW": "開啟控制台 Application Portal", "zh-CN": "打开控制面板 Application Portal", ja: "コントロールパネルの Application Portal を開く", ko: "제어판 Application Portal 열기", de: "Application Portal in der Systemsteuerung öffnen", fr: "Ouvrir Application Portal dans le Panneau de configuration", es: "Abrir Application Portal en el Panel de control", it: "Apri Application Portal nel Pannello di controllo" },
13
+ portal_alias_invalid: { en: "Use 1-64 lowercase letters, digits or hyphens, not starting or ending with a hyphen.", "zh-TW": "請使用 1–64 個小寫英文字母、數字或連字號,且不可以連字號開頭或結尾。", "zh-CN": "请使用 1–64 个小写英文字母、数字或连字符,且不能以连字符开头或结尾。", ja: "1~64 文字の小文字英字・数字・ハイフンを使用し、先頭と末尾にハイフンは使えません。", ko: "1~64자의 영문 소문자, 숫자 또는 하이픈을 사용하고 하이픈으로 시작하거나 끝나지 않게 하세요.", de: "Verwenden Sie 1–64 Kleinbuchstaben, Ziffern oder Bindestriche, ohne Bindestrich am Anfang oder Ende.", fr: "Utilisez 1 à 64 lettres minuscules, chiffres ou tirets, sans tiret au début ni à la fin.", es: "Use de 1 a 64 letras minúsculas, dígitos o guiones, sin guion al principio ni al final.", it: "Usa da 1 a 64 lettere minuscole, cifre o trattini, senza trattino all'inizio o alla fine." },
14
+ portal_alias_reserved: { en: "DSM already uses this alias. Choose another one.", "zh-TW": "DSM 已使用這個別名,請改用其他別名。", "zh-CN": "DSM 已使用此别名,请改用其他别名。", ja: "このエイリアスは DSM で使用されています。別のものを選んでください。", ko: "DSM에서 이미 사용하는 별칭입니다. 다른 별칭을 선택하세요.", de: "DSM verwendet diesen Alias bereits. Wählen Sie einen anderen.", fr: "DSM utilise déjà cet alias. Choisissez-en un autre.", es: "DSM ya usa este alias. Elija otro.", it: "DSM usa già questo alias. Scegline un altro." },
15
+ portal_alias_in_use: { en: "Another app already uses this alias. Choose another one.", "zh-TW": "另一個 App 已使用這個別名,請改用其他別名。", "zh-CN": "另一个应用已使用此别名,请改用其他别名。", ja: "別のアプリがこのエイリアスを使用しています。別のものを選んでください。", ko: "다른 앱이 이미 이 별칭을 사용합니다. 다른 별칭을 선택하세요.", de: "Eine andere App verwendet diesen Alias bereits. Wählen Sie einen anderen.", fr: "Une autre application utilise déjà cet alias. Choisissez-en un autre.", es: "Otra aplicación ya usa este alias. Elija otro.", it: "Un'altra app usa già questo alias. Scegline un altro." },
16
+ admin_required: { en: "Only a DSM administrator can change this.", "zh-TW": "只有 DSM 管理員可以變更這項設定。", "zh-CN": "只有 DSM 管理员可以更改此设置。", ja: "これを変更できるのは DSM 管理者のみです。", ko: "DSM 관리자만 변경할 수 있습니다.", de: "Nur ein DSM-Administrator kann dies ändern.", fr: "Seul un administrateur DSM peut modifier ce paramètre.", es: "Solo un administrador de DSM puede cambiar esto.", it: "Solo un amministratore DSM può modificarlo." },
17
+ portal_unavailable: { en: "DSM did not accept the change. Try again or use Control Panel.", "zh-TW": "DSM 未接受變更。請再試一次或改用控制台。", "zh-CN": "DSM 未接受更改。请重试或改用控制面板。", ja: "DSM は変更を受け付けませんでした。再試行するか、コントロールパネルを使用してください。", ko: "DSM이 변경을 받아들이지 않았습니다. 다시 시도하거나 제어판을 사용하세요.", de: "DSM hat die Änderung nicht übernommen. Versuchen Sie es erneut oder verwenden Sie die Systemsteuerung.", fr: "DSM n'a pas accepté la modification. Réessayez ou utilisez le Panneau de configuration.", es: "DSM no aceptó el cambio. Inténtelo de nuevo o use el Panel de control.", it: "DSM non ha accettato la modifica. Riprova o usa il Pannello di controllo." },
18
+ };
19
+ function localizedMessages() {
20
+ const out = {};
21
+ for (const [key, texts] of Object.entries(PORTAL_MESSAGES)) {
22
+ for (const [locale, text] of Object.entries(texts))
23
+ (out[locale] ??= {})[key] = text;
24
+ }
25
+ return out;
26
+ }
27
+ /**
28
+ * `createPortalAccess(options)` → `ctx.portal`, plain ES5 for DSM's desktop.
29
+ *
30
+ * An administrator reads and sets the alias with DSM's own
31
+ * SYNO.Core.AppPortal API in their own session, after SYNO.API.Info shows the
32
+ * API; DSM itself refuses everyone else (105). An ordinary user reads the
33
+ * alias only through the package backend's `portal.status`. Anything
34
+ * unexpected reads as `unavailable`; an administrator then gets only the
35
+ * Control Panel shortcut.
36
+ *
37
+ * `status()` resolves `{state, alias?, url?, canManage, controlPanel,
38
+ * defaultAlias}`; `apply(alias)` and `disable()` resolve the new status or
39
+ * reject `{code}`; `openControlPanel()` opens Login Portal > Applications.
40
+ * `messages` is the panel text in the window's locale; `mountPanel(element)`
41
+ * renders a plain panel for UIs without their own.
42
+ */
43
+ export const PORTAL_RUNTIME = `function createPortalAccess(options) {
44
+ var ALIAS = new RegExp(${JSON.stringify(PORTAL_ALIAS_PATTERN.source)});
45
+ var RESERVED = ${JSON.stringify(RESERVED_PORTAL_ALIASES)};
46
+ var LINKABLE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
47
+ var CATALOGS = ${JSON.stringify(localizedMessages())};
48
+ var messages = CATALOGS[options.locale] || CATALOGS.en;
49
+ var ERRORS = { dsm_4100: "portal_alias_invalid", dsm_4102: "portal_alias_reserved", dsm_4103: "portal_alias_in_use", dsm_105: "admin_required" };
50
+ function result(state, alias, managed) {
51
+ var out = { state: state, canManage: managed === true, controlPanel: managed !== undefined, defaultAlias: options.defaultAlias };
52
+ if (state === "active") {
53
+ out.alias = alias;
54
+ out.url = options.location.protocol + "//" + options.location.host + "/" + encodeURIComponent(alias) + "/";
55
+ }
56
+ return out;
57
+ }
58
+ function fromBackend() {
59
+ return options.call("portal.status", {}).then(function (data) {
60
+ if (data && data.state === "active" && typeof data.alias === "string" && LINKABLE.test(data.alias)) return result("active", data.alias);
61
+ return result(data && data.state === "inactive" ? "inactive" : "unavailable");
62
+ }, function () {
63
+ return result("unavailable");
64
+ });
65
+ }
66
+ function fromDsm() {
67
+ return options.send("SYNO.API.Info", "query", 1, { query: "SYNO.Core.AppPortal" }).then(function (info) {
68
+ var api = info && info["SYNO.Core.AppPortal"];
69
+ if (!api || !(api.maxVersion >= 2)) return null;
70
+ return options.send("SYNO.Core.AppPortal", "get", 2, { id: options.appId, additional: ["default_setting"] });
71
+ }).then(function (item) {
72
+ if (!item || item.id !== options.appId) return result("unavailable", undefined, false);
73
+ var alias = typeof item.alias === "string" && LINKABLE.test(item.alias) ? item.alias : "";
74
+ var out = result(alias ? "active" : "inactive", alias, true);
75
+ var setting = item.additional && item.additional.default_setting;
76
+ if (setting && typeof setting.alias === "string" && ALIAS.test(setting.alias)) out.defaultAlias = setting.alias;
77
+ return out;
78
+ }, function () {
79
+ return result("unavailable", undefined, false);
80
+ });
81
+ }
82
+ function status() {
83
+ return options.isAdmin() ? fromDsm() : fromBackend();
84
+ }
85
+ function set(alias) {
86
+ if (!options.isAdmin()) return Promise.reject({ code: "admin_required" });
87
+ return options.send("SYNO.Core.AppPortal", "set", 2, { id: options.appId, alias: alias }).then(status, function (error) {
88
+ throw { code: ERRORS[error && error.code] || "portal_unavailable" };
89
+ });
90
+ }
91
+ var access = {
92
+ messages: messages,
93
+ status: status,
94
+ apply: function (alias) {
95
+ if (typeof alias !== "string" || !ALIAS.test(alias)) return Promise.reject({ code: "portal_alias_invalid" });
96
+ if (RESERVED.indexOf(alias) >= 0) return Promise.reject({ code: "portal_alias_reserved" });
97
+ return set(alias);
98
+ },
99
+ disable: function () {
100
+ return set(null);
101
+ },
102
+ openControlPanel: function () {
103
+ options.launch("SYNO.SDS.AdminCenter.Application", { fn: "SYNO.SDS.AdminCenter.Login.Main", tab: "applications" });
104
+ },
105
+ mountPanel: function (element) {
106
+ return mountPanel(element);
107
+ }
108
+ };
109
+ function node(tag, attrs, children) {
110
+ var out = document.createElement(tag);
111
+ for (var key in attrs) {
112
+ if (key === "text") out.textContent = attrs[key];
113
+ else out.setAttribute(key, attrs[key]);
114
+ }
115
+ for (var i = 0; children && i < children.length; i++) out.appendChild(children[i]);
116
+ return out;
117
+ }
118
+ function button(text, onClick) {
119
+ var out = node("button", { type: "button", text: text });
120
+ out.addEventListener("click", function (event) { event.preventDefault(); onClick(); });
121
+ return out;
122
+ }
123
+ function mountPanel(element) {
124
+ var disposed = false;
125
+ function render(current, error) {
126
+ if (disposed) return;
127
+ var parts = [node("h2", { text: messages.title })];
128
+ var settle = function (next) { return next.then(function (fresh) { render(fresh); }, function (failure) { render(current, failure); }); };
129
+ if (current.state === "active") {
130
+ parts.push(node("p", {}, [node("span", { text: messages.link + " " }), node("a", { href: current.url, target: "_blank", rel: "noopener", text: current.url })]));
131
+ }
132
+ if (current.canManage) {
133
+ if (current.state !== "active") parts.push(node("p", { text: messages.inactive }));
134
+ var input = node("input", { type: "text", maxlength: "64", autocomplete: "off", "aria-label": messages.alias });
135
+ input.value = current.alias || current.defaultAlias;
136
+ var form = node("form", { class: "dsmapp-portal-form" }, [node("label", { text: messages.alias }), input, node("button", { type: "submit", text: messages.apply })]);
137
+ form.addEventListener("submit", function (event) { event.preventDefault(); settle(access.apply(input.value)); });
138
+ if (current.state === "active") form.appendChild(button(messages.disable, function () { settle(access.disable()); }));
139
+ parts.push(form, button(messages.advanced, access.openControlPanel));
140
+ } else if (current.controlPanel) {
141
+ parts.push(button(messages.controlPanel, access.openControlPanel));
142
+ } else if (current.state !== "active") {
143
+ parts.push(node("p", { text: messages.askAdmin }));
144
+ }
145
+ if (error) parts.push(node("p", { role: "alert", class: "dsmapp-portal-error", text: messages[error.code] || messages.portal_unavailable }));
146
+ element.replaceChildren.apply(element, parts);
147
+ }
148
+ status().then(function (current) { render(current); });
149
+ return {
150
+ refresh: function () { return status().then(function (current) { render(current); }); },
151
+ dispose: function () { disposed = true; element.replaceChildren(); }
152
+ };
153
+ }
154
+ return access;
155
+ }`;
@@ -0,0 +1,4 @@
1
+ import type { StandaloneManifest } from "./manifest.js";
2
+ import type { PortalPackage } from "../portal/package.js";
3
+ /** A native portal opens the package's own DSM window. */
4
+ export declare function nativePortal(manifest: StandaloneManifest): PortalPackage | undefined;
@@ -0,0 +1,4 @@
1
+ /** A native portal opens the package's own DSM window. */
2
+ export function nativePortal(manifest) {
3
+ return manifest.portal && { appId: `SYNO.SDS.${manifest.package}.Instance`, application: manifest.displayname, alias: manifest.portal.alias };
4
+ }
@@ -1,11 +1,13 @@
1
1
  import type { Capabilities } from "./manifest.js";
2
2
  import { type SharedFolder } from "./shared-folder.js";
3
+ import { type PortalPackage } from "../portal/package.js";
3
4
  /**
4
- * `conf/resource` for a native package: only DSM's official `data-share` and
5
- * `systemd-user-unit` workers, in a fixed key order. Undefined when neither applies.
5
+ * `conf/resource` for a native package: only DSM's official `data-share`,
6
+ * `systemd-user-unit` and `web-config` workers, in a fixed key order.
7
+ * Undefined when none applies.
6
8
  */
7
9
  export declare function renderStandaloneResource(m: {
8
10
  package: string;
9
11
  capabilities: Capabilities;
10
12
  sharedFolder?: SharedFolder;
11
- }): string | undefined;
13
+ }, portal?: PortalPackage): string | undefined;
@@ -1,13 +1,16 @@
1
1
  import { sharedFolderResource } from "./shared-folder.js";
2
+ import { portalResource } from "../portal/package.js";
2
3
  /**
3
- * `conf/resource` for a native package: only DSM's official `data-share` and
4
- * `systemd-user-unit` workers, in a fixed key order. Undefined when neither applies.
4
+ * `conf/resource` for a native package: only DSM's official `data-share`,
5
+ * `systemd-user-unit` and `web-config` workers, in a fixed key order.
6
+ * Undefined when none applies.
5
7
  */
6
- export function renderStandaloneResource(m) {
8
+ export function renderStandaloneResource(m, portal) {
7
9
  const dataShare = m.sharedFolder && sharedFolderResource(m.package, m.sharedFolder);
8
10
  const resource = {
9
11
  ...(dataShare ? { "data-share": dataShare } : {}),
10
12
  ...(m.capabilities.jobs ? { "systemd-user-unit": {} } : {}),
13
+ ...(portal ? portalResource() : {}),
11
14
  };
12
15
  return Object.keys(resource).length > 0 ? JSON.stringify(resource) : undefined;
13
16
  }
@@ -2,4 +2,7 @@ export { executorTasks as rootTasks, type ExecutorTask as RootTask } from '../ru
2
2
  /** Exact readback is authoritative. PasswordConfirm tokens are reused immediately,
3
3
  * across both Root APIs, and never persisted (DSM validity is about 300 seconds). */
4
4
  export declare const ROOT_RUNTIME: string;
5
- export declare const ROOT_PANEL = "function mountRootPanel(host, access, i18n, tasks, admin) {\n if (!admin) return;\n var status = document.createElement(\"p\"), approve = document.createElement(\"button\"), retry = document.createElement(\"button\");\n approve.textContent = \"Approve background access\"; retry.textContent = \"Check status\";\n host.appendChild(status); host.appendChild(approve); host.appendChild(retry);\n function show(result) { status.textContent = result.state + (result.reason ? \": \" + result.reason : \"\"); approve.hidden = result.state !== \"needs-admin-approval\"; }\n function run(fn) { approve.disabled = retry.disabled = true; return fn().then(show, function(e) { show({state: \"blocked\", reason: e.message || e.code}); }).then(function() { approve.disabled = retry.disabled = false; }); }\n approve.onclick = function() { return run(function() { return access.authorize(); }); };\n retry.onclick = function() { return run(function() { return access.status(); }); };\n run(function() { return access.status().then(function(result) { return result.tasks && result.tasks.boot && result.tasks.control && result.tasks.boot.state === \"ready\" && result.tasks.control.state === \"ready\" ? access.control(\"start\") : result; }); });\n}";
5
+ export declare const ROOT_PANEL = "function mountRootPanel(host, access, i18n, tasks, admin) {\n if (!admin) return;\n var status = document.createElement(\"p\"), approve = document.createElement(\"button\"), retry = document.createElement(\"button\");\n approve.textContent = \"Approve background access\"; retry.textContent = \"Check status\";\n host.appendChild(status); host.appendChild(approve); host.appendChild(retry);\n function show(result) { status.textContent = result.state + (result.reason ? \": \" + result.reason : \"\"); approve.hidden = result.state !== \"needs-admin-approval\" && result.retry !== true; }\n function run(fn) { approve.disabled = retry.disabled = true; return fn().then(show, function(e) { show({state: \"blocked\", reason: e.message || e.code}); }).then(function() { approve.disabled = retry.disabled = false; }); }\n access.subscribe(show);\n approve.onclick = function() { return run(function() { return access.authorize(); }); };\n retry.onclick = function() { return run(function() { return access.status(); }); };\n run(function() { return access.status().then(function(result) { return result.tasks && result.tasks.boot && result.tasks.control && result.tasks.boot.state === \"ready\" && result.tasks.control.state === \"ready\" ? access.control(\"start\") : result; }); });\n}";
6
+ /** Administrator password confirmation in the window's own session: a supplied
7
+ * password, or a masked form when none is given. */
8
+ export declare const PASSWORD_CONFIRM: string;