@synopackageland/cli 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (956) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +42 -1
  3. package/dist/build-spk/delete-app-data.d.ts +27 -7
  4. package/dist/build-spk/delete-app-data.js +35 -34
  5. package/dist/build-spk/dsm-arch.d.ts +6 -1
  6. package/dist/build-spk/dsm-arch.js +25 -1
  7. package/dist/build-spk/dsm-version.d.ts +14 -0
  8. package/dist/build-spk/dsm-version.js +47 -0
  9. package/dist/build-spk/gateway.d.ts +31 -0
  10. package/dist/build-spk/gateway.js +55 -0
  11. package/dist/build-spk/generator.d.ts +5 -0
  12. package/dist/build-spk/generator.js +106 -107
  13. package/dist/build-spk/install-wizard.d.ts +20 -0
  14. package/dist/build-spk/install-wizard.js +76 -0
  15. package/dist/build-spk/native-lifecycle.d.ts +5 -0
  16. package/dist/build-spk/native-lifecycle.js +12 -2
  17. package/dist/build-spk/notices.d.ts +5 -0
  18. package/dist/build-spk/notices.js +60 -0
  19. package/dist/build-spk/resource-worker.d.ts +9 -4
  20. package/dist/build-spk/resource-worker.js +15 -6
  21. package/dist/build-spk/share-combobox.d.ts +3 -0
  22. package/dist/build-spk/share-combobox.js +27 -0
  23. package/dist/build-spk/uninstall-wizard.d.ts +14 -0
  24. package/dist/build-spk/uninstall-wizard.js +33 -0
  25. package/dist/build-spk/wizard-i18n.d.ts +18 -0
  26. package/dist/build-spk/wizard-i18n.js +38 -0
  27. package/dist/build-spk/wizard-messages.d.ts +388 -0
  28. package/dist/build-spk/wizard-messages.js +387 -0
  29. package/dist/cli.js +136 -29
  30. package/dist/compose/analyze.d.ts +20 -0
  31. package/dist/compose/analyze.js +75 -11
  32. package/dist/contract/validate.js +33 -1
  33. package/dist/contract/web-launch.d.ts +22 -0
  34. package/dist/contract/web-launch.js +37 -0
  35. package/dist/deploy/deploy.d.ts +3 -0
  36. package/dist/deploy/deploy.js +11 -2
  37. package/dist/error-registry.js +80 -1
  38. package/dist/host/open-url.d.ts +2 -0
  39. package/dist/host/open-url.js +4 -1
  40. package/dist/images/pin.d.ts +52 -0
  41. package/dist/images/pin.js +249 -0
  42. package/dist/init.d.ts +29 -1
  43. package/dist/init.js +122 -25
  44. package/dist/inspect.d.ts +3 -0
  45. package/dist/inspect.js +15 -3
  46. package/dist/standalone/background.d.ts +21 -0
  47. package/dist/standalone/background.js +52 -0
  48. package/dist/standalone/binary.d.ts +1 -0
  49. package/dist/standalone/binary.js +1 -1
  50. package/dist/standalone/build.d.ts +2 -0
  51. package/dist/standalone/build.js +40 -6
  52. package/dist/standalone/daemon.d.ts +23 -0
  53. package/dist/standalone/daemon.js +114 -0
  54. package/dist/standalone/dsm-window.d.ts +1 -1
  55. package/dist/standalone/dsm-window.js +52 -12
  56. package/dist/standalone/helper-inventory.d.ts +31 -0
  57. package/dist/standalone/helper-inventory.js +11 -0
  58. package/dist/standalone/helper.d.ts +3 -12
  59. package/dist/standalone/helper.js +31 -12
  60. package/dist/standalone/host-adapter.d.ts +5 -0
  61. package/dist/standalone/host-adapter.js +166 -0
  62. package/dist/standalone/host-file-navigation.d.ts +7 -0
  63. package/dist/standalone/host-file-navigation.js +172 -0
  64. package/dist/standalone/host-platform.d.ts +13 -0
  65. package/dist/standalone/host-platform.js +42 -0
  66. package/dist/standalone/host-types.d.ts +49 -0
  67. package/dist/standalone/host-types.js +1 -0
  68. package/dist/standalone/inspect-helper.d.ts +6 -0
  69. package/dist/standalone/inspect-helper.js +93 -0
  70. package/dist/standalone/inspect-spk.d.ts +3 -1
  71. package/dist/standalone/inspect-spk.js +247 -5
  72. package/dist/standalone/job-diagnostics.d.ts +1 -0
  73. package/dist/standalone/job-diagnostics.js +49 -0
  74. package/dist/standalone/lifecycle-helper.d.ts +2 -0
  75. package/dist/standalone/lifecycle-helper.js +12 -0
  76. package/dist/standalone/lifecycle.d.ts +3 -0
  77. package/dist/standalone/lifecycle.js +63 -0
  78. package/dist/standalone/manifest.d.ts +17 -2
  79. package/dist/standalone/manifest.js +40 -6
  80. package/dist/standalone/native-layout.d.ts +74 -0
  81. package/dist/standalone/native-layout.js +318 -0
  82. package/dist/standalone/reopen-events.d.ts +2 -0
  83. package/dist/standalone/reopen-events.js +28 -0
  84. package/dist/standalone/resource.d.ts +11 -0
  85. package/dist/standalone/resource.js +13 -0
  86. package/dist/standalone/root-messages.js +9 -0
  87. package/dist/standalone/root-window.d.ts +6 -3
  88. package/dist/standalone/root-window.js +160 -30
  89. package/dist/standalone/shared-folder.d.ts +39 -0
  90. package/dist/standalone/shared-folder.js +141 -0
  91. package/dist/standalone/spk.d.ts +6 -3
  92. package/dist/standalone/spk.js +52 -35
  93. package/dist/standalone/worker-contract-json.d.ts +8 -0
  94. package/dist/standalone/worker-contract-json.js +141 -0
  95. package/dist/standalone/worker-contract.d.ts +189 -0
  96. package/dist/standalone/worker-contract.js +175 -0
  97. package/dist/standalone/worker-registry.d.ts +40 -0
  98. package/dist/standalone/worker-registry.js +167 -0
  99. package/dist/template-paths.d.ts +2 -0
  100. package/dist/template-paths.js +9 -0
  101. package/dist/templates/_daemon/fixture_linux_test.go +15 -0
  102. package/dist/templates/_daemon/fixture_other_test.go +7 -0
  103. package/dist/templates/_daemon/go.mod +5 -0
  104. package/dist/templates/_daemon/main.go +608 -0
  105. package/dist/templates/_daemon/main_test.go +242 -0
  106. package/dist/templates/_daemon/process_linux.go +55 -0
  107. package/dist/templates/_daemon/process_linux_test.go +161 -0
  108. package/dist/templates/_daemon/process_other.go +14 -0
  109. package/dist/templates/_daemon/testdata/child.go +41 -0
  110. package/dist/templates/_gateway/auth.go +101 -0
  111. package/dist/templates/_gateway/auth_test.go +216 -0
  112. package/dist/templates/_gateway/cgi.go +133 -0
  113. package/dist/templates/_gateway/cgi_test.go +156 -0
  114. package/dist/templates/_gateway/csrf.go +73 -0
  115. package/dist/templates/_gateway/csrf_test.go +155 -0
  116. package/dist/templates/_gateway/directory.go +108 -0
  117. package/dist/templates/_gateway/directory_test.go +202 -0
  118. package/dist/templates/_gateway/gateway.go +412 -0
  119. package/dist/templates/_gateway/gateway_test.go +676 -0
  120. package/dist/templates/_gateway/go.mod +3 -0
  121. package/dist/templates/_gateway/groups.go +66 -0
  122. package/dist/templates/_gateway/main.go +45 -0
  123. package/dist/templates/_shared/GO-LICENSE +27 -0
  124. package/dist/templates/_shared/GO-PATENTS +22 -0
  125. package/dist/templates/_shared/LICENSES/TEMPLATE.txt +21 -0
  126. package/dist/templates/_shared/notice-overrides/index.json +14 -0
  127. package/dist/templates/_shared/notice-overrides/utils-0.4.2-LICENSE +21 -0
  128. package/dist/templates/_shared/notice-overrides/utils-0.5.0-LICENSE +21 -0
  129. package/dist/templates/_shared/third-party-notices.mjs +51 -0
  130. package/dist/templates/binary/synology-app.yaml +1 -1
  131. package/dist/templates/compose-import/compose.yaml +1 -1
  132. package/dist/templates/compose-import/synology-app.yaml +1 -1
  133. package/dist/templates/hello-files/compose.yaml +1 -1
  134. package/dist/templates/hello-files/synology-app.yaml +1 -1
  135. package/dist/templates/hello-web/compose.yaml +5 -2
  136. package/dist/templates/hello-web/synology-app.yaml +4 -1
  137. package/dist/templates/hello-web-page/compose.yaml +5 -2
  138. package/dist/templates/hello-web-page/synology-app.yaml +4 -1
  139. package/dist/templates/native-go/README.md +149 -4
  140. package/dist/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +61 -0
  141. package/dist/templates/native-go/backend/cmd/app/main.go +17 -0
  142. package/dist/templates/native-go/backend/cmd/app/sdk_main.go +60 -0
  143. package/dist/templates/native-go/backend/cmd/background-worker/main.go +38 -0
  144. package/dist/templates/native-go/backend/cmd/dsm-readonly-probe/main_linux.go +46 -0
  145. package/dist/templates/native-go/backend/cmd/helper/main.go +10 -1
  146. package/dist/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
  147. package/dist/templates/native-go/backend/go.mod +7 -1
  148. package/dist/templates/native-go/backend/go.sum +4 -0
  149. package/dist/templates/native-go/backend/internal/api/binary.go +154 -0
  150. package/dist/templates/native-go/backend/internal/api/binary_test.go +165 -0
  151. package/dist/templates/native-go/backend/internal/api/registry.go +28 -7
  152. package/dist/templates/native-go/backend/internal/api/server.go +11 -1
  153. package/dist/templates/native-go/backend/internal/app/background.go +270 -0
  154. package/dist/templates/native-go/backend/internal/app/background_none.go +8 -0
  155. package/dist/templates/native-go/backend/internal/app/background_owner.go +59 -0
  156. package/dist/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
  157. package/dist/templates/native-go/backend/internal/app/background_schedule.go +74 -0
  158. package/dist/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
  159. package/dist/templates/native-go/backend/internal/app/background_test.go +346 -0
  160. package/dist/templates/native-go/backend/internal/app/integration_state.go +16 -0
  161. package/dist/templates/native-go/backend/internal/app/migrations.go +41 -0
  162. package/dist/templates/native-go/backend/internal/app/migrations_test.go +41 -0
  163. package/dist/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +129 -0
  164. package/dist/templates/native-go/backend/internal/app/nas_refusal_test.go +46 -0
  165. package/dist/templates/native-go/backend/internal/app/routes.go +28 -3
  166. package/dist/templates/native-go/backend/internal/app/routes_test.go +27 -5
  167. package/dist/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
  168. package/dist/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
  169. package/dist/templates/native-go/backend/internal/app/sdk_routes.go +174 -0
  170. package/dist/templates/native-go/backend/internal/app/session_files.go +15 -0
  171. package/dist/templates/native-go/backend/internal/app/session_files_test.go +26 -0
  172. package/dist/templates/native-go/backend/internal/app/shared_folder.go +144 -0
  173. package/dist/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
  174. package/dist/templates/native-go/backend/internal/background/access.go +57 -0
  175. package/dist/templates/native-go/backend/internal/background/owner_test.go +126 -0
  176. package/dist/templates/native-go/backend/internal/background/runner.go +185 -0
  177. package/dist/templates/native-go/backend/internal/background/runner_test.go +209 -0
  178. package/dist/templates/native-go/backend/internal/background/schedule.go +300 -0
  179. package/dist/templates/native-go/backend/internal/background/schedule_test.go +335 -0
  180. package/dist/templates/native-go/backend/internal/background/store.go +807 -0
  181. package/dist/templates/native-go/backend/internal/background/store_test.go +407 -0
  182. package/dist/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
  183. package/dist/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
  184. package/dist/templates/native-go/backend/internal/dsmprobe/collector_linux.go +335 -0
  185. package/dist/templates/native-go/backend/internal/dsmprobe/collector_linux_test.go +41 -0
  186. package/dist/templates/native-go/backend/internal/dsmprobe/protocol.go +179 -0
  187. package/dist/templates/native-go/backend/internal/dsmprobe/protocol_test.go +29 -0
  188. package/dist/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
  189. package/dist/templates/native-go/backend/internal/filestation/client.go +251 -0
  190. package/dist/templates/native-go/backend/internal/filestation/client_test.go +155 -0
  191. package/dist/templates/native-go/backend/internal/filestation/doc.go +4 -0
  192. package/dist/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
  193. package/dist/templates/native-go/backend/internal/filestation/repository.go +207 -0
  194. package/dist/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
  195. package/dist/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
  196. package/dist/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
  197. package/dist/templates/native-go/backend/internal/filestation/service.go +254 -0
  198. package/dist/templates/native-go/backend/internal/filestation/service_test.go +94 -0
  199. package/dist/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
  200. package/dist/templates/native-go/backend/internal/filestation/write.go +72 -0
  201. package/dist/templates/native-go/backend/internal/filestation/write_test.go +123 -0
  202. package/dist/templates/native-go/backend/internal/helper/background_proof.go +163 -0
  203. package/dist/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
  204. package/dist/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
  205. package/dist/templates/native-go/backend/internal/helper/cohort.go +393 -0
  206. package/dist/templates/native-go/backend/internal/helper/cohort_publication.go +18 -0
  207. package/dist/templates/native-go/backend/internal/helper/cohort_publication_test.go +105 -0
  208. package/dist/templates/native-go/backend/internal/helper/cohort_test.go +372 -0
  209. package/dist/templates/native-go/backend/internal/helper/control.go +226 -21
  210. package/dist/templates/native-go/backend/internal/helper/control_test.go +10 -2
  211. package/dist/templates/native-go/backend/internal/helper/data_contract.go +245 -0
  212. package/dist/templates/native-go/backend/internal/helper/data_contract_test.go +51 -0
  213. package/dist/templates/native-go/backend/internal/helper/data_decode.go +184 -0
  214. package/dist/templates/native-go/backend/internal/helper/data_decode_pointer_test.go +30 -0
  215. package/dist/templates/native-go/backend/internal/helper/data_protocol.go +419 -0
  216. package/dist/templates/native-go/backend/internal/helper/data_protocol_test.go +449 -0
  217. package/dist/templates/native-go/backend/internal/helper/dsm_acl_linux.go +139 -0
  218. package/dist/templates/native-go/backend/internal/helper/dsm_acl_linux_test.go +121 -0
  219. package/dist/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux.go +95 -0
  220. package/dist/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux_test.go +56 -0
  221. package/dist/templates/native-go/backend/internal/helper/dsm_bridge_linux.go +144 -0
  222. package/dist/templates/native-go/backend/internal/helper/dsm_bridge_linux_test.go +89 -0
  223. package/dist/templates/native-go/backend/internal/helper/dsm_home_linux.go +107 -0
  224. package/dist/templates/native-go/backend/internal/helper/dsm_home_linux_test.go +82 -0
  225. package/dist/templates/native-go/backend/internal/helper/dsm_probe_transport_linux.go +151 -0
  226. package/dist/templates/native-go/backend/internal/helper/dsm_probe_transport_linux_test.go +66 -0
  227. package/dist/templates/native-go/backend/internal/helper/grant_authority.go +519 -0
  228. package/dist/templates/native-go/backend/internal/helper/grant_authority_contract.go +88 -0
  229. package/dist/templates/native-go/backend/internal/helper/grant_authority_test.go +510 -0
  230. package/dist/templates/native-go/backend/internal/helper/grant_cohort.go +389 -0
  231. package/dist/templates/native-go/backend/internal/helper/grant_cohort_test.go +239 -0
  232. package/dist/templates/native-go/backend/internal/helper/grant_delivery.go +49 -0
  233. package/dist/templates/native-go/backend/internal/helper/grant_delivery_methods.go +273 -0
  234. package/dist/templates/native-go/backend/internal/helper/grant_delivery_test.go +322 -0
  235. package/dist/templates/native-go/backend/internal/helper/grant_operation_contract.go +47 -0
  236. package/dist/templates/native-go/backend/internal/helper/grant_readonly_test.go +180 -0
  237. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux.go +416 -0
  238. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +469 -0
  239. package/dist/templates/native-go/backend/internal/helper/grant_rpc.go +147 -0
  240. package/dist/templates/native-go/backend/internal/helper/grant_rpc_test.go +51 -0
  241. package/dist/templates/native-go/backend/internal/helper/grant_snapshot.go +78 -0
  242. package/dist/templates/native-go/backend/internal/helper/grant_supervisor_linux.go +134 -0
  243. package/dist/templates/native-go/backend/internal/helper/grant_supervisor_linux_test.go +254 -0
  244. package/dist/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
  245. package/dist/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
  246. package/dist/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
  247. package/dist/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
  248. package/dist/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
  249. package/dist/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
  250. package/dist/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
  251. package/dist/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
  252. package/dist/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
  253. package/dist/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
  254. package/dist/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
  255. package/dist/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
  256. package/dist/templates/native-go/backend/internal/helper/lease.go +112 -0
  257. package/dist/templates/native-go/backend/internal/helper/lease_linux.go +44 -0
  258. package/dist/templates/native-go/backend/internal/helper/lease_other.go +8 -0
  259. package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
  260. package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
  261. package/dist/templates/native-go/backend/internal/helper/lifecycle.go +234 -0
  262. package/dist/templates/native-go/backend/internal/helper/lifecycle_test.go +473 -0
  263. package/dist/templates/native-go/backend/internal/helper/managed_pilot.go +284 -0
  264. package/dist/templates/native-go/backend/internal/helper/managed_pilot_repository_linux.go +74 -0
  265. package/dist/templates/native-go/backend/internal/helper/managed_pilot_repository_linux_test.go +40 -0
  266. package/dist/templates/native-go/backend/internal/helper/managed_pilot_test.go +210 -0
  267. package/dist/templates/native-go/backend/internal/helper/management.go +79 -0
  268. package/dist/templates/native-go/backend/internal/helper/nas_shipped_refusal_linux_test.go +97 -0
  269. package/dist/templates/native-go/backend/internal/helper/native_discovery.go +79 -0
  270. package/dist/templates/native-go/backend/internal/helper/native_identity.go +89 -0
  271. package/dist/templates/native-go/backend/internal/helper/native_provider.go +159 -0
  272. package/dist/templates/native-go/backend/internal/helper/native_provider_test.go +421 -0
  273. package/dist/templates/native-go/backend/internal/helper/observation.go +244 -0
  274. package/dist/templates/native-go/backend/internal/helper/observation_health_test.go +127 -0
  275. package/dist/templates/native-go/backend/internal/helper/observation_reload_budget_test.go +117 -0
  276. package/dist/templates/native-go/backend/internal/helper/observation_test.go +196 -0
  277. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic.go +155 -0
  278. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux.go +76 -0
  279. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +130 -0
  280. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_test.go +98 -0
  281. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
  282. package/dist/templates/native-go/backend/internal/helper/operation_bootstrap_linux.go +193 -0
  283. package/dist/templates/native-go/backend/internal/helper/operation_credentials_linux.go +56 -0
  284. package/dist/templates/native-go/backend/internal/helper/operation_linux.go +480 -0
  285. package/dist/templates/native-go/backend/internal/helper/operation_linux_test.go +528 -0
  286. package/dist/templates/native-go/backend/internal/helper/process_linux.go +14 -1
  287. package/dist/templates/native-go/backend/internal/helper/publication_test.go +178 -0
  288. package/dist/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
  289. package/dist/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
  290. package/dist/templates/native-go/backend/internal/helper/read_stream_cohort_linux_test.go +156 -0
  291. package/dist/templates/native-go/backend/internal/helper/read_transfer.go +40 -0
  292. package/dist/templates/native-go/backend/internal/helper/read_transfer_linux.go +109 -0
  293. package/dist/templates/native-go/backend/internal/helper/read_transfer_linux_test.go +118 -0
  294. package/dist/templates/native-go/backend/internal/helper/read_transfer_test.go +177 -0
  295. package/dist/templates/native-go/backend/internal/helper/readonly.go +105 -0
  296. package/dist/templates/native-go/backend/internal/helper/readonly_admission.go +85 -0
  297. package/dist/templates/native-go/backend/internal/helper/readonly_cohort_linux_test.go +253 -0
  298. package/dist/templates/native-go/backend/internal/helper/readonly_linux_test.go +378 -0
  299. package/dist/templates/native-go/backend/internal/helper/readonly_mount_linux.go +65 -0
  300. package/dist/templates/native-go/backend/internal/helper/readonly_mount_proxy_linux.go +113 -0
  301. package/dist/templates/native-go/backend/internal/helper/readonly_operations_linux.go +168 -0
  302. package/dist/templates/native-go/backend/internal/helper/readonly_resolver_linux.go +241 -0
  303. package/dist/templates/native-go/backend/internal/helper/readonly_test.go +40 -0
  304. package/dist/templates/native-go/backend/internal/helper/relaxed_identity.go +252 -0
  305. package/dist/templates/native-go/backend/internal/helper/relaxed_identity_contract.go +105 -0
  306. package/dist/templates/native-go/backend/internal/helper/relaxed_identity_test.go +406 -0
  307. package/dist/templates/native-go/backend/internal/helper/relaxed_invalidation.go +203 -0
  308. package/dist/templates/native-go/backend/internal/helper/repair.go +132 -0
  309. package/dist/templates/native-go/backend/internal/helper/repair_test.go +271 -0
  310. package/dist/templates/native-go/backend/internal/helper/s1r_actor_acl_linux_test.go +303 -0
  311. package/dist/templates/native-go/backend/internal/helper/s1r_actor_fixture_linux_test.go +184 -0
  312. package/dist/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +250 -0
  313. package/dist/templates/native-go/backend/internal/helper/s1r_fixture_contract_linux_test.go +18 -0
  314. package/dist/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
  315. package/dist/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
  316. package/dist/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
  317. package/dist/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
  318. package/dist/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
  319. package/dist/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
  320. package/dist/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
  321. package/dist/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
  322. package/dist/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
  323. package/dist/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
  324. package/dist/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
  325. package/dist/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
  326. package/dist/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
  327. package/dist/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
  328. package/dist/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
  329. package/dist/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
  330. package/dist/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
  331. package/dist/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
  332. package/dist/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
  333. package/dist/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
  334. package/dist/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
  335. package/dist/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
  336. package/dist/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
  337. package/dist/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
  338. package/dist/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
  339. package/dist/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
  340. package/dist/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
  341. package/dist/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
  342. package/dist/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
  343. package/dist/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
  344. package/dist/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
  345. package/dist/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
  346. package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
  347. package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
  348. package/dist/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
  349. package/dist/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
  350. package/dist/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
  351. package/dist/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
  352. package/dist/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
  353. package/dist/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
  354. package/dist/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
  355. package/dist/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
  356. package/dist/templates/native-go/backend/internal/helper/sdk_server_linux.go +152 -0
  357. package/dist/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
  358. package/dist/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
  359. package/dist/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
  360. package/dist/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
  361. package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
  362. package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
  363. package/dist/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
  364. package/dist/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
  365. package/dist/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
  366. package/dist/templates/native-go/backend/internal/helper/server_linux.go +47 -3
  367. package/dist/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
  368. package/dist/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
  369. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
  370. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
  371. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
  372. package/dist/templates/native-go/backend/internal/helper/status.go +83 -11
  373. package/dist/templates/native-go/backend/internal/helper/status_test.go +128 -0
  374. package/dist/templates/native-go/backend/internal/helper/supervision.go +28 -5
  375. package/dist/templates/native-go/backend/internal/helper/supervisor_frame.go +79 -0
  376. package/dist/templates/native-go/backend/internal/helper/supervisor_frame_linux_test.go +69 -0
  377. package/dist/templates/native-go/backend/internal/helper/supervisor_frame_test.go +107 -0
  378. package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +191 -16
  379. package/dist/templates/native-go/backend/internal/helper/supervisor_linux_test.go +618 -7
  380. package/dist/templates/native-go/backend/internal/helper/supervisor_socket_eof_test.go +74 -0
  381. package/dist/templates/native-go/backend/internal/helper/supervisor_socket_test.go +45 -0
  382. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/create.json +23 -0
  383. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/frames.json +67 -0
  384. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/grant-store.json +52 -0
  385. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/intent.json +20 -0
  386. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/list.json +20 -0
  387. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/publish.json +20 -0
  388. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/read.json +22 -0
  389. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/stat.json +22 -0
  390. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/write-stream.json +22 -0
  391. package/dist/templates/native-go/backend/internal/helper/unit_connection.go +75 -0
  392. package/dist/templates/native-go/backend/internal/helper/unit_connection_linux_test.go +135 -0
  393. package/dist/templates/native-go/backend/internal/helper/unit_connection_test.go +151 -0
  394. package/dist/templates/native-go/backend/internal/helper/unit_frame_test.go +32 -0
  395. package/dist/templates/native-go/backend/internal/helper/unit_linux.go +368 -0
  396. package/dist/templates/native-go/backend/internal/helper/unit_linux_test.go +46 -0
  397. package/dist/templates/native-go/backend/internal/helper/unit_mechanisms_linux_test.go +217 -0
  398. package/dist/templates/native-go/backend/internal/helper/unit_padding_linux_test.go +178 -0
  399. package/dist/templates/native-go/backend/internal/helper/unit_query_linux.go +115 -0
  400. package/dist/templates/native-go/backend/internal/helper/unit_reload_linux_test.go +372 -0
  401. package/dist/templates/native-go/backend/internal/helper/unit_reload_sequence_linux_test.go +232 -0
  402. package/dist/templates/native-go/backend/internal/helper/write.go +77 -0
  403. package/dist/templates/native-go/backend/internal/helper/write_admission.go +260 -0
  404. package/dist/templates/native-go/backend/internal/helper/write_admission_test.go +135 -0
  405. package/dist/templates/native-go/backend/internal/helper/write_cohort_linux_test.go +218 -0
  406. package/dist/templates/native-go/backend/internal/helper/write_files_linux.go +205 -0
  407. package/dist/templates/native-go/backend/internal/helper/write_files_linux_test.go +225 -0
  408. package/dist/templates/native-go/backend/internal/helper/write_intent_linux.go +116 -0
  409. package/dist/templates/native-go/backend/internal/helper/write_intent_linux_test.go +74 -0
  410. package/dist/templates/native-go/backend/internal/helper/write_operation_linux.go +245 -0
  411. package/dist/templates/native-go/backend/internal/helper/write_test.go +53 -0
  412. package/dist/templates/native-go/dsm-package.yaml +1 -1
  413. package/dist/templates/native-go/ui/app.js +8 -1
  414. package/dist/templates/native-go-background/BACKGROUND.md +111 -0
  415. package/dist/templates/native-go-background/backend/internal/app/background_on.go +7 -0
  416. package/dist/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
  417. package/dist/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
  418. package/dist/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
  419. package/dist/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
  420. package/dist/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
  421. package/dist/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
  422. package/dist/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
  423. package/dist/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
  424. package/dist/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
  425. package/dist/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
  426. package/dist/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
  427. package/dist/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
  428. package/dist/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
  429. package/dist/templates/native-go-background/frontend/test/background.test.ts +179 -0
  430. package/dist/templates/native-go-better-auth/node/build.mjs +2 -0
  431. package/dist/templates/native-go-integration/backend/internal/app/personal.go +2 -2
  432. package/dist/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
  433. package/dist/templates/native-go-vue/README.md +151 -6
  434. package/dist/templates/native-go-vue/frontend/DESIGN.md +16 -4
  435. package/dist/templates/native-go-vue/frontend/README-JOBS.md +75 -0
  436. package/dist/templates/native-go-vue/frontend/README-M2.md +64 -0
  437. package/dist/templates/native-go-vue/frontend/package-lock.json +137 -233
  438. package/dist/templates/native-go-vue/frontend/package.json +2 -2
  439. package/dist/templates/native-go-vue/frontend/src/App.vue +71 -16
  440. package/dist/templates/native-go-vue/frontend/src/M2App.vue +57 -0
  441. package/dist/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
  442. package/dist/templates/native-go-vue/frontend/src/context.ts +41 -2
  443. package/dist/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
  444. package/dist/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
  445. package/dist/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
  446. package/dist/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
  447. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
  448. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
  449. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
  450. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
  451. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
  452. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
  453. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
  454. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
  455. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
  456. package/dist/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
  457. package/dist/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
  458. package/dist/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
  459. package/dist/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
  460. package/dist/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
  461. package/dist/templates/native-go-vue/frontend/src/m2-style.css +7 -0
  462. package/dist/templates/native-go-vue/frontend/src/main.ts +4 -1
  463. package/dist/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
  464. package/dist/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
  465. package/dist/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
  466. package/dist/templates/native-go-vue/frontend/src/nas/NasGrantSettings.vue +74 -0
  467. package/dist/templates/native-go-vue/frontend/src/nas/NasPathPicker.vue +106 -0
  468. package/dist/templates/native-go-vue/frontend/src/nas/NasUnavailable.vue +20 -0
  469. package/dist/templates/native-go-vue/frontend/src/nas/i18n/de.json +74 -0
  470. package/dist/templates/native-go-vue/frontend/src/nas/i18n/en.json +74 -0
  471. package/dist/templates/native-go-vue/frontend/src/nas/i18n/es.json +74 -0
  472. package/dist/templates/native-go-vue/frontend/src/nas/i18n/fr.json +74 -0
  473. package/dist/templates/native-go-vue/frontend/src/nas/i18n/it.json +74 -0
  474. package/dist/templates/native-go-vue/frontend/src/nas/i18n/ja.json +74 -0
  475. package/dist/templates/native-go-vue/frontend/src/nas/i18n/ko.json +74 -0
  476. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
  477. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
  478. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
  479. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
  480. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
  481. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
  482. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
  483. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
  484. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
  485. package/dist/templates/native-go-vue/frontend/src/nas/i18n/zh-CN.json +74 -0
  486. package/dist/templates/native-go-vue/frontend/src/nas/i18n/zh-TW.json +74 -0
  487. package/dist/templates/native-go-vue/frontend/src/nas/i18n.ts +38 -0
  488. package/dist/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
  489. package/dist/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
  490. package/dist/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
  491. package/dist/templates/native-go-vue/frontend/src/nas/mock-provider.ts +119 -0
  492. package/dist/templates/native-go-vue/frontend/src/nas/provider.ts +59 -0
  493. package/dist/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
  494. package/dist/templates/native-go-vue/frontend/src/nas/use-request.ts +27 -0
  495. package/dist/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
  496. package/dist/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
  497. package/dist/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
  498. package/dist/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
  499. package/dist/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
  500. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
  501. package/dist/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
  502. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
  503. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
  504. package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
  505. package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
  506. package/dist/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
  507. package/dist/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
  508. package/dist/templates/native-go-vue/frontend/src/style.css +19 -6
  509. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +65 -2
  510. package/dist/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
  511. package/dist/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
  512. package/dist/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
  513. package/dist/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
  514. package/dist/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
  515. package/dist/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
  516. package/dist/templates/native-go-vue/frontend/test/nas-provider.test.ts +81 -0
  517. package/dist/templates/native-go-vue/frontend/test/nas-request.test.ts +21 -0
  518. package/dist/templates/native-go-vue/frontend/test/nas-ui.test.ts +261 -0
  519. package/dist/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
  520. package/dist/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
  521. package/dist/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
  522. package/dist/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
  523. package/dist/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
  524. package/dist/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
  525. package/dist/templates/native-go-vue/frontend/tsconfig.json +1 -1
  526. package/dist/templates/native-go-vue/frontend/vite.config.ts +8 -6
  527. package/dist/validate.js +6 -3
  528. package/package.json +3 -2
  529. package/schema/synology-app.schema.json +19 -0
  530. package/skills/reference/create.md +4 -0
  531. package/templates/_daemon/fixture_linux_test.go +15 -0
  532. package/templates/_daemon/fixture_other_test.go +7 -0
  533. package/templates/_daemon/go.mod +5 -0
  534. package/templates/_daemon/main.go +608 -0
  535. package/templates/_daemon/main_test.go +242 -0
  536. package/templates/_daemon/process_linux.go +55 -0
  537. package/templates/_daemon/process_linux_test.go +161 -0
  538. package/templates/_daemon/process_other.go +14 -0
  539. package/templates/_daemon/testdata/child.go +41 -0
  540. package/templates/_gateway/auth.go +101 -0
  541. package/templates/_gateway/auth_test.go +216 -0
  542. package/templates/_gateway/cgi.go +133 -0
  543. package/templates/_gateway/cgi_test.go +156 -0
  544. package/templates/_gateway/csrf.go +73 -0
  545. package/templates/_gateway/csrf_test.go +155 -0
  546. package/templates/_gateway/directory.go +108 -0
  547. package/templates/_gateway/directory_test.go +202 -0
  548. package/templates/_gateway/gateway.go +412 -0
  549. package/templates/_gateway/gateway_test.go +676 -0
  550. package/templates/_gateway/go.mod +3 -0
  551. package/templates/_gateway/groups.go +66 -0
  552. package/templates/_gateway/main.go +45 -0
  553. package/templates/_shared/GO-LICENSE +27 -0
  554. package/templates/_shared/GO-PATENTS +22 -0
  555. package/templates/_shared/LICENSES/TEMPLATE.txt +21 -0
  556. package/templates/_shared/notice-overrides/index.json +14 -0
  557. package/templates/_shared/notice-overrides/utils-0.4.2-LICENSE +21 -0
  558. package/templates/_shared/notice-overrides/utils-0.5.0-LICENSE +21 -0
  559. package/templates/_shared/third-party-notices.mjs +51 -0
  560. package/templates/binary/synology-app.yaml +1 -1
  561. package/templates/compose-import/compose.yaml +1 -1
  562. package/templates/compose-import/synology-app.yaml +1 -1
  563. package/templates/hello-files/compose.yaml +1 -1
  564. package/templates/hello-files/synology-app.yaml +1 -1
  565. package/templates/hello-web/compose.yaml +5 -2
  566. package/templates/hello-web/synology-app.yaml +4 -1
  567. package/templates/hello-web-page/compose.yaml +5 -2
  568. package/templates/hello-web-page/synology-app.yaml +4 -1
  569. package/templates/native-go/README.md +149 -4
  570. package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +61 -0
  571. package/templates/native-go/backend/cmd/app/main.go +17 -0
  572. package/templates/native-go/backend/cmd/app/sdk_main.go +60 -0
  573. package/templates/native-go/backend/cmd/background-worker/main.go +38 -0
  574. package/templates/native-go/backend/cmd/dsm-readonly-probe/main_linux.go +46 -0
  575. package/templates/native-go/backend/cmd/helper/main.go +10 -1
  576. package/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
  577. package/templates/native-go/backend/go.mod +7 -1
  578. package/templates/native-go/backend/go.sum +4 -0
  579. package/templates/native-go/backend/internal/api/binary.go +154 -0
  580. package/templates/native-go/backend/internal/api/binary_test.go +165 -0
  581. package/templates/native-go/backend/internal/api/registry.go +28 -7
  582. package/templates/native-go/backend/internal/api/server.go +11 -1
  583. package/templates/native-go/backend/internal/app/background.go +270 -0
  584. package/templates/native-go/backend/internal/app/background_none.go +8 -0
  585. package/templates/native-go/backend/internal/app/background_owner.go +59 -0
  586. package/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
  587. package/templates/native-go/backend/internal/app/background_schedule.go +74 -0
  588. package/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
  589. package/templates/native-go/backend/internal/app/background_test.go +346 -0
  590. package/templates/native-go/backend/internal/app/integration_state.go +16 -0
  591. package/templates/native-go/backend/internal/app/migrations.go +41 -0
  592. package/templates/native-go/backend/internal/app/migrations_test.go +41 -0
  593. package/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +129 -0
  594. package/templates/native-go/backend/internal/app/nas_refusal_test.go +46 -0
  595. package/templates/native-go/backend/internal/app/routes.go +28 -3
  596. package/templates/native-go/backend/internal/app/routes_test.go +27 -5
  597. package/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
  598. package/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
  599. package/templates/native-go/backend/internal/app/sdk_routes.go +174 -0
  600. package/templates/native-go/backend/internal/app/session_files.go +15 -0
  601. package/templates/native-go/backend/internal/app/session_files_test.go +26 -0
  602. package/templates/native-go/backend/internal/app/shared_folder.go +144 -0
  603. package/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
  604. package/templates/native-go/backend/internal/background/access.go +57 -0
  605. package/templates/native-go/backend/internal/background/owner_test.go +126 -0
  606. package/templates/native-go/backend/internal/background/runner.go +185 -0
  607. package/templates/native-go/backend/internal/background/runner_test.go +209 -0
  608. package/templates/native-go/backend/internal/background/schedule.go +300 -0
  609. package/templates/native-go/backend/internal/background/schedule_test.go +335 -0
  610. package/templates/native-go/backend/internal/background/store.go +807 -0
  611. package/templates/native-go/backend/internal/background/store_test.go +407 -0
  612. package/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
  613. package/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
  614. package/templates/native-go/backend/internal/dsmprobe/collector_linux.go +335 -0
  615. package/templates/native-go/backend/internal/dsmprobe/collector_linux_test.go +41 -0
  616. package/templates/native-go/backend/internal/dsmprobe/protocol.go +179 -0
  617. package/templates/native-go/backend/internal/dsmprobe/protocol_test.go +29 -0
  618. package/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
  619. package/templates/native-go/backend/internal/filestation/client.go +251 -0
  620. package/templates/native-go/backend/internal/filestation/client_test.go +155 -0
  621. package/templates/native-go/backend/internal/filestation/doc.go +4 -0
  622. package/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
  623. package/templates/native-go/backend/internal/filestation/repository.go +207 -0
  624. package/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
  625. package/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
  626. package/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
  627. package/templates/native-go/backend/internal/filestation/service.go +254 -0
  628. package/templates/native-go/backend/internal/filestation/service_test.go +94 -0
  629. package/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
  630. package/templates/native-go/backend/internal/filestation/write.go +72 -0
  631. package/templates/native-go/backend/internal/filestation/write_test.go +123 -0
  632. package/templates/native-go/backend/internal/helper/background_proof.go +163 -0
  633. package/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
  634. package/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
  635. package/templates/native-go/backend/internal/helper/cohort.go +393 -0
  636. package/templates/native-go/backend/internal/helper/cohort_publication.go +18 -0
  637. package/templates/native-go/backend/internal/helper/cohort_publication_test.go +105 -0
  638. package/templates/native-go/backend/internal/helper/cohort_test.go +372 -0
  639. package/templates/native-go/backend/internal/helper/control.go +226 -21
  640. package/templates/native-go/backend/internal/helper/control_test.go +10 -2
  641. package/templates/native-go/backend/internal/helper/data_contract.go +245 -0
  642. package/templates/native-go/backend/internal/helper/data_contract_test.go +51 -0
  643. package/templates/native-go/backend/internal/helper/data_decode.go +184 -0
  644. package/templates/native-go/backend/internal/helper/data_decode_pointer_test.go +30 -0
  645. package/templates/native-go/backend/internal/helper/data_protocol.go +419 -0
  646. package/templates/native-go/backend/internal/helper/data_protocol_test.go +449 -0
  647. package/templates/native-go/backend/internal/helper/dsm_acl_linux.go +139 -0
  648. package/templates/native-go/backend/internal/helper/dsm_acl_linux_test.go +121 -0
  649. package/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux.go +95 -0
  650. package/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux_test.go +56 -0
  651. package/templates/native-go/backend/internal/helper/dsm_bridge_linux.go +144 -0
  652. package/templates/native-go/backend/internal/helper/dsm_bridge_linux_test.go +89 -0
  653. package/templates/native-go/backend/internal/helper/dsm_home_linux.go +107 -0
  654. package/templates/native-go/backend/internal/helper/dsm_home_linux_test.go +82 -0
  655. package/templates/native-go/backend/internal/helper/dsm_probe_transport_linux.go +151 -0
  656. package/templates/native-go/backend/internal/helper/dsm_probe_transport_linux_test.go +66 -0
  657. package/templates/native-go/backend/internal/helper/grant_authority.go +519 -0
  658. package/templates/native-go/backend/internal/helper/grant_authority_contract.go +88 -0
  659. package/templates/native-go/backend/internal/helper/grant_authority_test.go +510 -0
  660. package/templates/native-go/backend/internal/helper/grant_cohort.go +389 -0
  661. package/templates/native-go/backend/internal/helper/grant_cohort_test.go +239 -0
  662. package/templates/native-go/backend/internal/helper/grant_delivery.go +49 -0
  663. package/templates/native-go/backend/internal/helper/grant_delivery_methods.go +273 -0
  664. package/templates/native-go/backend/internal/helper/grant_delivery_test.go +322 -0
  665. package/templates/native-go/backend/internal/helper/grant_operation_contract.go +47 -0
  666. package/templates/native-go/backend/internal/helper/grant_readonly_test.go +180 -0
  667. package/templates/native-go/backend/internal/helper/grant_repository_linux.go +416 -0
  668. package/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +469 -0
  669. package/templates/native-go/backend/internal/helper/grant_rpc.go +147 -0
  670. package/templates/native-go/backend/internal/helper/grant_rpc_test.go +51 -0
  671. package/templates/native-go/backend/internal/helper/grant_snapshot.go +78 -0
  672. package/templates/native-go/backend/internal/helper/grant_supervisor_linux.go +134 -0
  673. package/templates/native-go/backend/internal/helper/grant_supervisor_linux_test.go +254 -0
  674. package/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
  675. package/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
  676. package/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
  677. package/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
  678. package/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
  679. package/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
  680. package/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
  681. package/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
  682. package/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
  683. package/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
  684. package/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
  685. package/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
  686. package/templates/native-go/backend/internal/helper/lease.go +112 -0
  687. package/templates/native-go/backend/internal/helper/lease_linux.go +44 -0
  688. package/templates/native-go/backend/internal/helper/lease_other.go +8 -0
  689. package/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
  690. package/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
  691. package/templates/native-go/backend/internal/helper/lifecycle.go +234 -0
  692. package/templates/native-go/backend/internal/helper/lifecycle_test.go +473 -0
  693. package/templates/native-go/backend/internal/helper/managed_pilot.go +284 -0
  694. package/templates/native-go/backend/internal/helper/managed_pilot_repository_linux.go +74 -0
  695. package/templates/native-go/backend/internal/helper/managed_pilot_repository_linux_test.go +40 -0
  696. package/templates/native-go/backend/internal/helper/managed_pilot_test.go +210 -0
  697. package/templates/native-go/backend/internal/helper/management.go +79 -0
  698. package/templates/native-go/backend/internal/helper/nas_shipped_refusal_linux_test.go +97 -0
  699. package/templates/native-go/backend/internal/helper/native_discovery.go +79 -0
  700. package/templates/native-go/backend/internal/helper/native_identity.go +89 -0
  701. package/templates/native-go/backend/internal/helper/native_provider.go +159 -0
  702. package/templates/native-go/backend/internal/helper/native_provider_test.go +421 -0
  703. package/templates/native-go/backend/internal/helper/observation.go +244 -0
  704. package/templates/native-go/backend/internal/helper/observation_health_test.go +127 -0
  705. package/templates/native-go/backend/internal/helper/observation_reload_budget_test.go +117 -0
  706. package/templates/native-go/backend/internal/helper/observation_test.go +196 -0
  707. package/templates/native-go/backend/internal/helper/observer_diagnostic.go +155 -0
  708. package/templates/native-go/backend/internal/helper/observer_diagnostic_linux.go +76 -0
  709. package/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +130 -0
  710. package/templates/native-go/backend/internal/helper/observer_diagnostic_test.go +98 -0
  711. package/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
  712. package/templates/native-go/backend/internal/helper/operation_bootstrap_linux.go +193 -0
  713. package/templates/native-go/backend/internal/helper/operation_credentials_linux.go +56 -0
  714. package/templates/native-go/backend/internal/helper/operation_linux.go +480 -0
  715. package/templates/native-go/backend/internal/helper/operation_linux_test.go +528 -0
  716. package/templates/native-go/backend/internal/helper/process_linux.go +14 -1
  717. package/templates/native-go/backend/internal/helper/publication_test.go +178 -0
  718. package/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
  719. package/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
  720. package/templates/native-go/backend/internal/helper/read_stream_cohort_linux_test.go +156 -0
  721. package/templates/native-go/backend/internal/helper/read_transfer.go +40 -0
  722. package/templates/native-go/backend/internal/helper/read_transfer_linux.go +109 -0
  723. package/templates/native-go/backend/internal/helper/read_transfer_linux_test.go +118 -0
  724. package/templates/native-go/backend/internal/helper/read_transfer_test.go +177 -0
  725. package/templates/native-go/backend/internal/helper/readonly.go +105 -0
  726. package/templates/native-go/backend/internal/helper/readonly_admission.go +85 -0
  727. package/templates/native-go/backend/internal/helper/readonly_cohort_linux_test.go +253 -0
  728. package/templates/native-go/backend/internal/helper/readonly_linux_test.go +378 -0
  729. package/templates/native-go/backend/internal/helper/readonly_mount_linux.go +65 -0
  730. package/templates/native-go/backend/internal/helper/readonly_mount_proxy_linux.go +113 -0
  731. package/templates/native-go/backend/internal/helper/readonly_operations_linux.go +168 -0
  732. package/templates/native-go/backend/internal/helper/readonly_resolver_linux.go +241 -0
  733. package/templates/native-go/backend/internal/helper/readonly_test.go +40 -0
  734. package/templates/native-go/backend/internal/helper/relaxed_identity.go +252 -0
  735. package/templates/native-go/backend/internal/helper/relaxed_identity_contract.go +105 -0
  736. package/templates/native-go/backend/internal/helper/relaxed_identity_test.go +406 -0
  737. package/templates/native-go/backend/internal/helper/relaxed_invalidation.go +203 -0
  738. package/templates/native-go/backend/internal/helper/repair.go +132 -0
  739. package/templates/native-go/backend/internal/helper/repair_test.go +271 -0
  740. package/templates/native-go/backend/internal/helper/s1r_actor_acl_linux_test.go +303 -0
  741. package/templates/native-go/backend/internal/helper/s1r_actor_fixture_linux_test.go +184 -0
  742. package/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +250 -0
  743. package/templates/native-go/backend/internal/helper/s1r_fixture_contract_linux_test.go +18 -0
  744. package/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
  745. package/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
  746. package/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
  747. package/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
  748. package/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
  749. package/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
  750. package/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
  751. package/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
  752. package/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
  753. package/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
  754. package/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
  755. package/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
  756. package/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
  757. package/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
  758. package/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
  759. package/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
  760. package/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
  761. package/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
  762. package/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
  763. package/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
  764. package/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
  765. package/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
  766. package/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
  767. package/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
  768. package/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
  769. package/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
  770. package/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
  771. package/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
  772. package/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
  773. package/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
  774. package/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
  775. package/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
  776. package/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
  777. package/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
  778. package/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
  779. package/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
  780. package/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
  781. package/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
  782. package/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
  783. package/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
  784. package/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
  785. package/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
  786. package/templates/native-go/backend/internal/helper/sdk_server_linux.go +152 -0
  787. package/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
  788. package/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
  789. package/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
  790. package/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
  791. package/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
  792. package/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
  793. package/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
  794. package/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
  795. package/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
  796. package/templates/native-go/backend/internal/helper/server_linux.go +47 -3
  797. package/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
  798. package/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
  799. package/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
  800. package/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
  801. package/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
  802. package/templates/native-go/backend/internal/helper/status.go +83 -11
  803. package/templates/native-go/backend/internal/helper/status_test.go +128 -0
  804. package/templates/native-go/backend/internal/helper/supervision.go +28 -5
  805. package/templates/native-go/backend/internal/helper/supervisor_frame.go +79 -0
  806. package/templates/native-go/backend/internal/helper/supervisor_frame_linux_test.go +69 -0
  807. package/templates/native-go/backend/internal/helper/supervisor_frame_test.go +107 -0
  808. package/templates/native-go/backend/internal/helper/supervisor_linux.go +191 -16
  809. package/templates/native-go/backend/internal/helper/supervisor_linux_test.go +618 -7
  810. package/templates/native-go/backend/internal/helper/supervisor_socket_eof_test.go +74 -0
  811. package/templates/native-go/backend/internal/helper/supervisor_socket_test.go +45 -0
  812. package/templates/native-go/backend/internal/helper/testdata/protocol2/create.json +23 -0
  813. package/templates/native-go/backend/internal/helper/testdata/protocol2/frames.json +67 -0
  814. package/templates/native-go/backend/internal/helper/testdata/protocol2/grant-store.json +52 -0
  815. package/templates/native-go/backend/internal/helper/testdata/protocol2/intent.json +20 -0
  816. package/templates/native-go/backend/internal/helper/testdata/protocol2/list.json +20 -0
  817. package/templates/native-go/backend/internal/helper/testdata/protocol2/publish.json +20 -0
  818. package/templates/native-go/backend/internal/helper/testdata/protocol2/read.json +22 -0
  819. package/templates/native-go/backend/internal/helper/testdata/protocol2/stat.json +22 -0
  820. package/templates/native-go/backend/internal/helper/testdata/protocol2/write-stream.json +22 -0
  821. package/templates/native-go/backend/internal/helper/unit_connection.go +75 -0
  822. package/templates/native-go/backend/internal/helper/unit_connection_linux_test.go +135 -0
  823. package/templates/native-go/backend/internal/helper/unit_connection_test.go +151 -0
  824. package/templates/native-go/backend/internal/helper/unit_frame_test.go +32 -0
  825. package/templates/native-go/backend/internal/helper/unit_linux.go +368 -0
  826. package/templates/native-go/backend/internal/helper/unit_linux_test.go +46 -0
  827. package/templates/native-go/backend/internal/helper/unit_mechanisms_linux_test.go +217 -0
  828. package/templates/native-go/backend/internal/helper/unit_padding_linux_test.go +178 -0
  829. package/templates/native-go/backend/internal/helper/unit_query_linux.go +115 -0
  830. package/templates/native-go/backend/internal/helper/unit_reload_linux_test.go +372 -0
  831. package/templates/native-go/backend/internal/helper/unit_reload_sequence_linux_test.go +232 -0
  832. package/templates/native-go/backend/internal/helper/write.go +77 -0
  833. package/templates/native-go/backend/internal/helper/write_admission.go +260 -0
  834. package/templates/native-go/backend/internal/helper/write_admission_test.go +135 -0
  835. package/templates/native-go/backend/internal/helper/write_cohort_linux_test.go +218 -0
  836. package/templates/native-go/backend/internal/helper/write_files_linux.go +205 -0
  837. package/templates/native-go/backend/internal/helper/write_files_linux_test.go +225 -0
  838. package/templates/native-go/backend/internal/helper/write_intent_linux.go +116 -0
  839. package/templates/native-go/backend/internal/helper/write_intent_linux_test.go +74 -0
  840. package/templates/native-go/backend/internal/helper/write_operation_linux.go +245 -0
  841. package/templates/native-go/backend/internal/helper/write_test.go +53 -0
  842. package/templates/native-go/dsm-package.yaml +1 -1
  843. package/templates/native-go/ui/app.js +8 -1
  844. package/templates/native-go-background/BACKGROUND.md +111 -0
  845. package/templates/native-go-background/backend/internal/app/background_on.go +7 -0
  846. package/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
  847. package/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
  848. package/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
  849. package/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
  850. package/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
  851. package/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
  852. package/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
  853. package/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
  854. package/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
  855. package/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
  856. package/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
  857. package/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
  858. package/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
  859. package/templates/native-go-background/frontend/test/background.test.ts +179 -0
  860. package/templates/native-go-better-auth/node/build.mjs +2 -0
  861. package/templates/native-go-integration/backend/internal/app/personal.go +2 -2
  862. package/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
  863. package/templates/native-go-vue/README.md +151 -6
  864. package/templates/native-go-vue/frontend/DESIGN.md +16 -4
  865. package/templates/native-go-vue/frontend/README-JOBS.md +75 -0
  866. package/templates/native-go-vue/frontend/README-M2.md +64 -0
  867. package/templates/native-go-vue/frontend/package-lock.json +137 -233
  868. package/templates/native-go-vue/frontend/package.json +2 -2
  869. package/templates/native-go-vue/frontend/src/App.vue +71 -16
  870. package/templates/native-go-vue/frontend/src/M2App.vue +57 -0
  871. package/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
  872. package/templates/native-go-vue/frontend/src/context.ts +41 -2
  873. package/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
  874. package/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
  875. package/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
  876. package/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
  877. package/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
  878. package/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
  879. package/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
  880. package/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
  881. package/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
  882. package/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
  883. package/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
  884. package/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
  885. package/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
  886. package/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
  887. package/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
  888. package/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
  889. package/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
  890. package/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
  891. package/templates/native-go-vue/frontend/src/m2-style.css +7 -0
  892. package/templates/native-go-vue/frontend/src/main.ts +4 -1
  893. package/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
  894. package/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
  895. package/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
  896. package/templates/native-go-vue/frontend/src/nas/NasGrantSettings.vue +74 -0
  897. package/templates/native-go-vue/frontend/src/nas/NasPathPicker.vue +106 -0
  898. package/templates/native-go-vue/frontend/src/nas/NasUnavailable.vue +20 -0
  899. package/templates/native-go-vue/frontend/src/nas/i18n/de.json +74 -0
  900. package/templates/native-go-vue/frontend/src/nas/i18n/en.json +74 -0
  901. package/templates/native-go-vue/frontend/src/nas/i18n/es.json +74 -0
  902. package/templates/native-go-vue/frontend/src/nas/i18n/fr.json +74 -0
  903. package/templates/native-go-vue/frontend/src/nas/i18n/it.json +74 -0
  904. package/templates/native-go-vue/frontend/src/nas/i18n/ja.json +74 -0
  905. package/templates/native-go-vue/frontend/src/nas/i18n/ko.json +74 -0
  906. package/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
  907. package/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
  908. package/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
  909. package/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
  910. package/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
  911. package/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
  912. package/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
  913. package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
  914. package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
  915. package/templates/native-go-vue/frontend/src/nas/i18n/zh-CN.json +74 -0
  916. package/templates/native-go-vue/frontend/src/nas/i18n/zh-TW.json +74 -0
  917. package/templates/native-go-vue/frontend/src/nas/i18n.ts +38 -0
  918. package/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
  919. package/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
  920. package/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
  921. package/templates/native-go-vue/frontend/src/nas/mock-provider.ts +119 -0
  922. package/templates/native-go-vue/frontend/src/nas/provider.ts +59 -0
  923. package/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
  924. package/templates/native-go-vue/frontend/src/nas/use-request.ts +27 -0
  925. package/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
  926. package/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
  927. package/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
  928. package/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
  929. package/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
  930. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
  931. package/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
  932. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
  933. package/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
  934. package/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
  935. package/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
  936. package/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
  937. package/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
  938. package/templates/native-go-vue/frontend/src/style.css +19 -6
  939. package/templates/native-go-vue/frontend/test/apps.test.ts +65 -2
  940. package/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
  941. package/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
  942. package/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
  943. package/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
  944. package/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
  945. package/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
  946. package/templates/native-go-vue/frontend/test/nas-provider.test.ts +81 -0
  947. package/templates/native-go-vue/frontend/test/nas-request.test.ts +21 -0
  948. package/templates/native-go-vue/frontend/test/nas-ui.test.ts +261 -0
  949. package/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
  950. package/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
  951. package/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
  952. package/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
  953. package/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
  954. package/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
  955. package/templates/native-go-vue/frontend/tsconfig.json +1 -1
  956. package/templates/native-go-vue/frontend/vite.config.ts +8 -6
@@ -0,0 +1,209 @@
1
+ // @vitest-environment jsdom
2
+ import {expect,test,vi} from 'vitest'
3
+ import {createApp,h,nextTick} from 'vue'
4
+ import {AppRoot} from '@synopackageland/ui'
5
+ import {mount} from '../src/m2-main'
6
+ import M2PathPicker from '../src/nas/M2PathPicker.vue'
7
+ import {M2_MAX_BYTES,M2ProviderKey,type M2Provider} from '../src/nas/m2-contract'
8
+ import {m2Copy,m2Catalogs,m2ErrorCopy} from '../src/nas/m2-i18n'
9
+ import {format} from '../src/nas/i18n'
10
+ import {shellCopy} from '../src/shell/i18n'
11
+ import type {Context} from '../src/context'
12
+ vi.stubGlobal('URL',Object.assign(URL,{createObjectURL:vi.fn(()=> 'blob:local-test'),revokeObjectURL:vi.fn()}))
13
+ const id='a'.repeat(64)
14
+ async function settle(){for(let i=0;i<20;i++){await Promise.resolve();await nextTick()}await new Promise(r=>setTimeout(r,25))}
15
+ function click(root:HTMLElement,text:string){const b=[...root.querySelectorAll('button')].find(b=>b.textContent?.trim()===text||b.getAttribute('aria-label')===text);expect(b,text).toBeTruthy();b!.click()}
16
+ function fixture(locale='en'){
17
+ let user='normal1',selections:any[]=[],failure=''
18
+ const reopen:Array<()=>void>=[]
19
+ const call=vi.fn(async(method:string,args?:Record<string,unknown>)=>{
20
+ if(failure&&method.startsWith('nas.'))throw {code:failure,message:'Cookie=secret /private'}
21
+ if(method==='app.status')return {package:'SamePackage',version:'1',user,admin:false}
22
+ if(method==='nas.session.status')return {mode:'filestation-session',interactive:'session-required',background:'unavailable',validation:'local-only'}
23
+ if(method==='nas.discovery')return {files:args?.folder?[]:null,shares:args?.folder?undefined:[{name:'Home',path:'/home',isdir:true}],total:args?.folder?0:1,offset:0}
24
+ if(method==='nas.grants.list')return selections
25
+ if(method==='nas.grants.confirm'){const s={grantId:id,folder:args!.folder,writable:args!.writable};selections.push(s);return s}
26
+ if(method==='nas.grants.revoke'){selections=[];return {revoked:true}}
27
+ if(method==='nas.files.list')return {files:[{name:'notes.txt',path:'/home/notes.txt',isdir:false,additional:{size:3}}],total:1,offset:0}
28
+ if(method==='nas.files.stat')return {name:'notes.txt',path:'/home/notes.txt',isdir:false,additional:{size:3}}
29
+ if(method==='nas.files.read')return {data:'YWJj',bytes:3}
30
+ if(method==='nas.files.create')return {created:true}
31
+ if(method==='nas.files.write')return {written:true}
32
+ throw {code:'unknown_method'}
33
+ })
34
+ const ctx={locale,call,reopen(fn:()=>void){reopen.push(fn);return ()=>{}}} as Context
35
+ const root=document.createElement('div');document.body.append(root);const app=mount(root,ctx)
36
+ return {root,app,call,reopen,setUser(value:string){user=value},fail(code:string){failure=code},close(){app.unmount();root.remove()}}
37
+ }
38
+ test('the File Station build uses the same DSM sidebar with a status page',async()=>{
39
+ const f=fixture(),copy=shellCopy('en')
40
+ try{
41
+ await settle()
42
+ const labels=[...f.root.querySelectorAll<HTMLElement>('[data-nav-item]')].map(node=>node.textContent?.trim())
43
+ expect(labels).toEqual([copy.status,copy.folders])
44
+ expect(f.root.querySelector('h1')?.textContent?.trim()).toBe(copy.status)
45
+ const folders=[...f.root.querySelectorAll<HTMLElement>('[data-nav-item]')].find(node=>node.textContent?.trim()===copy.folders)!
46
+ folders.click();await settle()
47
+ expect(f.root.querySelector('h1')?.textContent?.trim()).toBe(copy.folders)
48
+ expect(f.root.textContent).toContain(m2Copy('en').ownPermissions)
49
+ }finally{f.close()}
50
+ })
51
+
52
+ test('real session routes drive browse, writable consent, file actions and revoke without helper approval',async()=>{
53
+ const f=fixture(),copy=m2Copy('en')
54
+ try{
55
+ await settle();expect(f.root.textContent).toContain(copy.ownPermissions);expect(f.root.textContent).toContain(copy.unsupported)
56
+ click(f.root,copy.choose);await settle();click(f.root,'Select Home');await settle()
57
+ const checkbox=f.root.querySelector<HTMLElement>('[role=checkbox]')!;checkbox.click()
58
+ click(f.root,copy.confirm);await settle()
59
+ expect(f.call).toHaveBeenCalledWith('nas.grants.confirm',{folder:'/home',writable:true})
60
+ click(f.root,copy.openFiles);await settle();click(f.root,copy.inspect);await settle()
61
+ expect(f.root.textContent).toContain('3');click(f.root,copy.read);await settle()
62
+ expect(f.root.textContent).toContain(copy.readComplete)
63
+ const labelled=(text:string)=>f.root.querySelector<HTMLElement>(`#${[...f.root.querySelectorAll('label')].find(l=>l.textContent?.startsWith(text))!.htmlFor}`)
64
+ expect(labelled(copy.folderName)).toBe(f.root.querySelector('input[data-folder-name]'));expect(labelled(copy.uploadFile)).toBe(f.root.querySelector('input[type=file]'))
65
+ const input=f.root.querySelector<HTMLInputElement>('input[data-folder-name]')!;input.value='new';input.dispatchEvent(new Event('input',{bubbles:true}));await settle()
66
+ click(f.root,copy.create);await settle();expect(f.call).toHaveBeenCalledWith('nas.files.create',{grantId:id,relative:'',name:'new'})
67
+ const upload=f.root.querySelector<HTMLInputElement>('input[type=file]')!
68
+ Object.defineProperty(upload,'files',{value:[{name:'note.bin',size:3,arrayBuffer:async()=>new Uint8Array([0,1,255]).buffer}]})
69
+ upload.dispatchEvent(new Event('change',{bubbles:true}));await settle();click(f.root,copy.upload);await settle()
70
+ expect(f.call).toHaveBeenCalledWith('nas.files.write',{grantId:id,relative:'',name:'note.bin',data:'AAH/'})
71
+ click(f.root,copy.revoke);await settle();click(f.root,copy.confirmRevoke);await settle()
72
+ expect(f.root.textContent).toContain(copy.emptySelections)
73
+ expect(f.call.mock.calls.some(([m])=>/prepare|stream|publish|integration|root/.test(m))).toBe(false)
74
+ }finally{f.close()}
75
+ })
76
+ test('nine catalogs contain matching placeholders and distinct recovery copy for each safe failure',async()=>{
77
+ expect(Object.keys(m2Catalogs)).toHaveLength(9)
78
+ for(const [locale,copy]of Object.entries(m2Catalogs)){
79
+ expect(Object.keys(copy).sort()).toEqual(Object.keys(m2Catalogs.en).sort())
80
+ for(const key of Object.keys(copy)as Array<keyof typeof copy>){expect(copy[key].trim()).not.toBe('');expect(copy[key].match(/\{\w+\}/g)??[]).toEqual(m2Catalogs.en[key].match(/\{\w+\}/g)??[])}
81
+ const messages=['session_required','denied','not_found','conflict','commit-uncertain'].map(code=>m2ErrorCopy({code,message:'secret'},copy))
82
+ expect(new Set(messages).size).toBe(5)
83
+ const f=fixture(locale)
84
+ try{await settle();expect(f.root.textContent).toContain(copy.ownPermissions);f.fail('session_required');click(f.root,copy.refresh);await settle();expect(f.root.textContent).toContain(copy.errorSession);expect(f.root.textContent).not.toContain('Cookie=secret')}
85
+ finally{f.close()}
86
+ }
87
+ })
88
+ test('account change discards selections and pending dialogs until remount; two mounts isolate dialogs',async()=>{
89
+ const a=fixture(),b=fixture(),copy=m2Copy('en')
90
+ try{
91
+ await settle();click(a.root,copy.choose);click(b.root,copy.choose);await settle()
92
+ const ids=[...document.querySelectorAll('[id]')].map(n=>n.id).filter(Boolean);expect(new Set(ids).size).toBe(ids.length)
93
+ expect(a.root.querySelector('[role=dialog]')?.hasAttribute('aria-modal')).toBe(false)
94
+ a.setUser('normal2');a.reopen.forEach(fn=>fn());await settle()
95
+ expect(a.root.textContent).toContain(copy.accountChanged);expect(a.root.querySelector('[role=dialog]')).toBeNull()
96
+ expect(b.root.querySelector('[role=dialog]')).toBeTruthy()
97
+ }finally{a.close();b.close()}
98
+ })
99
+
100
+ test('read-only selection hides mutations; cancellation never confirms and errors never auto-retry',async()=>{
101
+ const f=fixture(),copy=m2Copy('en')
102
+ try{
103
+ await settle();click(f.root,copy.choose);await settle();click(f.root,'Select Home');click(f.root,copy.cancel);await settle()
104
+ expect(f.call.mock.calls.some(([m])=>m==='nas.grants.confirm')).toBe(false)
105
+ click(f.root,copy.choose);await settle();click(f.root,'Select Home');await settle();click(f.root,copy.confirm);await settle()
106
+ expect(f.call).toHaveBeenCalledWith('nas.grants.confirm',{folder:'/home',writable:false})
107
+ click(f.root,copy.openFiles);await settle()
108
+ expect(f.root.querySelector('input[type=file]')).toBeNull();expect(f.root.querySelector('input[data-folder-name]')).toBeNull()
109
+ f.fail('not_found');click(f.root,copy.inspect);await settle();expect(f.root.textContent).toContain(copy.errorNotFound)
110
+ expect(f.call.mock.calls.filter(([m])=>m==='nas.files.stat')).toHaveLength(1)
111
+ }finally{f.close()}
112
+ })
113
+ test('late discovery is discarded on unmount; a failed refresh does not forget the original account binding',async()=>{
114
+ const f=fixture(),copy=m2Copy('en')
115
+ try{
116
+ await settle()
117
+ const original=f.call.getMockImplementation()!
118
+ f.call.mockImplementation(async(method,args)=>{if(method==='app.status')throw {code:'session_required'};return original(method,args)})
119
+ f.reopen.forEach(fn=>fn());await settle()
120
+ f.call.mockImplementation(original);f.setUser('normal2');f.reopen.forEach(fn=>fn());await settle()
121
+ expect(f.root.textContent).toContain(copy.accountChanged)
122
+ }finally{f.close()}
123
+ const g=fixture()
124
+ await settle()
125
+ let release!:(value:unknown)=>void
126
+ const original=g.call.getMockImplementation()!
127
+ g.call.mockImplementation(async(method,args)=>method==='nas.discovery'?new Promise(r=>release=r):original(method,args))
128
+ click(g.root,copy.choose);await settle();g.app.unmount()
129
+ release({files:null,shares:[{name:'private',path:'/private',isdir:true}],total:1,offset:0});await settle()
130
+ expect(g.root.childElementCount).toBe(0);g.root.remove()
131
+ })
132
+
133
+ test('pending upload blocks competing folder controls and duplicate submission; uncertain outcome is actionable',async()=>{
134
+ const f=fixture(),copy=m2Copy('en')
135
+ try{
136
+ await settle();click(f.root,copy.choose);await settle();click(f.root,'Select Home');await settle()
137
+ const checkbox=f.root.querySelector<HTMLElement>('[role=checkbox]')!;checkbox.click()
138
+ click(f.root,copy.confirm);await settle();click(f.root,copy.openFiles);await settle()
139
+ const upload=f.root.querySelector<HTMLInputElement>('input[type=file]')!
140
+ Object.defineProperty(upload,'files',{value:[{name:'note.bin',size:3,arrayBuffer:async()=>new Uint8Array([0,1,255]).buffer}]})
141
+ upload.dispatchEvent(new Event('change',{bubbles:true}));await settle()
142
+ let reject!:(error:unknown)=>void
143
+ const original=f.call.getMockImplementation()!
144
+ f.call.mockImplementation(async(method,args)=>method==='nas.files.write'?new Promise((_resolve,r)=>reject=r):original(method,args))
145
+ click(f.root,copy.upload);click(f.root,copy.upload);await settle()
146
+ for(const button of [...f.root.querySelectorAll('button')].filter(b=>[copy.choose,copy.revoke,copy.refresh,copy.openFiles].includes(b.textContent?.trim()??'')))expect(button.disabled).toBe(true)
147
+ reject({code:'commit-uncertain'});await settle()
148
+ expect(f.root.textContent).toContain(copy.errorUncertain)
149
+ expect(f.call.mock.calls.filter(([m])=>m==='nas.files.write')).toHaveLength(1)
150
+ expect([...f.root.querySelectorAll('button')].find(b=>b.textContent?.trim()===copy.upload)?.disabled).toBe(true)
151
+ }finally{f.close()}
152
+ })
153
+
154
+ function mountPicker(consent?:string){
155
+ const provider={discovery:async()=>({entries:[],nextOffset:undefined})} as unknown as M2Provider
156
+ const root=document.createElement('div');document.body.append(root)
157
+ const app=createApp({render:()=>h(AppRoot,{},()=>h(M2PathPicker,{open:true,locale:'en',consent}))})
158
+ app.provide(M2ProviderKey,provider);app.config.idPrefix=`picker-${Math.random()}`;app.mount(root)
159
+ return {root,close(){app.unmount();root.remove()}}
160
+ }
161
+ test('the picker shows the caller-provided consent copy and keeps the M2 copy by default',async()=>{
162
+ const custom=mountPicker('Read once with your DSM login.');await settle()
163
+ expect(custom.root.textContent).toContain('Read once with your DSM login.');expect(custom.root.textContent).not.toContain(m2Copy('en').consent);custom.close()
164
+ const plain=mountPicker();await settle()
165
+ expect(plain.root.textContent).toContain(m2Copy('en').consent);plain.close()
166
+ })
167
+
168
+ async function openFiles(f:ReturnType<typeof fixture>,locale='en'){
169
+ const copy=m2Copy(locale)
170
+ await settle()
171
+ // In ko the navigation item shares the Choose button's label; the page button is the last match.
172
+ ;[...f.root.querySelectorAll('button')].filter(b=>b.textContent?.trim()===copy.choose).at(-1)!.click();await settle();click(f.root,format(copy.select,'Home'));await settle()
173
+ f.root.querySelector<HTMLElement>('[role=checkbox]')!.click()
174
+ click(f.root,copy.confirm);await settle();click(f.root,copy.openFiles);await settle()
175
+ return copy
176
+ }
177
+ // UI FilePicker "Choose files" per locale, written as escapes: template sources keep non-English text in catalogs only.
178
+ const chooseFiles:Record<string,string>={en:'Choose files','zh-TW':'\u9078\u64c7\u6a94\u6848','zh-CN':'\u9009\u62e9\u6587\u4ef6',ja:'\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e',ko:'\ud30c\uc77c \uc120\ud0dd',de:'Dateien ausw\u00e4hlen',fr:'Choisir des fichiers',es:'Elegir archivos',it:'Scegli file'}
179
+ test.each(Object.keys(chooseFiles))('upload uses the compact UI FilePicker in %s',async locale=>{
180
+ const f=fixture(locale)
181
+ try{
182
+ const copy=await openFiles(f,locale)
183
+ expect(f.root.textContent).toContain(chooseFiles[locale])
184
+ expect(f.root.querySelectorAll('input[type=file]')).toHaveLength(1)
185
+ const upload=f.root.querySelector<HTMLInputElement>('input[type=file]')!
186
+ expect(upload.multiple).toBe(false)
187
+ expect(f.root.querySelector(`label[for="${upload.id}"]`)?.textContent).toContain(copy.uploadFile)
188
+ }finally{f.close()}
189
+ })
190
+ test('an oversize file is refused with the limit message and is never uploaded',async()=>{
191
+ const f=fixture(),copy=m2Copy('en')
192
+ try{
193
+ await openFiles(f)
194
+ const upload=f.root.querySelector<HTMLInputElement>('input[type=file]')!
195
+ Object.defineProperty(upload,'files',{value:[new File([new Uint8Array(M2_MAX_BYTES+1)],'big.bin')]})
196
+ upload.dispatchEvent(new Event('change',{bubbles:true}));await settle()
197
+ expect(f.root.textContent).toContain(m2ErrorCopy({code:'limit-exceeded'},copy))
198
+ expect([...f.root.querySelectorAll('button')].find(b=>b.textContent?.trim()===copy.upload)?.disabled).toBe(true)
199
+ expect(f.call.mock.calls.some(([m])=>m==='nas.files.write')).toBe(false)
200
+ }finally{f.close()}
201
+ })
202
+ test('a downloaded read result is a UI Link with the file name',async()=>{
203
+ const f=fixture(),copy=m2Copy('en')
204
+ try{
205
+ await openFiles(f);click(f.root,copy.read);await settle()
206
+ const link=f.root.querySelector<HTMLAnchorElement>('a[download]')!
207
+ expect(link.textContent).toContain(copy.download);expect(link.download).toBe('notes.txt');expect(link.getAttribute('href')).toMatch(/^blob:/)
208
+ }finally{f.close()}
209
+ })
@@ -0,0 +1,81 @@
1
+ import {expect, test} from 'vitest'
2
+ import {createMockNasService} from '../src/nas/mock-provider'
3
+
4
+ const signal = () => new AbortController().signal
5
+ async function selection(provider: ReturnType<ReturnType<typeof createMockNasService>['connect']>) {
6
+ const context = await provider.begin('user-personal', signal())
7
+ const page = await provider.list(context.contextId, undefined, undefined, signal())
8
+ return {context, candidate: page.entries[0]!}
9
+ }
10
+
11
+ test('two ordinary subjects cannot exchange contexts, candidates, intents or personal grants', async () => {
12
+ const service = createMockNasService(), a = service.connect('normal1'), b = service.connect('normal2')
13
+ const picked = await selection(a)
14
+ await expect(b.list(picked.context.contextId, undefined, undefined, signal())).rejects.toEqual({code:'denied'})
15
+ await expect(b.prepare(picked.candidate.nodeId, signal())).rejects.toEqual({code:'denied'})
16
+ const intent = await a.prepare(picked.candidate.nodeId, signal())
17
+ await expect(b.confirm(intent.intentId, intent.summaryDigest, signal())).rejects.toEqual({code:'denied'})
18
+ const grant = await a.confirm(intent.intentId, intent.summaryDigest, signal())
19
+ expect(await b.grants(signal())).toEqual([])
20
+ await expect(b.revoke(grant.grantId, grant.revision, signal())).rejects.toEqual({code:'denied'})
21
+ expect(grant.actions).toEqual(['nas.files.list','nas.files.stat','nas.files.read'])
22
+ expect(JSON.stringify(grant)).not.toMatch(/\/volume|uid|sessionRef/)
23
+ })
24
+
25
+ test('intent expires at 30 seconds; candidate expires at 60; cancel never creates a grant', async () => {
26
+ let now = 1000
27
+ const service = createMockNasService({now:() => now}), a = service.connect('normal1')
28
+ const picked = await selection(a), intent = await a.prepare(picked.candidate.nodeId, signal())
29
+ now += 30_000
30
+ await expect(a.confirm(intent.intentId, intent.summaryDigest, signal())).rejects.toEqual({code:'expired'})
31
+ now += 30_000
32
+ await expect(a.prepare(picked.candidate.nodeId, signal())).rejects.toEqual({code:'expired'})
33
+ const next = await selection(a), cancelIntent = await a.prepare(next.candidate.nodeId, signal())
34
+ await a.cancel(next.context.contextId)
35
+ await expect(a.confirm(cancelIntent.intentId, cancelIntent.summaryDigest, signal())).rejects.toEqual({code:'canceled'})
36
+ expect(await a.grants(signal())).toEqual([])
37
+ })
38
+
39
+ test('summary mismatch, replay, abort, role and session changes refuse; reconfirm gets a new ID', async () => {
40
+ const service = createMockNasService(), admin = service.connect('admin'), a = service.connect('normal1')
41
+ await expect(a.begin('app-shared', signal())).rejects.toEqual({code:'denied'})
42
+ const picked = await selection(a), intent = await a.prepare(picked.candidate.nodeId, signal())
43
+ await expect(a.confirm(intent.intentId, '0'.repeat(64), signal())).rejects.toEqual({code:'stale'})
44
+ const grant = await a.confirm(intent.intentId, intent.summaryDigest, signal())
45
+ await expect(a.confirm(intent.intentId, intent.summaryDigest, signal())).rejects.toEqual({code:'replay'})
46
+ await a.revoke(grant.grantId, grant.revision, signal())
47
+ const second = await a.prepare(picked.candidate.nodeId, signal())
48
+ expect((await a.confirm(second.intentId, second.summaryDigest, signal())).grantId).not.toBe(grant.grantId)
49
+ const aborted = new AbortController(); aborted.abort()
50
+ await expect(a.begin('user-personal', aborted.signal)).rejects.toEqual({code:'canceled'})
51
+ const context = await admin.begin('app-shared', signal()), page = await admin.list(context.contextId, undefined, undefined, signal())
52
+ const shared = await admin.prepare(page.entries[0]!.nodeId, signal())
53
+ service.setAdmin('admin', false)
54
+ await expect(admin.confirm(shared.intentId, shared.summaryDigest, signal())).rejects.toEqual({code:'denied'})
55
+ service.invalidate('normal1')
56
+ await expect(a.list(picked.context.contextId, undefined, undefined, signal())).rejects.toEqual({code:'stale'})
57
+ })
58
+
59
+ test('shared grant discovery is visible without becoming revoke authority; R and Q stay separate', async () => {
60
+ const service = createMockNasService({drained:false}), admin = service.connect('admin'), a = service.connect('normal1')
61
+ const ctx = await admin.begin('app-shared', signal()), page = await admin.list(ctx.contextId, undefined, undefined, signal())
62
+ const intent = await admin.prepare(page.entries[0]!.nodeId, signal()), grant = await admin.confirm(intent.intentId, intent.summaryDigest, signal())
63
+ expect((await a.grants(signal()))[0]?.grantId).toBe(grant.grantId)
64
+ await expect(a.revoke(grant.grantId, grant.revision, signal())).rejects.toEqual({code:'denied'})
65
+ expect(await admin.revoke(grant.grantId, grant.revision, signal())).toMatchObject({revoked:true,drained:false})
66
+ })
67
+
68
+ test('pagination binds cursor to actor/context/node and revision CAS rejects stale revoke',async()=> {
69
+ const service=createMockNasService({pageSize:1}), a=service.connect('normal1'), b=service.connect('normal2')
70
+ const {context,candidate}=await selection(a)
71
+ const page=await a.list(context.contextId,undefined,undefined,signal())
72
+ expect(page.entries).toHaveLength(1);expect(page.nextCursor).toBeTruthy()
73
+ expect((await a.list(context.contextId,undefined,page.nextCursor,signal())).entries[0]!.displayName).toBe('Empty folder')
74
+ await expect(a.list(context.contextId,candidate.nodeId,page.nextCursor,signal())).rejects.toEqual({code:'denied'})
75
+ await expect(b.list(context.contextId,undefined,page.nextCursor,signal())).rejects.toEqual({code:'denied'})
76
+ const intent=await a.prepare(candidate.nodeId,signal()), grant=await a.confirm(intent.intentId,intent.summaryDigest,signal())
77
+ await expect(a.revoke(grant.grantId,grant.revision+1,signal())).rejects.toEqual({code:'stale'})
78
+ service.newEpoch()
79
+ expect((await a.grants(signal()))[0]!.effectiveState).toBe('suspended')
80
+ await expect(a.prepare(candidate.nodeId,signal())).rejects.toEqual({code:'stale'})
81
+ })
@@ -0,0 +1,21 @@
1
+ // @vitest-environment jsdom
2
+ import {expect,test,vi} from 'vitest'
3
+ import {createApp,defineComponent} from 'vue'
4
+ import {useNasRequest} from '../src/nas/use-request'
5
+
6
+ test('unresponsive discovery times out in five seconds, aborts, and ignores late metadata',async()=> {
7
+ vi.useFakeTimers()
8
+ let request!:ReturnType<typeof useNasRequest>
9
+ const root=document.createElement('div')
10
+ const app=createApp(defineComponent({setup(){request=useNasRequest();return ()=>null}}));app.mount(root)
11
+ try {
12
+ let resolve!:(s:string)=>void, signal!:AbortSignal
13
+ const pending=request.run(s=>{signal=s;return new Promise<string>(r=>resolve=r)})
14
+ await vi.advanceTimersByTimeAsync(5000)
15
+ expect(await pending).toBeUndefined()
16
+ expect(request.busy.value).toBe(false);expect(signal.aborted).toBe(true)
17
+ expect(request.error.value).toEqual({code:'timeout'})
18
+ resolve('late private metadata');await Promise.resolve()
19
+ expect(request.error.value).toEqual({code:'timeout'})
20
+ } finally {app.unmount();vi.useRealTimers()}
21
+ })
@@ -0,0 +1,261 @@
1
+ // @vitest-environment jsdom
2
+ import {expect, test, vi} from 'vitest'
3
+ import {nextTick} from 'vue'
4
+ import {mount} from '../src/main'
5
+ import {createMockNasService} from '../src/nas/mock-provider'
6
+ import {catalogs, nasCopy, format, errorCopy} from '../src/nas/i18n'
7
+ import type {NasProvider} from '../src/nas/provider'
8
+ import type {Context} from '../src/context'
9
+
10
+ async function settle() {for(let i=0;i<20;i++){await Promise.resolve();await nextTick()}await new Promise(r=>setTimeout(r,25))}
11
+ function click(root:HTMLElement, text:string) {const b=[...root.querySelectorAll('button')].find(b=>b.textContent?.trim()===text || b.getAttribute('aria-label')===text);expect(b,text).toBeTruthy();b!.click()}
12
+ function fixture(nas:NasProvider | undefined, user='normal1', locale='en') {
13
+ const root=document.createElement('div');document.body.append(root)
14
+ const reopen:Array<()=>void>=[]
15
+ const ctx={locale,reopen(fn:()=>void){reopen.push(fn)},call:vi.fn(async(method:string)=> {
16
+ if(method==='app.status') return {package:'SamePackage',version:'1',user,admin:user==='admin'}
17
+ if(method==='integration.status') return {state:'not-enabled',reason:'not-requested',packageRunning:'unknown',scheduler:'not-probed'}
18
+ throw {code:'unknown_method'}
19
+ })} as Context
20
+ const app=mount(root,ctx,{nasProvider:nas})
21
+ return {root,app,ctx,reopen}
22
+ }
23
+ function cleanup(...fixtures:ReturnType<typeof fixture>[]) {for(const f of fixtures){f.app.unmount();f.root.remove()}}
24
+
25
+ test('managed account pilot stays visibly off with maintenance and approval restrictions',async()=> {
26
+ const f=fixture(createMockNasService().connect('admin'),'admin')
27
+ try {
28
+ await settle()
29
+ expect(f.root.textContent).toContain('Managed account pilot: off')
30
+ expect(f.root.textContent).toContain('Account changes or unverified identity revoke access')
31
+ expect(f.root.textContent).toContain('Enabling this pilot is unavailable in this build')
32
+ expect([...f.root.querySelectorAll('button')].some(b=>b.textContent?.includes('Enable managed'))).toBe(false)
33
+ } finally {cleanup(f)}
34
+ })
35
+
36
+ test('nine complete catalogs resolve DSM locale aliases with English fallback',()=> {
37
+ expect(Object.keys(catalogs)).toEqual(['en','zh-TW','zh-CN','ja','ko','de','fr','es','it'])
38
+ for(const catalog of Object.values(catalogs)) {
39
+ expect(Object.keys(catalog).sort()).toEqual(Object.keys(catalogs.en).sort())
40
+ expect(Object.values(catalog).every(s=>typeof s==='string' && s.trim().length>0)).toBe(true)
41
+ for(const key of Object.keys(catalogs.en) as Array<keyof typeof catalogs.en>) {
42
+ expect(catalog[key].match(/\{\w+\}/g) ?? []).toEqual(catalogs.en[key].match(/\{\w+\}/g) ?? [])
43
+ }
44
+ }
45
+ expect(nasCopy('cht')).toEqual(catalogs['zh-TW'])
46
+ expect(nasCopy('zh_CN')).toEqual(catalogs['zh-CN'])
47
+ expect(nasCopy('unknown')).toEqual(catalogs.en)
48
+ })
49
+
50
+ test('account changes discard the bound provider UI and its pending candidate context',async()=> {
51
+ const provider=createMockNasService().connect('normal1'), cancel=vi.spyOn(provider,'cancel'), f=fixture(provider)
52
+ try {
53
+ await settle();click(f.root,'Choose my folder');await settle()
54
+ f.ctx.call=vi.fn(async(method:string)=>method==='app.status'?{package:'SamePackage',version:'1',user:'normal2',admin:false}:{state:'not-enabled',reason:'not-requested',packageRunning:'unknown',scheduler:'not-probed'})
55
+ f.reopen.forEach(fn=>fn());await settle()
56
+ expect(f.root.textContent).toContain('normal2')
57
+ expect(f.root.querySelector('[role="dialog"]')).toBeNull()
58
+ expect(f.root.textContent).not.toContain('Choose my folder')
59
+ expect(cancel).toHaveBeenCalled()
60
+ } finally {cleanup(f)}
61
+ })
62
+
63
+ test('all nine locale UIs localize dialog controls and allow keyboard review without mouse-only actions',async()=> {
64
+ for(const locale of Object.keys(catalogs)) {
65
+ const copy=nasCopy(locale), f=fixture(createMockNasService().connect('normal1'),'normal1',locale)
66
+ try {
67
+ await settle();click(f.root,copy.choosePersonal);await settle()
68
+ const selected=[...f.root.querySelectorAll('button')].find(b=>b.getAttribute('aria-label')===format(copy.select,'Projects'))!
69
+ selected.focus();expect(document.activeElement).toBe(selected)
70
+ // Native Button remains a keyboard-activatable button (browser verifies Enter).
71
+ expect(selected.tagName).toBe('BUTTON');selected.click();await settle()
72
+ click(f.root,copy.review);await settle();expect(f.root.textContent).toContain(copy.persistent)
73
+ expect(f.root.querySelector(`button[aria-label="${copy.close}"]`)).toBeTruthy()
74
+ click(f.root,copy.cancel);await settle()
75
+ } finally {cleanup(f)}
76
+ }
77
+ })
78
+
79
+ test('home unavailable is recoverable and native diagnostics are never rendered',async()=> {
80
+ const provider=createMockNasService({homeAvailable:false}).connect('normal1'), f=fixture(provider)
81
+ try {
82
+ await settle();click(f.root,'Choose my folder');await settle()
83
+ expect(f.root.textContent).toContain('Required native identity or permission proof is unavailable')
84
+ provider.begin=async()=>{throw {code:'unknown',message:'/volume1/private-secret stderr'}}
85
+ click(f.root,'Retry');await settle()
86
+ expect(f.root.textContent).toContain('The request failed')
87
+ expect(f.root.textContent).not.toMatch(/private-secret|stderr/)
88
+ } finally {cleanup(f)}
89
+ })
90
+
91
+ test('picker browse, separate selection/summary, cancel, empty and confirm use injected provider only',async()=> {
92
+ const service=createMockNasService(), provider=service.connect('normal1'), cancel=vi.spyOn(provider,'cancel'), f=fixture(provider)
93
+ try {
94
+ await settle();click(f.root,'Choose my folder');await settle()
95
+ expect(f.root.textContent).toContain('Mock preview')
96
+ expect(f.root.querySelector('[role="dialog"]')).toBeTruthy()
97
+ click(f.root,'Select Projects');await settle()
98
+ expect(f.root.textContent).not.toContain('Persistent access')
99
+ click(f.root,'Review access');await settle()
100
+ expect(f.root.textContent).toContain('Persistent access')
101
+ click(f.root,'Cancel');await settle()
102
+ expect(cancel).toHaveBeenCalled()
103
+ expect(await provider.grants(new AbortController().signal)).toEqual([])
104
+ click(f.root,'Choose my folder');await settle();click(f.root,'Open Empty folder');await settle()
105
+ expect(f.root.textContent).toContain('This folder is empty')
106
+ click(f.root,'Back');await settle();click(f.root,'Select Projects');await settle();click(f.root,'Review access');await settle();click(f.root,'Confirm access');await settle()
107
+ expect(f.root.querySelector('[role="dialog"]')).toBeNull()
108
+ expect(f.root.textContent).toContain('Active')
109
+ } finally {cleanup(f)}
110
+ })
111
+
112
+ test('two same-package apps retain local modality, unique ARIA IDs and cancellation isolation',async()=> {
113
+ const service=createMockNasService(), a=fixture(service.connect('normal1')), b=fixture(service.connect('normal2'))
114
+ const body=document.body.getAttribute('style')
115
+ try {
116
+ await settle();click(a.root,'Choose my folder');click(b.root,'Choose my folder');await settle()
117
+ const ids=[...document.querySelectorAll('[id]')].map(n=>n.id).filter(Boolean)
118
+ expect(new Set(ids).size).toBe(ids.length)
119
+ for(const f of [a,b]) {
120
+ const dialog=f.root.querySelector('[role="dialog"]')!
121
+ expect(dialog.hasAttribute('aria-modal')).toBe(false)
122
+ for(const name of ['aria-labelledby','aria-describedby']) expect(f.root.querySelector(`[id="${dialog.getAttribute(name)}"]`)).toBeTruthy()
123
+ }
124
+ expect(getComputedStyle(b.root).pointerEvents).not.toBe('none')
125
+ click(a.root,'Cancel');await settle()
126
+ expect(a.root.querySelector('[role="dialog"]')).toBeNull()
127
+ expect(b.root.querySelector('[role="dialog"]')).toBeTruthy()
128
+ expect(document.body.getAttribute('style')).toBe(body)
129
+ } finally {cleanup(a,b)}
130
+ })
131
+
132
+ test('intent expiry is actionable; revoked but not drained never claims transfers stopped',async()=> {
133
+ let now=1000
134
+ const service=createMockNasService({now:()=>now,drained:false}), provider=service.connect('normal1'), f=fixture(provider)
135
+ try {
136
+ await settle();click(f.root,'Choose my folder');await settle();click(f.root,'Select Projects');await settle();click(f.root,'Review access');await settle()
137
+ now+=30_000;click(f.root,'Confirm access');await settle()
138
+ expect(f.root.textContent).toContain('expired')
139
+ expect(await provider.grants(new AbortController().signal)).toEqual([])
140
+ click(f.root,'Cancel');await settle();click(f.root,'Choose my folder');await settle();click(f.root,'Select Projects');await settle();click(f.root,'Review access');await settle();click(f.root,'Confirm access');await settle()
141
+ click(f.root,'Revoke');await settle()
142
+ expect(f.root.textContent).toContain('already sent or written')
143
+ click(f.root,'Confirm revoke');await settle()
144
+ expect(f.root.textContent).toContain('Revoked; stopping transfers')
145
+ } finally {cleanup(f)}
146
+ })
147
+
148
+ test('unmount aborts late browse and cancels its context without creating a grant',async()=> {
149
+ const provider=createMockNasService().connect('normal1'), base=provider.list.bind(provider)
150
+ let resolve!:()=>void, requestSignal!:AbortSignal
151
+ provider.list=async(...args)=>{requestSignal=args[3];await new Promise<void>(r=>resolve=r);return base(...args)}
152
+ const cancel=vi.spyOn(provider,'cancel'), f=fixture(provider)
153
+ await settle();click(f.root,'Choose my folder');await settle();f.app.unmount()
154
+ expect(requestSignal.aborted).toBe(true);expect(cancel).toHaveBeenCalled()
155
+ resolve();await settle();expect(f.root.childElementCount).toBe(0);f.root.remove()
156
+ })
157
+
158
+ test('late begin after close is canceled and rapid double review consumes one intent',async()=> {
159
+ const provider=createMockNasService().connect('normal1'), begin=provider.begin.bind(provider)
160
+ let release!:()=>void
161
+ provider.begin=async(kind,signal)=>{await new Promise<void>(r=>release=r);return begin(kind,new AbortController().signal)}
162
+ const cancel=vi.spyOn(provider,'cancel'), prepare=vi.spyOn(provider,'prepare'), f=fixture(provider)
163
+ try {
164
+ await settle();click(f.root,'Choose my folder');await settle();click(f.root,'Cancel');await settle()
165
+ release();await settle();expect(cancel).toHaveBeenCalled();expect(f.root.querySelector('[role="dialog"]')).toBeNull()
166
+ provider.begin=begin
167
+ click(f.root,'Choose my folder');await settle();click(f.root,'Select Projects');await settle()
168
+ click(f.root,'Review access');click(f.root,'Review access');await settle()
169
+ expect(prepare).toHaveBeenCalledTimes(1)
170
+ } finally {cleanup(f)}
171
+ })
172
+
173
+ test('long folder names stay text, and revoked without Q uses pending cleanup copy',async()=> {
174
+ const name='<img src=x onerror=alert(1)> '+ '\u5e74\u5ea6\u5831\u544a'.repeat(20)
175
+ const provider=createMockNasService({personalFolders:[name]}).connect('normal1'), f=fixture(provider)
176
+ try {
177
+ await settle();click(f.root,'Choose my folder');await settle()
178
+ expect(f.root.textContent).toContain(name);expect(f.root.querySelector('img')).toBeNull()
179
+ click(f.root,'Cancel');await settle()
180
+ provider.settings=async()=>({canManageShared:false,items:[{grantId:'fixture',revision:2,scopeKind:'user-personal',displayName:name,targetKind:'directory',actions:['nas.files.read'],effectiveState:'revoked',createdAt:1000,canRevoke:true,cleanupRequired:true}]})
181
+ click(f.root,'Refresh access');await settle()
182
+ expect(f.root.textContent).toContain('Revoked; cleanup needs verification')
183
+ expect(f.root.textContent).toContain('Read files')
184
+ expect(f.root.textContent).not.toContain('List folders')
185
+ } finally {cleanup(f)}
186
+ })
187
+
188
+
189
+ test('S8 production defaults display unavailable for normal/admin even when lifecycle is ready',async()=> {
190
+ for(const user of ['normal1','admin']) for(const locale of Object.keys(catalogs)) {
191
+ const f=fixture(undefined,user,locale),copy=nasCopy(locale)
192
+ try {
193
+ f.ctx.call=vi.fn(async(method:string)=> {
194
+ if(method==='app.status') return {package:'SamePackage',version:'1',user,admin:user==='admin'}
195
+ if(method==='integration.status') return {state:'ready',packageRunning:'running',scheduler:'ready'}
196
+ if(method==='personal.list') return {items:[]}
197
+ throw {code:'unknown_method'}
198
+ })
199
+ f.reopen.forEach(fn=>fn());await settle()
200
+ expect(f.root.textContent).toContain(copy.unavailableMessage)
201
+ expect(f.root.textContent).toContain(copy.pilotUnavailable)
202
+ expect(f.root.textContent).toContain(copy.noUnlock)
203
+ expect(f.root.textContent).not.toContain(copy.choosePersonal)
204
+ expect(f.root.textContent).not.toContain(copy.chooseShared)
205
+ expect(f.root.textContent).not.toContain(copy.emptyGrant)
206
+ expect(f.ctx.call.mock.calls.some(([method])=>method.startsWith('nas.'))).toBe(false)
207
+ } finally {cleanup(f)}
208
+ }
209
+ })
210
+
211
+ test('S8 unavailable connected providers are ignored; only development mocks have a picker',async()=> {
212
+ const connected=createMockNasService().connect('normal1')
213
+ Object.defineProperty(connected,'mode',{value:'connected'})
214
+ const settings=vi.spyOn(connected,'settings'),f=fixture(connected)
215
+ try {
216
+ await settle()
217
+ expect(f.root.textContent).toContain(nasCopy('en').unavailableMessage)
218
+ expect(f.root.textContent).not.toContain('Choose my folder')
219
+ expect(settings).not.toHaveBeenCalled()
220
+ } finally {cleanup(f)}
221
+ })
222
+
223
+
224
+ test('S8 safe error codes distinguish missing proof, denial, missing method and app authentication',()=> {
225
+ for(const copy of Object.values(catalogs)) {
226
+ for(const [code,key] of [['unavailable','errorNativeProof'],['denied','errorDenied'],['unknown_method','errorUnknownMethod'],['unsupported','errorUnsupported'],['session_required','errorSession'],['auth_unavailable','errorAuthentication']] as const) {
227
+ expect(errorCopy({code,message:'/volume1/private cookie=sid'},copy)).toBe(copy[key])
228
+ expect(errorCopy({code,message:'/volume1/private cookie=sid'},copy)).not.toMatch(/volume1|cookie=sid/)
229
+ }
230
+ expect(new Set(['unavailable','denied','unknown_method','unsupported'].map(code=>errorCopy({code},copy))).size).toBe(4)
231
+ }
232
+ })
233
+
234
+
235
+ test('S8 app request failures use localized safe-code copy without native diagnostics',async()=> {
236
+ for(const code of ['denied','unknown_method','unavailable','unsupported','session_required','auth_unavailable']) {
237
+ const f=fixture(undefined,'normal1','cht')
238
+ try {
239
+ await settle()
240
+ f.ctx.call=vi.fn(async()=>{throw {code,message:'/volume1/private cookie=sid'}})
241
+ f.reopen.forEach(fn=>fn());await settle()
242
+ expect(f.root.querySelector('[role="alert"]')?.textContent).toBe(errorCopy({code},nasCopy('cht')))
243
+ expect(f.root.textContent).not.toMatch(/volume1|cookie=sid/)
244
+ } finally {cleanup(f)}
245
+ }
246
+ })
247
+
248
+ test('S1R risk and reauthorization are disclosed in nine unavailable UIs without data actions',async()=> {
249
+ for(const locale of Object.keys(catalogs)) {
250
+ const copy=nasCopy(locale) as any, f=fixture(undefined,'normal1',locale)
251
+ try {
252
+ await settle()
253
+ for(const key of ['relaxedRisk','relaxedReauthorize','relaxedPermissions']) {
254
+ expect(copy[key],`${locale}:${key}`).toBeTypeOf('string')
255
+ expect(f.root.textContent).toContain(copy[key])
256
+ }
257
+ expect(f.root.textContent).not.toContain(copy.choosePersonal)
258
+ expect(f.ctx.call.mock.calls.some(([method])=>method.startsWith('nas.'))).toBe(false)
259
+ } finally {cleanup(f)}
260
+ }
261
+ })
@@ -0,0 +1,27 @@
1
+ import {readdirSync,readFileSync} from 'node:fs'
2
+ import {join} from 'node:path'
3
+ import {expect,test} from 'vitest'
4
+ const root=join(__dirname,'../src')
5
+ const sources=(dir:string):string[]=>readdirSync(dir,{withFileTypes:true}).flatMap(e=>e.isDirectory()?sources(join(dir,e.name)):e.name.endsWith('.vue')?[join(dir,e.name)]:[])
6
+ const template=(file:string)=>readFileSync(file,'utf8').replace(/<script[\s\S]*?<\/script>/g,'').replace(/<style[\s\S]*?<\/style>/g,'')
7
+ const uses=(file:string,tag:string)=>new RegExp(`<${tag}[\\s>/]`).test(template(file))
8
+ // The template ships @synopackageland/ui controls only; a native form control
9
+ // means a missing UI component, which is a UI gap to report, not to paper over.
10
+ test.each(['select','option','textarea','label','input','a'])('no vue template renders a native <%s>',tag=>{
11
+ expect(sources(root).filter(file=>uses(file,tag))).toEqual([])
12
+ })
13
+ // Form direction and the control id come from the UI: `direction="auto"` stacks labels in a
14
+ // narrow package window, and a control inside a FormItem binds its id/ARIA by itself.
15
+ test('FormItem controls rely on the UI auto layout and id binding',()=>{
16
+ const items=sources(root).filter(file=>uses(file,'FormItem'))
17
+ expect(items.length).toBeGreaterThan(0)
18
+ expect(items.filter(file=>/direction="vertical"|field\.controlId|#default="\{field\}"/.test(template(file)))).toEqual([])
19
+ })
20
+ // UI built-in text follows the Provider locale (nine locales), so every app root sets it once and no
21
+ // component repeats a per-control locale or download label.
22
+ test('app roots set the UI locale once and components do not translate UI text themselves',()=>{
23
+ const roots=sources(root).filter(file=>uses(file,'AppRoot'))
24
+ expect(roots.length).toBeGreaterThan(0)
25
+ expect(roots.filter(file=>!uses(file,'ConfigProvider'))).toEqual([])
26
+ expect(sources(root).filter(file=>/download-label|external-label|<FilePicker[^>]*:locale=/.test(template(file)))).toEqual([])
27
+ })