@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
@@ -0,0 +1,20 @@
1
+ {
2
+ "checking": "正在检查登录状态…",
3
+ "refresh": "刷新",
4
+ "signOut": "注销",
5
+ "settings": "套件设置",
6
+ "loading": "正在加载套件数据…",
7
+ "actionRequired": "需要处理",
8
+ "statusTitle": "套件状态",
9
+ "statusError": "无法加载状态,请刷新后重试。",
10
+ "greeting": "问候语",
11
+ "save": "保存",
12
+ "saved": "问候语已保存。",
13
+ "errors": {
14
+ "session_required": "DSM 登录已过期,请重新登录。",
15
+ "admin_required": "此操作必须由 DSM 管理员执行。",
16
+ "app_privilege_denied": "DSM 应用程序权限不允许此帐户使用此 App。",
17
+ "auth_unavailable": "DSM 验证暂时不可用,请刷新后重试。",
18
+ "request_failed": "请求失败({code}),请刷新后重试。"
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "checking": "正在檢查登入狀態…",
3
+ "refresh": "重新整理",
4
+ "signOut": "登出",
5
+ "settings": "套件設定",
6
+ "loading": "正在載入套件資料…",
7
+ "actionRequired": "需要處理",
8
+ "statusTitle": "套件狀態",
9
+ "statusError": "無法載入狀態,請重新整理後再試。",
10
+ "greeting": "問候語",
11
+ "save": "儲存",
12
+ "saved": "問候語已儲存。",
13
+ "errors": {
14
+ "session_required": "DSM 登入已逾時,請重新登入。",
15
+ "admin_required": "此操作須由 DSM 管理員執行。",
16
+ "app_privilege_denied": "DSM 應用程式權限不允許此帳號使用這個 App。",
17
+ "auth_unavailable": "DSM 驗證目前無法使用,請重新整理後再試。",
18
+ "request_failed": "要求失敗({code}),請重新整理後再試。"
19
+ }
20
+ }
@@ -0,0 +1,13 @@
1
+ import en from './i18n/en.json'
2
+ import zhTW from './i18n/zh-TW.json'
3
+ import zhCN from './i18n/zh-CN.json'
4
+ import ja from './i18n/ja.json'
5
+ import ko from './i18n/ko.json'
6
+ import de from './i18n/de.json'
7
+ import fr from './i18n/fr.json'
8
+ import es from './i18n/es.json'
9
+ import it from './i18n/it.json'
10
+ import {uiLocale} from './nas/locale'
11
+ export type AppCopy=typeof en
12
+ export const appCatalogs:Record<string,AppCopy>={en,'zh-TW':zhTW,'zh-CN':zhCN,ja,ko,de,fr,es,it}
13
+ export function appCopy(locale:string):AppCopy{return appCatalogs[uiLocale(locale)]!}
@@ -2,7 +2,9 @@
2
2
  import {computed, nextTick, onUnmounted, ref} from 'vue'
3
3
  import {Button, Callout, Form, FormActions, FormItem, Input, SettingsSection} from '@synopackageland/ui'
4
4
  import type {IdentitySession} from './session'
5
- const props = defineProps<{session: IdentitySession}>()
5
+ import {identityCopy} from './i18n'
6
+ const props = defineProps<{session: IdentitySession; locale: string}>()
7
+ const copy = computed(() => identityCopy(props.locale))
6
8
  const account = ref('')
7
9
  const password = ref('')
8
10
  const otp = ref('')
@@ -14,7 +16,7 @@ const secure = computed(() => window.location.protocol === 'https:')
14
16
  let disposed = false
15
17
  function message(e: unknown) {
16
18
  const code = (e as {code?: string})?.code
17
- return ({rate_limited: 'Too many sign-in attempts. Wait one minute and try again.', https_required: 'Open this app using HTTPS to sign in.', auth_unavailable: 'DSM sign-in is unavailable. Try again.', session_required: 'Sign in to DSM in this browser, then try again.'} as Record<string, string>)[code || ''] || 'Sign-in could not be completed. Check your credentials or contact your administrator.'
19
+ return (copy.value.errors as Record<string, string>)[code || ''] || copy.value.errors.failed
18
20
  }
19
21
  async function submit() {
20
22
  if (busy.value || !secure.value || !account.value || !password.value || (needsOTP.value && !otp.value)) return
@@ -48,22 +50,22 @@ onUnmounted(() => {disposed = true; password.value = ''; otp.value = ''})
48
50
 
49
51
  <template>
50
52
  <main class="identity-login" :aria-busy="busy">
51
- <SettingsSection title="Sign in with your Synology account" :collapsible="false">
52
- <p>Use your account on this NAS to sign in to the app.</p>
53
- <Callout v-if="!secure" tone="warning" title="HTTPS required">Open this app using HTTPS to sign in.</Callout>
54
- <p v-if="session.notice.value" role="status">{{ session.notice.value }}</p>
55
- <Callout v-if="error" tone="danger" title="Sign-in failed"><span role="alert">{{ error }}</span></Callout>
53
+ <SettingsSection :title="copy.title" :collapsible="false">
54
+ <p>{{ copy.intro }}</p>
55
+ <Callout v-if="!secure" tone="warning" :title="copy.httpsTitle">{{ copy.errors.https_required }}</Callout>
56
+ <p v-if="session.notice.value" role="status">{{ copy.notices[session.notice.value] }}</p>
57
+ <Callout v-if="error" tone="danger" :title="copy.failedTitle"><span role="alert">{{ error }}</span></Callout>
56
58
  <Form @submit.prevent="submit">
57
- <FormItem label="Account"><Input v-model="account" autocomplete="username" :disabled="busy || needsOTP || !secure" /></FormItem>
58
- <FormItem v-if="!needsOTP" label="Password"><Input v-model="password" type="password" autocomplete="current-password" :disabled="busy || !secure" /></FormItem>
59
+ <FormItem :label="copy.account"><Input v-model="account" autocomplete="username" :disabled="busy || needsOTP || !secure" /></FormItem>
60
+ <FormItem v-if="!needsOTP" :label="copy.password"><Input v-model="password" type="password" autocomplete="current-password" :disabled="busy || !secure" /></FormItem>
59
61
  <template v-else>
60
- <p role="status">Enter the verification code from your authenticator app.</p>
61
- <div ref="otpField"><FormItem label="Verification code"><Input v-model="otp" inputmode="numeric" autocomplete="one-time-code" :disabled="busy" /></FormItem></div>
62
+ <p role="status">{{ copy.otpPrompt }}</p>
63
+ <div ref="otpField"><FormItem :label="copy.otp"><Input v-model="otp" inputmode="numeric" autocomplete="one-time-code" :disabled="busy" /></FormItem></div>
62
64
  </template>
63
65
  <FormActions>
64
- <Button type="submit" variant="primary" :disabled="busy || !secure || !account || !password || (needsOTP && !otp)">{{ busy ? 'Signing in…' : needsOTP ? 'Verify and sign in' : 'Sign in' }}</Button>
65
- <Button v-if="needsOTP" variant="secondary" :disabled="busy" @click="restart">Use another account</Button>
66
- <Button v-else variant="secondary" :disabled="busy || !secure" @click="useDSM">Continue with DSM</Button>
66
+ <Button type="submit" variant="primary" :disabled="busy || !secure || !account || !password || (needsOTP && !otp)">{{ busy ? copy.signingIn : needsOTP ? copy.verify : copy.signIn }}</Button>
67
+ <Button v-if="needsOTP" variant="secondary" :disabled="busy" @click="restart">{{ copy.otherAccount }}</Button>
68
+ <Button v-else variant="secondary" :disabled="busy || !secure" @click="useDSM">{{ copy.continueDSM }}</Button>
67
69
  </FormActions>
68
70
  </Form>
69
71
  </SettingsSection>
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "Mit Ihrem Synology-Konto anmelden",
3
+ "intro": "Melden Sie sich mit Ihrem Konto auf diesem NAS bei der App an.",
4
+ "httpsTitle": "HTTPS erforderlich",
5
+ "failedTitle": "Anmeldung fehlgeschlagen",
6
+ "account": "Konto",
7
+ "password": "Passwort",
8
+ "otpPrompt": "Geben Sie den Bestätigungscode aus Ihrer Authentifizierungs-App ein.",
9
+ "otp": "Bestätigungscode",
10
+ "signingIn": "Anmeldung läuft…",
11
+ "verify": "Bestätigen und anmelden",
12
+ "signIn": "Anmelden",
13
+ "otherAccount": "Anderes Konto verwenden",
14
+ "continueDSM": "Mit DSM fortfahren",
15
+ "errors": {
16
+ "rate_limited": "Zu viele Anmeldeversuche. Warten Sie eine Minute und versuchen Sie es erneut.",
17
+ "https_required": "Öffnen Sie diese App über HTTPS, um sich anzumelden.",
18
+ "auth_unavailable": "Die DSM-Anmeldung ist nicht verfügbar. Versuchen Sie es erneut.",
19
+ "session_required": "Melden Sie sich in diesem Browser bei DSM an und versuchen Sie es dann erneut.",
20
+ "failed": "Die Anmeldung konnte nicht abgeschlossen werden. Prüfen Sie Ihre Anmeldedaten oder wenden Sie sich an Ihren Administrator."
21
+ },
22
+ "notices": {
23
+ "expired": "Ihre Sitzung ist abgelaufen. Melden Sie sich erneut an.",
24
+ "revalidate": "Melden Sie sich in diesem Browser bei DSM an und wählen Sie dann „Mit DSM fortfahren“.",
25
+ "unavailable": "Die Anmeldung ist nicht verfügbar. Aktualisieren Sie die Ansicht und versuchen Sie es erneut."
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "Sign in with your Synology account",
3
+ "intro": "Use your account on this NAS to sign in to the app.",
4
+ "httpsTitle": "HTTPS required",
5
+ "failedTitle": "Sign-in failed",
6
+ "account": "Account",
7
+ "password": "Password",
8
+ "otpPrompt": "Enter the verification code from your authenticator app.",
9
+ "otp": "Verification code",
10
+ "signingIn": "Signing in…",
11
+ "verify": "Verify and sign in",
12
+ "signIn": "Sign in",
13
+ "otherAccount": "Use another account",
14
+ "continueDSM": "Continue with DSM",
15
+ "errors": {
16
+ "rate_limited": "Too many sign-in attempts. Wait one minute and try again.",
17
+ "https_required": "Open this app using HTTPS to sign in.",
18
+ "auth_unavailable": "DSM sign-in is unavailable. Try again.",
19
+ "session_required": "Sign in to DSM in this browser, then try again.",
20
+ "failed": "Sign-in could not be completed. Check your credentials or contact your administrator."
21
+ },
22
+ "notices": {
23
+ "expired": "Your session expired. Sign in again.",
24
+ "revalidate": "Sign in to DSM in this browser, then choose Continue with DSM.",
25
+ "unavailable": "Sign-in is unavailable. Refresh to try again."
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "Iniciar sesión con su cuenta de Synology",
3
+ "intro": "Use su cuenta de este NAS para iniciar sesión en la aplicación.",
4
+ "httpsTitle": "Se requiere HTTPS",
5
+ "failedTitle": "Error al iniciar sesión",
6
+ "account": "Cuenta",
7
+ "password": "Contraseña",
8
+ "otpPrompt": "Introduzca el código de verificación de su aplicación de autenticación.",
9
+ "otp": "Código de verificación",
10
+ "signingIn": "Iniciando sesión…",
11
+ "verify": "Verificar e iniciar sesión",
12
+ "signIn": "Iniciar sesión",
13
+ "otherAccount": "Usar otra cuenta",
14
+ "continueDSM": "Continuar con DSM",
15
+ "errors": {
16
+ "rate_limited": "Demasiados intentos de inicio de sesión. Espere un minuto e inténtelo de nuevo.",
17
+ "https_required": "Abra esta aplicación con HTTPS para iniciar sesión.",
18
+ "auth_unavailable": "El inicio de sesión de DSM no está disponible. Inténtelo de nuevo.",
19
+ "session_required": "Inicie sesión en DSM en este navegador e inténtelo de nuevo.",
20
+ "failed": "No se pudo completar el inicio de sesión. Compruebe sus credenciales o póngase en contacto con su administrador."
21
+ },
22
+ "notices": {
23
+ "expired": "Su sesión ha caducado. Vuelva a iniciar sesión.",
24
+ "revalidate": "Inicie sesión en DSM en este navegador y luego elija «Continuar con DSM».",
25
+ "unavailable": "El inicio de sesión no está disponible. Actualice e inténtelo de nuevo."
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "Se connecter avec votre compte Synology",
3
+ "intro": "Utilisez votre compte sur ce NAS pour vous connecter à l’application.",
4
+ "httpsTitle": "HTTPS requis",
5
+ "failedTitle": "Échec de la connexion",
6
+ "account": "Compte",
7
+ "password": "Mot de passe",
8
+ "otpPrompt": "Saisissez le code de vérification de votre application d’authentification.",
9
+ "otp": "Code de vérification",
10
+ "signingIn": "Connexion…",
11
+ "verify": "Vérifier et se connecter",
12
+ "signIn": "Se connecter",
13
+ "otherAccount": "Utiliser un autre compte",
14
+ "continueDSM": "Continuer avec DSM",
15
+ "errors": {
16
+ "rate_limited": "Trop de tentatives de connexion. Patientez une minute et réessayez.",
17
+ "https_required": "Ouvrez cette application en HTTPS pour vous connecter.",
18
+ "auth_unavailable": "La connexion DSM n’est pas disponible. Réessayez.",
19
+ "session_required": "Connectez-vous à DSM dans ce navigateur, puis réessayez.",
20
+ "failed": "La connexion n’a pas pu aboutir. Vérifiez vos identifiants ou contactez votre administrateur."
21
+ },
22
+ "notices": {
23
+ "expired": "Votre session a expiré. Reconnectez-vous.",
24
+ "revalidate": "Connectez-vous à DSM dans ce navigateur, puis choisissez « Continuer avec DSM ».",
25
+ "unavailable": "La connexion n’est pas disponible. Actualisez et réessayez."
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "Accedi con l’account Synology",
3
+ "intro": "Usare l’account di questo NAS per accedere all’app.",
4
+ "httpsTitle": "HTTPS obbligatorio",
5
+ "failedTitle": "Accesso non riuscito",
6
+ "account": "Account",
7
+ "password": "Password",
8
+ "otpPrompt": "Inserire il codice di verifica dell’app di autenticazione.",
9
+ "otp": "Codice di verifica",
10
+ "signingIn": "Accesso in corso…",
11
+ "verify": "Verifica e accedi",
12
+ "signIn": "Accedi",
13
+ "otherAccount": "Usa un altro account",
14
+ "continueDSM": "Continua con DSM",
15
+ "errors": {
16
+ "rate_limited": "Troppi tentativi di accesso. Attendere un minuto e riprovare.",
17
+ "https_required": "Aprire questa app tramite HTTPS per accedere.",
18
+ "auth_unavailable": "L’accesso a DSM non è disponibile. Riprovare.",
19
+ "session_required": "Accedere a DSM in questo browser, quindi riprovare.",
20
+ "failed": "Impossibile completare l’accesso. Controllare le credenziali o contattare l’amministratore."
21
+ },
22
+ "notices": {
23
+ "expired": "La sessione è scaduta. Accedere di nuovo.",
24
+ "revalidate": "Accedere a DSM in questo browser, quindi scegliere «Continua con DSM».",
25
+ "unavailable": "L’accesso non è disponibile. Aggiornare e riprovare."
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "Synology アカウントでサインイン",
3
+ "intro": "この NAS のアカウントを使ってアプリにサインインします。",
4
+ "httpsTitle": "HTTPS が必要です",
5
+ "failedTitle": "サインインに失敗しました",
6
+ "account": "アカウント",
7
+ "password": "パスワード",
8
+ "otpPrompt": "認証アプリに表示された確認コードを入力してください。",
9
+ "otp": "確認コード",
10
+ "signingIn": "サインインしています…",
11
+ "verify": "確認してサインイン",
12
+ "signIn": "サインイン",
13
+ "otherAccount": "別のアカウントを使用",
14
+ "continueDSM": "DSM で続行",
15
+ "errors": {
16
+ "rate_limited": "サインインの試行回数が多すぎます。1 分待ってからもう一度お試しください。",
17
+ "https_required": "サインインするには HTTPS でこのアプリを開いてください。",
18
+ "auth_unavailable": "DSM サインインを利用できません。もう一度お試しください。",
19
+ "session_required": "このブラウザーで DSM にサインインしてから、もう一度お試しください。",
20
+ "failed": "サインインを完了できませんでした。アカウントとパスワードを確認するか、管理者に連絡してください。"
21
+ },
22
+ "notices": {
23
+ "expired": "セッションの有効期限が切れました。もう一度サインインしてください。",
24
+ "revalidate": "このブラウザーで DSM にサインインしてから、「DSM で続行」を選択してください。",
25
+ "unavailable": "サインインを利用できません。最新の情報に更新してから、もう一度お試しください。"
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "Synology 계정으로 로그인",
3
+ "intro": "이 NAS의 계정을 사용하여 앱에 로그인합니다.",
4
+ "httpsTitle": "HTTPS 필요",
5
+ "failedTitle": "로그인 실패",
6
+ "account": "계정",
7
+ "password": "암호",
8
+ "otpPrompt": "인증 앱에 표시된 인증 코드를 입력하십시오.",
9
+ "otp": "인증 코드",
10
+ "signingIn": "로그인 중…",
11
+ "verify": "인증 후 로그인",
12
+ "signIn": "로그인",
13
+ "otherAccount": "다른 계정 사용",
14
+ "continueDSM": "DSM으로 계속",
15
+ "errors": {
16
+ "rate_limited": "로그인 시도 횟수가 너무 많습니다. 1분 후 다시 시도하십시오.",
17
+ "https_required": "로그인하려면 HTTPS로 이 앱을 여십시오.",
18
+ "auth_unavailable": "DSM 로그인을 사용할 수 없습니다. 다시 시도하십시오.",
19
+ "session_required": "이 브라우저에서 DSM에 로그인한 후 다시 시도하십시오.",
20
+ "failed": "로그인을 완료할 수 없습니다. 계정과 암호를 확인하거나 관리자에게 문의하십시오."
21
+ },
22
+ "notices": {
23
+ "expired": "세션이 만료되었습니다. 다시 로그인하십시오.",
24
+ "revalidate": "이 브라우저에서 DSM에 로그인한 후 ‘DSM으로 계속’을 선택하십시오.",
25
+ "unavailable": "로그인을 사용할 수 없습니다. 새로 고친 후 다시 시도하십시오."
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "使用 Synology 帐户登录",
3
+ "intro": "使用这台 NAS 上的帐户登录此 App。",
4
+ "httpsTitle": "需要 HTTPS",
5
+ "failedTitle": "登录失败",
6
+ "account": "帐户",
7
+ "password": "密码",
8
+ "otpPrompt": "请输入身份验证器 App 中的验证码。",
9
+ "otp": "验证码",
10
+ "signingIn": "正在登录…",
11
+ "verify": "验证并登录",
12
+ "signIn": "登录",
13
+ "otherAccount": "使用其他帐户",
14
+ "continueDSM": "通过 DSM 继续",
15
+ "errors": {
16
+ "rate_limited": "登录尝试次数过多,请等待一分钟后重试。",
17
+ "https_required": "请使用 HTTPS 打开此 App 以登录。",
18
+ "auth_unavailable": "DSM 登录暂时不可用,请重试。",
19
+ "session_required": "请先在此浏览器中登录 DSM,然后重试。",
20
+ "failed": "无法完成登录。请检查帐户和密码,或联系管理员。"
21
+ },
22
+ "notices": {
23
+ "expired": "登录已过期,请重新登录。",
24
+ "revalidate": "请先在此浏览器中登录 DSM,然后选择“通过 DSM 继续”。",
25
+ "unavailable": "登录暂时不可用,请刷新后重试。"
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "title": "使用 Synology 帳號登入",
3
+ "intro": "使用這台 NAS 上的帳號登入此 App。",
4
+ "httpsTitle": "需要 HTTPS",
5
+ "failedTitle": "登入失敗",
6
+ "account": "帳號",
7
+ "password": "密碼",
8
+ "otpPrompt": "請輸入驗證器 App 中的驗證碼。",
9
+ "otp": "驗證碼",
10
+ "signingIn": "正在登入…",
11
+ "verify": "驗證並登入",
12
+ "signIn": "登入",
13
+ "otherAccount": "使用其他帳號",
14
+ "continueDSM": "以 DSM 繼續",
15
+ "errors": {
16
+ "rate_limited": "登入嘗試次數過多,請等候一分鐘再試。",
17
+ "https_required": "請使用 HTTPS 開啟此 App 以登入。",
18
+ "auth_unavailable": "DSM 登入目前無法使用,請再試一次。",
19
+ "session_required": "請先在此瀏覽器登入 DSM,然後再試一次。",
20
+ "failed": "無法完成登入。請檢查帳號與密碼,或聯絡管理員。"
21
+ },
22
+ "notices": {
23
+ "expired": "登入已逾時,請重新登入。",
24
+ "revalidate": "請先在此瀏覽器登入 DSM,然後選擇「以 DSM 繼續」。",
25
+ "unavailable": "登入目前無法使用,請重新整理後再試。"
26
+ }
27
+ }
@@ -0,0 +1,14 @@
1
+ import en from './i18n/en.json'
2
+ import zhTW from './i18n/zh-TW.json'
3
+ import zhCN from './i18n/zh-CN.json'
4
+ import ja from './i18n/ja.json'
5
+ import ko from './i18n/ko.json'
6
+ import de from './i18n/de.json'
7
+ import fr from './i18n/fr.json'
8
+ import es from './i18n/es.json'
9
+ import it from './i18n/it.json'
10
+ import {uiLocale} from '../nas/locale'
11
+ export type IdentityCopy=typeof en
12
+ export type IdentityNotice=''|keyof IdentityCopy['notices']
13
+ export const identityCatalogs:Record<string,IdentityCopy>={en,'zh-TW':zhTW,'zh-CN':zhCN,ja,ko,de,fr,es,it}
14
+ export function identityCopy(locale:string):IdentityCopy{return identityCatalogs[uiLocale(locale)]!}
@@ -8,6 +8,10 @@ test('discovers disabled identity without changing existing transport',async()=>
8
8
  const call=vi.fn().mockRejectedValue({code:'unknown_method'})
9
9
  const session=createSession(context(call));await session.start();expect(session.enabled.value).toBe(false);expect(session.ready.value).toBe(true);session.dispose()
10
10
  })
11
+ test('an Application Privileges refusal keeps the DSM shell instead of offering sign-in',async()=>{
12
+ const call=vi.fn().mockRejectedValue({code:'app_privilege_denied'})
13
+ const session=createSession(context(call));await session.start();expect(session.enabled.value).toBe(false);expect(session.notice.value).toBe('');session.dispose()
14
+ })
11
15
  test('bootstraps, expires and returns to login after a business rejection',async()=>{
12
16
  vi.useFakeTimers();const expiresAt=new Date(Date.now()+60000).toISOString()
13
17
  const call=vi.fn().mockResolvedValueOnce({enabled:true}).mockResolvedValueOnce({user:'alice',uid:'1205',expiresAt})
@@ -1,28 +1,29 @@
1
1
  import {ref} from 'vue'
2
2
  import type {Context} from '../context'
3
+ import type {IdentityNotice} from './i18n'
3
4
 
4
5
  export interface SessionSubject {user: string; uid: string; expiresAt: string}
5
6
  export function createSession(ctx: Context) {
6
7
  const enabled = ref(false)
7
8
  const ready = ref(false)
8
9
  const subject = ref<SessionSubject>()
9
- const notice = ref('')
10
+ const notice = ref<IdentityNotice>('')
10
11
  let disposed = false
11
12
  let revision = 0
12
13
  let expiry: ReturnType<typeof setTimeout> | undefined
13
14
  let poll: ReturnType<typeof setTimeout> | undefined
14
15
  function cancelTimers() {clearTimeout(expiry); clearTimeout(poll)}
15
- function clear(message = '') {revision++; cancelTimers(); subject.value = undefined; notice.value = message}
16
+ function clear(message: IdentityNotice = '') {revision++; cancelTimers(); subject.value = undefined; notice.value = message}
16
17
  function accept(value: SessionSubject) {
17
18
  if (disposed) return
18
19
  const remaining = Date.parse(value.expiresAt) - Date.now()
19
- if (!Number.isFinite(remaining) || remaining <= 0) {clear('Your session expired. Sign in again.'); return}
20
+ if (!Number.isFinite(remaining) || remaining <= 0) {clear('expired'); return}
20
21
  cancelTimers(); subject.value = value; notice.value = ''
21
- expiry = setTimeout(() => clear('Your session expired. Sign in again.'), remaining)
22
+ expiry = setTimeout(() => clear('expired'), remaining)
22
23
  const current = revision
23
24
  poll = setTimeout(async () => {
24
25
  try {const next = await ctx.call<SessionSubject>('identity.session'); if (!disposed && revision === current) accept(next)}
25
- catch {if (!disposed && revision === current) clear('Your session expired. Sign in again.')}
26
+ catch {if (!disposed && revision === current) clear('expired')}
26
27
  }, Math.min(60000, remaining))
27
28
  }
28
29
  async function start() {
@@ -37,8 +38,8 @@ export function createSession(ctx: Context) {
37
38
  } catch (e) {
38
39
  // Existing templates have no identity transport and retain their DSM shell.
39
40
  const code = (e as {code?: string})?.code
40
- enabled.value = !['unknown_method', 'admin_required', 'session_required'].includes(code || '')
41
- if (enabled.value) notice.value = 'Sign-in is unavailable. Refresh to try again.'
41
+ enabled.value = !['unknown_method', 'admin_required', 'app_privilege_denied', 'session_required'].includes(code || '')
42
+ if (enabled.value) notice.value = 'unavailable'
42
43
  } finally {if (!disposed) ready.value = true}
43
44
  }
44
45
  async function call<T = unknown>(method: string, params?: Record<string, unknown>): Promise<T> {
@@ -51,7 +52,7 @@ export function createSession(ctx: Context) {
51
52
  catch (e) {
52
53
  const code = (e as {code?: string})?.code
53
54
  if (!disposed && current === revision && enabled.value && ['session_required', 'session_revalidation_required'].includes(code || '')) {
54
- clear(code === 'session_revalidation_required' ? 'Sign in to DSM in this browser, then choose Continue with DSM.' : 'Your session expired. Sign in again.')
55
+ clear(code === 'session_revalidation_required' ? 'revalidate' : 'expired')
55
56
  }
56
57
  throw e
57
58
  }
@@ -1,23 +1,42 @@
1
1
  <script setup lang="ts">
2
- import {computed,ref,watch} from 'vue'
3
- import {Button,Dialog} from '@synopackageland/ui'
2
+ import {computed,onBeforeUnmount,ref,watch} from 'vue'
3
+ import {Button,Callout,Dialog} from '@synopackageland/ui'
4
4
  import FileBrowser from '../files/FileBrowser.vue'
5
5
  import type {NasProvider} from './contract'
6
6
  import {nasCopy} from './locale'
7
- const props=defineProps<{open:boolean;locale:string;provider:NasProvider;mode:'folder'|'file';title?:string;description?:string}>()
8
- const emit=defineEmits<{'update:open':[value:boolean];selected:[path:string]}>()
9
- const selected=ref<string>(),copy=computed(()=>nasCopy(props.locale))
10
- watch(()=>props.open,()=>{selected.value=undefined})
11
- function close(){selected.value=undefined;emit('update:open',false)}
12
- function confirm(){if(selected.value){emit('selected',selected.value);close()}}
7
+ import type {DestinationGrant,DestinationSelection} from '../delegate/long-running'
8
+ import {saveCopy,saveError} from '../delegate/save-copy'
9
+ const props=defineProps<{open:boolean;locale:string;provider:NasProvider;mode:'folder'|'file';title?:string;description?:string;destination?:DestinationSelection}>()
10
+ const emit=defineEmits<{'update:open':[value:boolean];selected:[path:string];authorized:[grant:DestinationGrant]}>()
11
+ const selected=ref<string>(),copy=computed(()=>nasCopy(props.locale)),save=computed(()=>saveCopy(props.locale)),busy=ref(false),error=ref<unknown>()
12
+ let generation=0,disposed=false
13
+ watch(()=>props.open,()=>{generation++;selected.value=undefined;error.value=undefined})
14
+ onBeforeUnmount(()=>{disposed=true;generation++})
15
+ function close(){if(busy.value)return;selected.value=undefined;emit('update:open',false)}
16
+ async function confirm(){
17
+ const path=selected.value,destination=props.destination,version=generation
18
+ if(!path||busy.value||!props.open||disposed||(destination&&props.mode!=='folder'))return
19
+ if(!destination){emit('selected',path);close();return}
20
+ busy.value=true;error.value=undefined
21
+ try{
22
+ const grant=await destination.selectDestination({key:destination.key,path})
23
+ if(disposed||version!==generation)return
24
+ if(!grant||typeof grant.id!=='string'||!grant.id||typeof grant.username!=='string'||!grant.username||grant.path!==path||grant.key!==destination.key||grant.lifetime!=='until-revoked')throw {code:'commit-uncertain'}
25
+ emit('authorized',grant);busy.value=false;close()
26
+ }catch(e){if(!disposed&&version===generation)error.value=e}
27
+ finally{if(!disposed)busy.value=false}
28
+ }
13
29
  </script>
14
30
  <template>
15
- <Dialog :open="open" :title="title??(mode==='folder'?copy.choose:copy.chooseFile)" :close-label="copy.close" width="800px" @update:open="value=>{if(!value)close()}">
16
- <p v-if="description">{{ description }}</p>
17
- <div class="nas-picker-content"><FileBrowser v-if="open" :provider="provider" :locale="locale" :mode="mode" @selected="selected=$event" /></div>
18
- <template #footer><Button variant="secondary" @click="close">{{ copy.cancel }}</Button><Button variant="primary" :disabled="!selected" @click="confirm">{{ copy.confirm }}</Button></template>
31
+ <Dialog :open="open" :title="title??(mode==='folder'?copy.choose:copy.chooseFile)" :description="description??copy.ownPermissions" :close-label="copy.close" :show-close="!busy" width="800px" @escape-key-down="event=>{if(busy)event.preventDefault()}" @interact-outside="event=>{if(busy)event.preventDefault()}" @update:open="value=>{if(!value)close()}">
32
+ <p v-if="destination" class="save-consent">{{ save.selection }}</p>
33
+ <Callout v-if="error" tone="danger" role="alert" class="save-message">{{ saveError(error,save) }}</Callout>
34
+ <div class="nas-picker-content" :aria-busy="busy" :inert="busy"><FileBrowser v-if="open" :provider="provider" :locale="locale" :mode="mode" @selected="selected=$event" /></div>
35
+ <template #footer><Button variant="secondary" :disabled="busy" @click="close">{{ copy.cancel }}</Button><Button variant="primary" :disabled="!selected||busy||!!destination&&mode!=='folder'" @click="confirm">{{ copy.confirm }}</Button></template>
19
36
  </Dialog>
20
37
  </template>
21
38
  <style scoped>
22
39
  .nas-picker-content { max-height: 65vh; overflow: auto; }
40
+ .save-message {--ui-text-secondary:var(--ui-text);}
41
+ .save-consent {color:var(--ui-text);margin-block:0 var(--ui-space-4,16px);}
23
42
  </style>
@@ -0,0 +1,48 @@
1
+ // @vitest-environment jsdom
2
+ import {afterEach,expect,test,vi} from 'vitest'
3
+ import {createApp,h,nextTick,ref} from 'vue'
4
+ import {AppRoot,ConfigProvider} from '@synopackageland/ui'
5
+ import NasPicker from './NasPicker.vue'
6
+ import {createNasProvider} from './provider'
7
+ import {nasCopy} from './locale'
8
+ const cleanup:Array<()=>void>=[]
9
+ afterEach(()=>cleanup.splice(0).forEach(fn=>fn()))
10
+ async function settle(){for(let i=0;i<30;i++){await Promise.resolve();await nextTick()}}
11
+ const grant={id:'d1',key:'save',path:'/home',username:'normal1',lifetime:'until-revoked' as const}
12
+ function fixture(selectDestination:any,mode:'folder'|'file'='folder'){
13
+ const root=document.createElement('div');document.body.append(root)
14
+ const selected=vi.fn(),authorized=vi.fn(),open=ref(true)
15
+ const provider=createNasProvider({call:vi.fn(async()=>({shares:[{name:'home',path:'/home',isdir:true}],offset:0,total:1})) as any})
16
+ const app=createApp({render:()=>h(ConfigProvider,{locale:'en'},()=>h(AppRoot,{},()=>h(NasPicker,{provider,locale:'en',mode,open:open.value,destination:{key:'save',selectDestination},onSelected:selected,onAuthorized:authorized,'onUpdate:open':v=>open.value=v})))})
17
+ app.config.idPrefix='destination-test';app.mount(root)
18
+ cleanup.push(()=>{app.unmount();provider.dispose();root.remove()})
19
+ return {root,open,selected,authorized,app}
20
+ }
21
+ function button(root:HTMLElement,label:string){const b=Array.from(root.querySelectorAll('button')).find(n=>n.textContent?.trim()===label||n.getAttribute('aria-label')===label);expect(b,label).toBeTruthy();return b!}
22
+ async function select(root:HTMLElement){await settle();button(root,'Select home').click();await settle();button(root,nasCopy('en').confirm).click();await settle()}
23
+ test('destination confirmation authorizes once with its manifest key, without a second consent dialog',async()=>{
24
+ const call=vi.fn(async()=>grant),f=fixture(call);await settle()
25
+ expect(f.root.textContent).toContain('after you sign out')
26
+ await select(f.root)
27
+ expect(call).toHaveBeenCalledExactlyOnceWith({key:'save',path:'/home'})
28
+ expect(f.authorized).toHaveBeenCalledExactlyOnceWith(grant)
29
+ expect(f.selected).not.toHaveBeenCalled();expect(f.open.value).toBe(false)
30
+ })
31
+ test('a rejected write/session check keeps the picker open and never emits a path or a grant',async()=>{
32
+ const f=fixture(vi.fn(async()=>{throw {code:'PERMISSION_DENIED',message:'secret SID'}}));await select(f.root)
33
+ expect(f.open.value).toBe(true);expect(f.selected).not.toHaveBeenCalled();expect(f.authorized).not.toHaveBeenCalled()
34
+ expect(f.root.querySelector('[role=alert]')?.textContent).toContain('permission')
35
+ expect(f.root.textContent).not.toContain('secret SID')
36
+ })
37
+ test('only folder destinations can authorize; a malformed grant is never reported as successful',async()=>{
38
+ const call=vi.fn(async()=>({...grant,path:'/elsewhere'})),f=fixture(call);await select(f.root)
39
+ expect(f.open.value).toBe(true);expect(f.authorized).not.toHaveBeenCalled()
40
+ const fileCall=vi.fn(async()=>grant),file=fixture(fileCall,'file');await settle()
41
+ expect(button(file.root,nasCopy('en').confirm).disabled).toBe(true);expect(fileCall).not.toHaveBeenCalled()
42
+ })
43
+ test('pending authorization prevents duplicate confirmation and ignores a late result after unmount',async()=>{
44
+ let resolve!:(value:typeof grant)=>void
45
+ const call=vi.fn(()=>new Promise(r=>resolve=r)),f=fixture(call);await select(f.root)
46
+ expect(button(f.root,nasCopy('en').confirm).disabled).toBe(true)
47
+ f.app.unmount();resolve(grant);await settle();expect(f.authorized).not.toHaveBeenCalled()
48
+ })
@@ -37,5 +37,5 @@
37
37
  "download": "Herunterladen",
38
38
  "uploaded": "Datei hochgeladen.",
39
39
  "errorDSM": "Melden Sie sich unter diesem Hostnamen bei DSM an, um auf NAS-Dateien zuzugreifen. Eine App-Anmeldung allein erlaubt keinen Zugriff auf File Station.",
40
- "errorUploadSize": "Wählen Sie eine Datei mit höchstens 16 GiB."
40
+ "errorUploadSize": "Wählen Sie eine Datei mit höchstens 16 GB aus."
41
41
  }
@@ -37,5 +37,5 @@
37
37
  "download": "Download",
38
38
  "uploaded": "File uploaded.",
39
39
  "errorDSM": "Sign in to DSM on this hostname to access NAS files. An App login alone cannot access File Station.",
40
- "errorUploadSize": "Choose one file up to 16 GiB."
40
+ "errorUploadSize": "Choose one file up to 16 GB."
41
41
  }