@synopackageland/cli 0.4.1 → 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 (631) hide show
  1. package/README.md +7 -3
  2. package/dist/build-spk/delete-app-data.d.ts +27 -7
  3. package/dist/build-spk/delete-app-data.js +35 -34
  4. package/dist/build-spk/dsm-arch.d.ts +6 -1
  5. package/dist/build-spk/dsm-arch.js +25 -1
  6. package/dist/build-spk/dsm-version.d.ts +14 -0
  7. package/dist/build-spk/dsm-version.js +47 -0
  8. package/dist/build-spk/gateway.d.ts +31 -0
  9. package/dist/build-spk/gateway.js +55 -0
  10. package/dist/build-spk/generator.d.ts +5 -0
  11. package/dist/build-spk/generator.js +103 -107
  12. package/dist/build-spk/install-wizard.d.ts +20 -0
  13. package/dist/build-spk/install-wizard.js +76 -0
  14. package/dist/build-spk/native-lifecycle.d.ts +5 -0
  15. package/dist/build-spk/native-lifecycle.js +12 -2
  16. package/dist/build-spk/resource-worker.d.ts +9 -4
  17. package/dist/build-spk/resource-worker.js +15 -6
  18. package/dist/build-spk/share-combobox.d.ts +3 -0
  19. package/dist/build-spk/share-combobox.js +27 -0
  20. package/dist/build-spk/uninstall-wizard.d.ts +14 -0
  21. package/dist/build-spk/uninstall-wizard.js +33 -0
  22. package/dist/build-spk/wizard-i18n.d.ts +18 -0
  23. package/dist/build-spk/wizard-i18n.js +38 -0
  24. package/dist/build-spk/wizard-messages.d.ts +388 -0
  25. package/dist/build-spk/wizard-messages.js +387 -0
  26. package/dist/cli.js +130 -30
  27. package/dist/compose/analyze.d.ts +20 -0
  28. package/dist/compose/analyze.js +75 -11
  29. package/dist/contract/validate.js +33 -1
  30. package/dist/contract/web-launch.d.ts +22 -0
  31. package/dist/contract/web-launch.js +37 -0
  32. package/dist/deploy/deploy.d.ts +3 -0
  33. package/dist/deploy/deploy.js +11 -2
  34. package/dist/error-registry.js +60 -1
  35. package/dist/host/open-url.d.ts +2 -0
  36. package/dist/host/open-url.js +4 -1
  37. package/dist/images/pin.d.ts +52 -0
  38. package/dist/images/pin.js +249 -0
  39. package/dist/init.d.ts +27 -3
  40. package/dist/init.js +104 -15
  41. package/dist/inspect.d.ts +3 -0
  42. package/dist/inspect.js +15 -3
  43. package/dist/standalone/background.d.ts +21 -0
  44. package/dist/standalone/background.js +52 -0
  45. package/dist/standalone/binary.d.ts +1 -0
  46. package/dist/standalone/binary.js +1 -1
  47. package/dist/standalone/build.d.ts +2 -0
  48. package/dist/standalone/build.js +38 -6
  49. package/dist/standalone/dsm-window.js +2 -2
  50. package/dist/standalone/helper-inventory.d.ts +15 -0
  51. package/dist/standalone/helper-inventory.js +9 -0
  52. package/dist/standalone/helper.d.ts +1 -0
  53. package/dist/standalone/helper.js +28 -10
  54. package/dist/standalone/host-adapter.d.ts +1 -1
  55. package/dist/standalone/host-adapter.js +33 -15
  56. package/dist/standalone/host-file-navigation.d.ts +7 -0
  57. package/dist/standalone/host-file-navigation.js +172 -0
  58. package/dist/standalone/inspect-helper.js +9 -4
  59. package/dist/standalone/inspect-spk.d.ts +1 -1
  60. package/dist/standalone/inspect-spk.js +200 -7
  61. package/dist/standalone/job-diagnostics.d.ts +1 -0
  62. package/dist/standalone/job-diagnostics.js +49 -0
  63. package/dist/standalone/lifecycle.js +12 -2
  64. package/dist/standalone/manifest.d.ts +15 -2
  65. package/dist/standalone/manifest.js +37 -6
  66. package/dist/standalone/native-layout.d.ts +74 -0
  67. package/dist/standalone/native-layout.js +318 -0
  68. package/dist/standalone/resource.d.ts +11 -0
  69. package/dist/standalone/resource.js +13 -0
  70. package/dist/standalone/root-window.d.ts +3 -1
  71. package/dist/standalone/root-window.js +156 -38
  72. package/dist/standalone/shared-folder.d.ts +39 -0
  73. package/dist/standalone/shared-folder.js +141 -0
  74. package/dist/standalone/spk.d.ts +2 -0
  75. package/dist/standalone/spk.js +33 -3
  76. package/dist/standalone/worker-contract-json.d.ts +8 -0
  77. package/dist/standalone/worker-contract-json.js +141 -0
  78. package/dist/standalone/worker-contract.d.ts +189 -0
  79. package/dist/standalone/worker-contract.js +175 -0
  80. package/dist/standalone/worker-registry.d.ts +40 -0
  81. package/dist/standalone/worker-registry.js +167 -0
  82. package/dist/templates/_daemon/go.mod +2 -0
  83. package/dist/templates/_gateway/auth.go +101 -0
  84. package/dist/templates/_gateway/auth_test.go +216 -0
  85. package/dist/templates/_gateway/cgi.go +133 -0
  86. package/dist/templates/_gateway/cgi_test.go +156 -0
  87. package/dist/templates/_gateway/csrf.go +73 -0
  88. package/dist/templates/_gateway/csrf_test.go +155 -0
  89. package/dist/templates/_gateway/directory.go +108 -0
  90. package/dist/templates/_gateway/directory_test.go +202 -0
  91. package/dist/templates/_gateway/gateway.go +412 -0
  92. package/dist/templates/_gateway/gateway_test.go +676 -0
  93. package/dist/templates/_gateway/go.mod +3 -0
  94. package/dist/templates/_gateway/groups.go +66 -0
  95. package/dist/templates/_gateway/main.go +45 -0
  96. package/dist/templates/binary/synology-app.yaml +1 -1
  97. package/dist/templates/compose-import/compose.yaml +1 -1
  98. package/dist/templates/compose-import/synology-app.yaml +1 -1
  99. package/dist/templates/hello-files/compose.yaml +1 -1
  100. package/dist/templates/hello-files/synology-app.yaml +1 -1
  101. package/dist/templates/hello-web/compose.yaml +5 -2
  102. package/dist/templates/hello-web/synology-app.yaml +4 -1
  103. package/dist/templates/hello-web-page/compose.yaml +5 -2
  104. package/dist/templates/hello-web-page/synology-app.yaml +4 -1
  105. package/dist/templates/native-go/README.md +93 -4
  106. package/dist/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +3 -1
  107. package/dist/templates/native-go/backend/cmd/app/main.go +17 -0
  108. package/dist/templates/native-go/backend/cmd/app/sdk_main.go +60 -0
  109. package/dist/templates/native-go/backend/cmd/background-worker/main.go +38 -0
  110. package/dist/templates/native-go/backend/cmd/helper/main.go +10 -1
  111. package/dist/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
  112. package/dist/templates/native-go/backend/go.mod +5 -3
  113. package/dist/templates/native-go/backend/go.sum +4 -4
  114. package/dist/templates/native-go/backend/internal/api/registry.go +17 -6
  115. package/dist/templates/native-go/backend/internal/api/server.go +7 -1
  116. package/dist/templates/native-go/backend/internal/app/background.go +270 -0
  117. package/dist/templates/native-go/backend/internal/app/background_none.go +8 -0
  118. package/dist/templates/native-go/backend/internal/app/background_owner.go +59 -0
  119. package/dist/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
  120. package/dist/templates/native-go/backend/internal/app/background_schedule.go +74 -0
  121. package/dist/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
  122. package/dist/templates/native-go/backend/internal/app/background_test.go +346 -0
  123. package/dist/templates/native-go/backend/internal/app/integration_state.go +16 -0
  124. package/dist/templates/native-go/backend/internal/app/migrations.go +41 -0
  125. package/dist/templates/native-go/backend/internal/app/migrations_test.go +41 -0
  126. package/dist/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +8 -0
  127. package/dist/templates/native-go/backend/internal/app/routes.go +17 -3
  128. package/dist/templates/native-go/backend/internal/app/routes_test.go +20 -3
  129. package/dist/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
  130. package/dist/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
  131. package/dist/templates/native-go/backend/internal/app/sdk_routes.go +174 -0
  132. package/dist/templates/native-go/backend/internal/app/session_files.go +15 -0
  133. package/dist/templates/native-go/backend/internal/app/session_files_test.go +26 -0
  134. package/dist/templates/native-go/backend/internal/app/shared_folder.go +144 -0
  135. package/dist/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
  136. package/dist/templates/native-go/backend/internal/background/access.go +57 -0
  137. package/dist/templates/native-go/backend/internal/background/owner_test.go +126 -0
  138. package/dist/templates/native-go/backend/internal/background/runner.go +185 -0
  139. package/dist/templates/native-go/backend/internal/background/runner_test.go +209 -0
  140. package/dist/templates/native-go/backend/internal/background/schedule.go +300 -0
  141. package/dist/templates/native-go/backend/internal/background/schedule_test.go +335 -0
  142. package/dist/templates/native-go/backend/internal/background/store.go +807 -0
  143. package/dist/templates/native-go/backend/internal/background/store_test.go +407 -0
  144. package/dist/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
  145. package/dist/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
  146. package/dist/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
  147. package/dist/templates/native-go/backend/internal/filestation/client.go +251 -0
  148. package/dist/templates/native-go/backend/internal/filestation/client_test.go +155 -0
  149. package/dist/templates/native-go/backend/internal/filestation/doc.go +4 -0
  150. package/dist/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
  151. package/dist/templates/native-go/backend/internal/filestation/repository.go +207 -0
  152. package/dist/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
  153. package/dist/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
  154. package/dist/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
  155. package/dist/templates/native-go/backend/internal/filestation/service.go +254 -0
  156. package/dist/templates/native-go/backend/internal/filestation/service_test.go +94 -0
  157. package/dist/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
  158. package/dist/templates/native-go/backend/internal/filestation/write.go +72 -0
  159. package/dist/templates/native-go/backend/internal/filestation/write_test.go +123 -0
  160. package/dist/templates/native-go/backend/internal/helper/background_proof.go +163 -0
  161. package/dist/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
  162. package/dist/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
  163. package/dist/templates/native-go/backend/internal/helper/data_contract.go +3 -0
  164. package/dist/templates/native-go/backend/internal/helper/data_protocol.go +3 -0
  165. package/dist/templates/native-go/backend/internal/helper/data_protocol_test.go +1 -1
  166. package/dist/templates/native-go/backend/internal/helper/grant_authority.go +3 -0
  167. package/dist/templates/native-go/backend/internal/helper/grant_authority_test.go +1 -1
  168. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux.go +2 -1
  169. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +4 -3
  170. package/dist/templates/native-go/backend/internal/helper/grant_snapshot.go +3 -0
  171. package/dist/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
  172. package/dist/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
  173. package/dist/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
  174. package/dist/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
  175. package/dist/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
  176. package/dist/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
  177. package/dist/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
  178. package/dist/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
  179. package/dist/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
  180. package/dist/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
  181. package/dist/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
  182. package/dist/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
  183. package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
  184. package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
  185. package/dist/templates/native-go/backend/internal/helper/management.go +79 -0
  186. package/dist/templates/native-go/backend/internal/helper/observation.go +42 -2
  187. package/dist/templates/native-go/backend/internal/helper/observation_health_test.go +13 -1
  188. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic.go +56 -10
  189. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +6 -0
  190. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
  191. package/dist/templates/native-go/backend/internal/helper/process_linux.go +3 -0
  192. package/dist/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
  193. package/dist/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
  194. package/dist/templates/native-go/backend/internal/helper/relaxed_invalidation.go +3 -0
  195. package/dist/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +23 -4
  196. package/dist/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
  197. package/dist/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
  198. package/dist/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
  199. package/dist/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
  200. package/dist/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
  201. package/dist/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
  202. package/dist/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
  203. package/dist/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
  204. package/dist/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
  205. package/dist/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
  206. package/dist/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
  207. package/dist/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
  208. package/dist/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
  209. package/dist/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
  210. package/dist/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
  211. package/dist/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
  212. package/dist/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
  213. package/dist/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
  214. package/dist/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
  215. package/dist/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
  216. package/dist/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
  217. package/dist/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
  218. package/dist/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
  219. package/dist/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
  220. package/dist/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
  221. package/dist/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
  222. package/dist/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
  223. package/dist/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
  224. package/dist/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
  225. package/dist/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
  226. package/dist/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
  227. package/dist/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
  228. package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
  229. package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
  230. package/dist/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
  231. package/dist/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
  232. package/dist/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
  233. package/dist/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
  234. package/dist/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
  235. package/dist/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
  236. package/dist/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
  237. package/dist/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
  238. package/dist/templates/native-go/backend/internal/helper/sdk_server_linux.go +152 -0
  239. package/dist/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
  240. package/dist/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
  241. package/dist/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
  242. package/dist/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
  243. package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
  244. package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
  245. package/dist/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
  246. package/dist/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
  247. package/dist/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
  248. package/dist/templates/native-go/backend/internal/helper/server_linux.go +3 -0
  249. package/dist/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
  250. package/dist/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
  251. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
  252. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
  253. package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
  254. package/dist/templates/native-go/backend/internal/helper/status.go +22 -13
  255. package/dist/templates/native-go/backend/internal/helper/status_test.go +45 -0
  256. package/dist/templates/native-go/backend/internal/helper/supervision.go +1 -1
  257. package/dist/templates/native-go/backend/internal/helper/supervisor_frame.go +3 -0
  258. package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +6 -2
  259. package/dist/templates/native-go/backend/internal/helper/unit_connection_test.go +22 -4
  260. package/dist/templates/native-go/backend/internal/helper/unit_linux.go +7 -3
  261. package/dist/templates/native-go/backend/internal/helper/unit_query_linux.go +5 -1
  262. package/dist/templates/native-go/backend/internal/helper/write_files_linux.go +7 -4
  263. package/dist/templates/native-go/backend/internal/helper/write_files_linux_test.go +26 -0
  264. package/dist/templates/native-go/dsm-package.yaml +1 -1
  265. package/dist/templates/native-go-background/BACKGROUND.md +111 -0
  266. package/dist/templates/native-go-background/backend/internal/app/background_on.go +7 -0
  267. package/dist/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
  268. package/dist/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
  269. package/dist/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
  270. package/dist/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
  271. package/dist/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
  272. package/dist/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
  273. package/dist/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
  274. package/dist/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
  275. package/dist/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
  276. package/dist/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
  277. package/dist/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
  278. package/dist/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
  279. package/dist/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
  280. package/dist/templates/native-go-background/frontend/test/background.test.ts +179 -0
  281. package/dist/templates/native-go-integration/backend/internal/app/personal.go +2 -2
  282. package/dist/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
  283. package/dist/templates/native-go-vue/README.md +38 -7
  284. package/dist/templates/native-go-vue/frontend/DESIGN.md +15 -3
  285. package/dist/templates/native-go-vue/frontend/README-JOBS.md +75 -0
  286. package/dist/templates/native-go-vue/frontend/README-M2.md +64 -0
  287. package/dist/templates/native-go-vue/frontend/package-lock.json +5 -4
  288. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  289. package/dist/templates/native-go-vue/frontend/src/App.vue +39 -11
  290. package/dist/templates/native-go-vue/frontend/src/M2App.vue +57 -0
  291. package/dist/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
  292. package/dist/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
  293. package/dist/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
  294. package/dist/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
  295. package/dist/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
  296. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
  297. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
  298. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
  299. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
  300. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
  301. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
  302. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
  303. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
  304. package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
  305. package/dist/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
  306. package/dist/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
  307. package/dist/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
  308. package/dist/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
  309. package/dist/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
  310. package/dist/templates/native-go-vue/frontend/src/m2-style.css +7 -0
  311. package/dist/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
  312. package/dist/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
  313. package/dist/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
  314. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
  315. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
  316. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
  317. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
  318. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
  319. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
  320. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
  321. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
  322. package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
  323. package/dist/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
  324. package/dist/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
  325. package/dist/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
  326. package/dist/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
  327. package/dist/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
  328. package/dist/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
  329. package/dist/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
  330. package/dist/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
  331. package/dist/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
  332. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
  333. package/dist/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
  334. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
  335. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
  336. package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
  337. package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
  338. package/dist/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
  339. package/dist/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
  340. package/dist/templates/native-go-vue/frontend/src/style.css +2 -6
  341. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +21 -0
  342. package/dist/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
  343. package/dist/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
  344. package/dist/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
  345. package/dist/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
  346. package/dist/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
  347. package/dist/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
  348. package/dist/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
  349. package/dist/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
  350. package/dist/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
  351. package/dist/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
  352. package/dist/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
  353. package/dist/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
  354. package/dist/templates/native-go-vue/frontend/vite.config.ts +2 -2
  355. package/dist/validate.js +6 -3
  356. package/package.json +1 -1
  357. package/schema/synology-app.schema.json +19 -0
  358. package/skills/reference/create.md +4 -0
  359. package/templates/_daemon/go.mod +2 -0
  360. package/templates/_gateway/auth.go +101 -0
  361. package/templates/_gateway/auth_test.go +216 -0
  362. package/templates/_gateway/cgi.go +133 -0
  363. package/templates/_gateway/cgi_test.go +156 -0
  364. package/templates/_gateway/csrf.go +73 -0
  365. package/templates/_gateway/csrf_test.go +155 -0
  366. package/templates/_gateway/directory.go +108 -0
  367. package/templates/_gateway/directory_test.go +202 -0
  368. package/templates/_gateway/gateway.go +412 -0
  369. package/templates/_gateway/gateway_test.go +676 -0
  370. package/templates/_gateway/go.mod +3 -0
  371. package/templates/_gateway/groups.go +66 -0
  372. package/templates/_gateway/main.go +45 -0
  373. package/templates/binary/synology-app.yaml +1 -1
  374. package/templates/compose-import/compose.yaml +1 -1
  375. package/templates/compose-import/synology-app.yaml +1 -1
  376. package/templates/hello-files/compose.yaml +1 -1
  377. package/templates/hello-files/synology-app.yaml +1 -1
  378. package/templates/hello-web/compose.yaml +5 -2
  379. package/templates/hello-web/synology-app.yaml +4 -1
  380. package/templates/hello-web-page/compose.yaml +5 -2
  381. package/templates/hello-web-page/synology-app.yaml +4 -1
  382. package/templates/native-go/README.md +93 -4
  383. package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +3 -1
  384. package/templates/native-go/backend/cmd/app/main.go +17 -0
  385. package/templates/native-go/backend/cmd/app/sdk_main.go +60 -0
  386. package/templates/native-go/backend/cmd/background-worker/main.go +38 -0
  387. package/templates/native-go/backend/cmd/helper/main.go +10 -1
  388. package/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
  389. package/templates/native-go/backend/go.mod +5 -3
  390. package/templates/native-go/backend/go.sum +4 -4
  391. package/templates/native-go/backend/internal/api/registry.go +17 -6
  392. package/templates/native-go/backend/internal/api/server.go +7 -1
  393. package/templates/native-go/backend/internal/app/background.go +270 -0
  394. package/templates/native-go/backend/internal/app/background_none.go +8 -0
  395. package/templates/native-go/backend/internal/app/background_owner.go +59 -0
  396. package/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
  397. package/templates/native-go/backend/internal/app/background_schedule.go +74 -0
  398. package/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
  399. package/templates/native-go/backend/internal/app/background_test.go +346 -0
  400. package/templates/native-go/backend/internal/app/integration_state.go +16 -0
  401. package/templates/native-go/backend/internal/app/migrations.go +41 -0
  402. package/templates/native-go/backend/internal/app/migrations_test.go +41 -0
  403. package/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +8 -0
  404. package/templates/native-go/backend/internal/app/routes.go +17 -3
  405. package/templates/native-go/backend/internal/app/routes_test.go +20 -3
  406. package/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
  407. package/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
  408. package/templates/native-go/backend/internal/app/sdk_routes.go +174 -0
  409. package/templates/native-go/backend/internal/app/session_files.go +15 -0
  410. package/templates/native-go/backend/internal/app/session_files_test.go +26 -0
  411. package/templates/native-go/backend/internal/app/shared_folder.go +144 -0
  412. package/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
  413. package/templates/native-go/backend/internal/background/access.go +57 -0
  414. package/templates/native-go/backend/internal/background/owner_test.go +126 -0
  415. package/templates/native-go/backend/internal/background/runner.go +185 -0
  416. package/templates/native-go/backend/internal/background/runner_test.go +209 -0
  417. package/templates/native-go/backend/internal/background/schedule.go +300 -0
  418. package/templates/native-go/backend/internal/background/schedule_test.go +335 -0
  419. package/templates/native-go/backend/internal/background/store.go +807 -0
  420. package/templates/native-go/backend/internal/background/store_test.go +407 -0
  421. package/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
  422. package/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
  423. package/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
  424. package/templates/native-go/backend/internal/filestation/client.go +251 -0
  425. package/templates/native-go/backend/internal/filestation/client_test.go +155 -0
  426. package/templates/native-go/backend/internal/filestation/doc.go +4 -0
  427. package/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
  428. package/templates/native-go/backend/internal/filestation/repository.go +207 -0
  429. package/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
  430. package/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
  431. package/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
  432. package/templates/native-go/backend/internal/filestation/service.go +254 -0
  433. package/templates/native-go/backend/internal/filestation/service_test.go +94 -0
  434. package/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
  435. package/templates/native-go/backend/internal/filestation/write.go +72 -0
  436. package/templates/native-go/backend/internal/filestation/write_test.go +123 -0
  437. package/templates/native-go/backend/internal/helper/background_proof.go +163 -0
  438. package/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
  439. package/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
  440. package/templates/native-go/backend/internal/helper/data_contract.go +3 -0
  441. package/templates/native-go/backend/internal/helper/data_protocol.go +3 -0
  442. package/templates/native-go/backend/internal/helper/data_protocol_test.go +1 -1
  443. package/templates/native-go/backend/internal/helper/grant_authority.go +3 -0
  444. package/templates/native-go/backend/internal/helper/grant_authority_test.go +1 -1
  445. package/templates/native-go/backend/internal/helper/grant_repository_linux.go +2 -1
  446. package/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +4 -3
  447. package/templates/native-go/backend/internal/helper/grant_snapshot.go +3 -0
  448. package/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
  449. package/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
  450. package/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
  451. package/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
  452. package/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
  453. package/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
  454. package/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
  455. package/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
  456. package/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
  457. package/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
  458. package/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
  459. package/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
  460. package/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
  461. package/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
  462. package/templates/native-go/backend/internal/helper/management.go +79 -0
  463. package/templates/native-go/backend/internal/helper/observation.go +42 -2
  464. package/templates/native-go/backend/internal/helper/observation_health_test.go +13 -1
  465. package/templates/native-go/backend/internal/helper/observer_diagnostic.go +56 -10
  466. package/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +6 -0
  467. package/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
  468. package/templates/native-go/backend/internal/helper/process_linux.go +3 -0
  469. package/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
  470. package/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
  471. package/templates/native-go/backend/internal/helper/relaxed_invalidation.go +3 -0
  472. package/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +23 -4
  473. package/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
  474. package/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
  475. package/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
  476. package/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
  477. package/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
  478. package/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
  479. package/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
  480. package/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
  481. package/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
  482. package/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
  483. package/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
  484. package/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
  485. package/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
  486. package/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
  487. package/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
  488. package/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
  489. package/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
  490. package/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
  491. package/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
  492. package/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
  493. package/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
  494. package/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
  495. package/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
  496. package/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
  497. package/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
  498. package/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
  499. package/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
  500. package/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
  501. package/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
  502. package/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
  503. package/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
  504. package/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
  505. package/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
  506. package/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
  507. package/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
  508. package/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
  509. package/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
  510. package/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
  511. package/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
  512. package/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
  513. package/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
  514. package/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
  515. package/templates/native-go/backend/internal/helper/sdk_server_linux.go +152 -0
  516. package/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
  517. package/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
  518. package/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
  519. package/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
  520. package/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
  521. package/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
  522. package/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
  523. package/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
  524. package/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
  525. package/templates/native-go/backend/internal/helper/server_linux.go +3 -0
  526. package/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
  527. package/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
  528. package/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
  529. package/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
  530. package/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
  531. package/templates/native-go/backend/internal/helper/status.go +22 -13
  532. package/templates/native-go/backend/internal/helper/status_test.go +45 -0
  533. package/templates/native-go/backend/internal/helper/supervision.go +1 -1
  534. package/templates/native-go/backend/internal/helper/supervisor_frame.go +3 -0
  535. package/templates/native-go/backend/internal/helper/supervisor_linux.go +6 -2
  536. package/templates/native-go/backend/internal/helper/unit_connection_test.go +22 -4
  537. package/templates/native-go/backend/internal/helper/unit_linux.go +7 -3
  538. package/templates/native-go/backend/internal/helper/unit_query_linux.go +5 -1
  539. package/templates/native-go/backend/internal/helper/write_files_linux.go +7 -4
  540. package/templates/native-go/backend/internal/helper/write_files_linux_test.go +26 -0
  541. package/templates/native-go/dsm-package.yaml +1 -1
  542. package/templates/native-go-background/BACKGROUND.md +111 -0
  543. package/templates/native-go-background/backend/internal/app/background_on.go +7 -0
  544. package/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
  545. package/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
  546. package/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
  547. package/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
  548. package/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
  549. package/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
  550. package/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
  551. package/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
  552. package/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
  553. package/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
  554. package/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
  555. package/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
  556. package/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
  557. package/templates/native-go-background/frontend/test/background.test.ts +179 -0
  558. package/templates/native-go-integration/backend/internal/app/personal.go +2 -2
  559. package/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
  560. package/templates/native-go-vue/README.md +38 -7
  561. package/templates/native-go-vue/frontend/DESIGN.md +15 -3
  562. package/templates/native-go-vue/frontend/README-JOBS.md +75 -0
  563. package/templates/native-go-vue/frontend/README-M2.md +64 -0
  564. package/templates/native-go-vue/frontend/package-lock.json +5 -4
  565. package/templates/native-go-vue/frontend/package.json +1 -1
  566. package/templates/native-go-vue/frontend/src/App.vue +39 -11
  567. package/templates/native-go-vue/frontend/src/M2App.vue +57 -0
  568. package/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
  569. package/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
  570. package/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
  571. package/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
  572. package/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
  573. package/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
  574. package/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
  575. package/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
  576. package/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
  577. package/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
  578. package/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
  579. package/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
  580. package/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
  581. package/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
  582. package/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
  583. package/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
  584. package/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
  585. package/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
  586. package/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
  587. package/templates/native-go-vue/frontend/src/m2-style.css +7 -0
  588. package/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
  589. package/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
  590. package/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
  591. package/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
  592. package/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
  593. package/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
  594. package/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
  595. package/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
  596. package/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
  597. package/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
  598. package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
  599. package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
  600. package/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
  601. package/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
  602. package/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
  603. package/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
  604. package/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
  605. package/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
  606. package/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
  607. package/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
  608. package/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
  609. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
  610. package/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
  611. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
  612. package/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
  613. package/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
  614. package/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
  615. package/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
  616. package/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
  617. package/templates/native-go-vue/frontend/src/style.css +2 -6
  618. package/templates/native-go-vue/frontend/test/apps.test.ts +21 -0
  619. package/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
  620. package/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
  621. package/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
  622. package/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
  623. package/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
  624. package/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
  625. package/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
  626. package/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
  627. package/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
  628. package/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
  629. package/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
  630. package/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
  631. package/templates/native-go-vue/frontend/vite.config.ts +2 -2
@@ -0,0 +1,807 @@
1
+ // Package background is the package-private spool, journal and fixed worker
2
+ // behind opt-in background jobs. The CGI submits and reads jobs; a package
3
+ // user unit runs the worker. Both run as the package account and share one
4
+ // 0700 directory, so no root helper, task scheduler or DSM session is needed.
5
+ package background
6
+
7
+ import (
8
+ "context"
9
+ "crypto/rand"
10
+ "crypto/sha256"
11
+ "encoding/hex"
12
+ "encoding/json"
13
+ "errors"
14
+ "io"
15
+ "os"
16
+ "regexp"
17
+ "syscall"
18
+ "time"
19
+ "unicode"
20
+ "unicode/utf8"
21
+
22
+ "golang.org/x/sys/unix"
23
+ )
24
+
25
+ // Product limits, not DSM limits.
26
+ const (
27
+ WorkerSHA256V1 = "sha256-v1"
28
+ // WorkerRevision identifies the worker code. A journal written under another
29
+ // revision never has its queued jobs run by this one.
30
+ WorkerRevision = 1
31
+ MaxInputBytes = 512 * 1024
32
+ MaxQueued = 16
33
+ MaxOwnerPending = 2
34
+ MaxOwnerBytes = 1 << 20
35
+ MaxPurgeAudit = 64
36
+ MaxTotalBytes = 16 << 20
37
+ JobTimeout = 60 * time.Second
38
+ // MaxHistory bounds finished jobs kept for reading results and for key reuse.
39
+ MaxHistory = 64
40
+
41
+ schemaVersion = 1
42
+ // resultReserve is charged against the total quota for every kept result.
43
+ resultReserve = 512
44
+ maxJournal = 4 << 20
45
+ )
46
+
47
+ type State string
48
+
49
+ const (
50
+ StateQueued State = "queued"
51
+ StateRunning State = "running"
52
+ StateSucceeded State = "succeeded"
53
+ StateFailed State = "failed"
54
+ StateCanceled State = "canceled"
55
+ StateInterrupted State = "interrupted"
56
+ )
57
+
58
+ func (s State) terminal() bool { return s != StateQueued && s != StateRunning }
59
+
60
+ var (
61
+ ErrOrdinaryDisabled = errors.New("ordinary background users are disabled")
62
+ ErrOwnerQueueFull = errors.New("owner pending quota reached")
63
+ ErrOwnerQuota = errors.New("owner storage quota reached")
64
+ ErrDisabled = errors.New("background mode is off")
65
+ ErrInvalid = errors.New("invalid background request")
66
+ ErrTooLarge = errors.New("input is larger than the per-file limit")
67
+ ErrQueueFull = errors.New("background queue is full")
68
+ ErrQuota = errors.New("background spool quota reached")
69
+ ErrKeyConflict = errors.New("idempotency key already used for another input")
70
+ ErrNotFound = errors.New("job not found")
71
+ ErrNotCancelable = errors.New("job already finished")
72
+ ErrNotRunning = errors.New("job is not running")
73
+ ErrUnsafeSpool = errors.New("background spool is not private to the package account")
74
+ )
75
+
76
+ // Submitter binds visibility to a fresh DSM username and UID. It never grants
77
+ // filesystem permissions or changes the worker identity.
78
+ type Submitter struct {
79
+ User string `json:"user"`
80
+ UID string `json:"uid"`
81
+ }
82
+
83
+ type Result struct {
84
+ SHA256 string `json:"sha256"`
85
+ Bytes int `json:"bytes"`
86
+ }
87
+
88
+ type Job struct {
89
+ CopyRetained bool `json:"copyRetained,omitempty"`
90
+ ScheduleID string `json:"scheduleId,omitempty"`
91
+ ScheduledAt time.Time `json:"scheduledAt,omitzero"`
92
+ ID string `json:"id"`
93
+ Key string `json:"key"`
94
+ Name string `json:"name"`
95
+ State State `json:"state"`
96
+ PurgeRequested bool `json:"purgeRequested,omitempty"`
97
+ CancelRequested bool `json:"cancelRequested,omitempty"`
98
+ Submitter Submitter `json:"submitter"`
99
+ Worker string `json:"worker"`
100
+ WorkerRevision int `json:"workerRevision"`
101
+ InputDigest string `json:"inputDigest"`
102
+ InputBytes int `json:"inputBytes"`
103
+ SubmittedAt time.Time `json:"submittedAt"`
104
+ StartedAt time.Time `json:"startedAt,omitzero"`
105
+ FinishedAt time.Time `json:"finishedAt,omitzero"`
106
+ ErrorCode string `json:"errorCode,omitempty"`
107
+ Result *Result `json:"result,omitempty"`
108
+ }
109
+
110
+ type SubmitRequest struct {
111
+ Admin bool // trusted request policy, not a client-supplied field
112
+ Key string
113
+ Name string
114
+ Data []byte
115
+ Submitter Submitter
116
+ }
117
+
118
+ // Outcome is what a worker reports for the job it claimed.
119
+ type Outcome struct {
120
+ State State
121
+ ErrorCode string
122
+ Result *Result
123
+ }
124
+
125
+ type WorkerInfo struct {
126
+ PID int `json:"pid"`
127
+ UID int `json:"uid"`
128
+ Username string `json:"username"`
129
+ Revision int `json:"revision"`
130
+ At time.Time `json:"at"`
131
+ }
132
+
133
+ type Status struct {
134
+ AllowOrdinaryUsers bool `json:"allowOrdinaryUsers"`
135
+ Enabled bool `json:"enabled"`
136
+ Algorithm string `json:"algorithm"`
137
+ Revision int `json:"revision"`
138
+ Queued int `json:"queued"`
139
+ Running int `json:"running"`
140
+ Worker *WorkerInfo `json:"worker,omitempty"`
141
+ }
142
+
143
+ type Limits struct{ MaxTotalBytes int64 }
144
+
145
+ type journal struct {
146
+ Schedules []Schedule `json:"schedules,omitempty"`
147
+ AllowOrdinaryUsers bool `json:"allowOrdinaryUsers,omitempty"`
148
+ PurgeAudit []PurgeAudit `json:"purgeAudit,omitempty"`
149
+ Schema int `json:"schema"`
150
+ Revision int `json:"workerRevision"`
151
+ Enabled bool `json:"enabled"`
152
+ Jobs []Job `json:"jobs"`
153
+ }
154
+
155
+ // Store is safe for concurrent use by several processes: every operation runs
156
+ // under an exclusive flock and commits the journal with write, fsync, rename.
157
+ type Store struct {
158
+ dir string
159
+ limits Limits
160
+ revision int
161
+ now func() time.Time
162
+ }
163
+
164
+ func NewStore(dir string) *Store {
165
+ return &Store{dir: dir, limits: Limits{MaxTotalBytes: MaxTotalBytes}, revision: WorkerRevision, now: time.Now}
166
+ }
167
+
168
+ var (
169
+ jobID = regexp.MustCompile(`^[0-9a-f]{32}$`)
170
+ keyRE = regexp.MustCompile(`^[A-Za-z0-9._-]{1,64}$`)
171
+ inputs = "inputs"
172
+ )
173
+
174
+ func validName(name string) bool {
175
+ if n := utf8.RuneCountInString(name); n < 1 || n > 128 || !utf8.ValidString(name) {
176
+ return false
177
+ }
178
+ for _, r := range name {
179
+ if unicode.IsControl(r) || r == '/' || r == '\\' {
180
+ return false
181
+ }
182
+ }
183
+ return true
184
+ }
185
+
186
+ // withJournal runs fn on the journal under the spool lock. fn reports whether
187
+ // it changed anything; only then is the journal rewritten.
188
+ func (s *Store) withJournal(ctx context.Context, fn func(root *os.Root, j *journal) (bool, error)) error {
189
+ root, err := s.openRoot()
190
+ if err != nil {
191
+ return err
192
+ }
193
+ defer root.Close()
194
+ lock, err := root.OpenFile("lock", os.O_CREATE|os.O_RDWR|unix.O_NOFOLLOW, 0o600)
195
+ if err != nil {
196
+ return err
197
+ }
198
+ defer lock.Close()
199
+ if err := checkPrivate(lock); err != nil {
200
+ return err
201
+ }
202
+ for {
203
+ err = unix.Flock(int(lock.Fd()), unix.LOCK_EX|unix.LOCK_NB)
204
+ if err == nil {
205
+ break
206
+ }
207
+ if !errors.Is(err, unix.EWOULDBLOCK) {
208
+ return err
209
+ }
210
+ select {
211
+ case <-ctx.Done():
212
+ return ctx.Err()
213
+ case <-time.After(10 * time.Millisecond):
214
+ }
215
+ }
216
+ defer unix.Flock(int(lock.Fd()), unix.LOCK_UN)
217
+ j, err := s.readJournal(root)
218
+ if err != nil {
219
+ return err
220
+ }
221
+ changed, err := fn(root, &j)
222
+ if err != nil || !changed {
223
+ return err
224
+ }
225
+ if err := writeAtomic(root, "journal.json", &j); err != nil {
226
+ return err
227
+ }
228
+ s.removeOrphanInputs(root, &j)
229
+ return nil
230
+ }
231
+
232
+ // openRoot creates the spool on first use and refuses one that is a symlink,
233
+ // belongs to someone else or is readable by other accounts.
234
+ func (s *Store) openRoot() (*os.Root, error) {
235
+ if err := os.Mkdir(s.dir, 0o700); err != nil && !errors.Is(err, os.ErrExist) {
236
+ return nil, err
237
+ }
238
+ info, err := os.Lstat(s.dir)
239
+ if err != nil {
240
+ return nil, err
241
+ }
242
+ if err := checkPrivateInfo(info, true); err != nil {
243
+ return nil, err
244
+ }
245
+ root, err := os.OpenRoot(s.dir)
246
+ if err != nil {
247
+ return nil, err
248
+ }
249
+ if err := root.Mkdir(inputs, 0o700); err != nil && !errors.Is(err, os.ErrExist) {
250
+ root.Close()
251
+ return nil, err
252
+ }
253
+ if info, err := root.Lstat(inputs); err != nil || checkPrivateInfo(info, true) != nil {
254
+ root.Close()
255
+ return nil, ErrUnsafeSpool
256
+ }
257
+ return root, nil
258
+ }
259
+
260
+ func checkPrivate(f *os.File) error {
261
+ info, err := f.Stat()
262
+ if err != nil {
263
+ return err
264
+ }
265
+ return checkPrivateInfo(info, false)
266
+ }
267
+
268
+ func checkPrivateInfo(info os.FileInfo, dir bool) error {
269
+ if dir != info.IsDir() || (!dir && !info.Mode().IsRegular()) || info.Mode().Perm()&0o077 != 0 || !ownedByUs(info) {
270
+ return ErrUnsafeSpool
271
+ }
272
+ return nil
273
+ }
274
+
275
+ func (s *Store) readJournal(root *os.Root) (journal, error) {
276
+ j := journal{Schema: schemaVersion, Revision: s.revision}
277
+ f, err := root.OpenFile("journal.json", os.O_RDONLY|unix.O_NOFOLLOW, 0)
278
+ if errors.Is(err, os.ErrNotExist) {
279
+ return j, nil
280
+ }
281
+ if err != nil {
282
+ return j, err
283
+ }
284
+ defer f.Close()
285
+ if err := checkPrivate(f); err != nil {
286
+ return j, err
287
+ }
288
+ b, err := io.ReadAll(io.LimitReader(f, maxJournal+1))
289
+ if err != nil || len(b) > maxJournal {
290
+ return j, errors.New("background journal unreadable")
291
+ }
292
+ if err := json.Unmarshal(b, &j); err != nil || j.Schema != schemaVersion {
293
+ return journal{}, errors.New("background journal has an unsupported schema")
294
+ }
295
+ return j, nil
296
+ }
297
+
298
+ func writeAtomic(root *os.Root, name string, v any) error {
299
+ b, err := json.Marshal(v)
300
+ if err != nil {
301
+ return err
302
+ }
303
+ nonce := make([]byte, 8)
304
+ if _, err := rand.Read(nonce); err != nil {
305
+ return err
306
+ }
307
+ tmp := "." + name + "-" + hex.EncodeToString(nonce)
308
+ f, err := root.OpenFile(tmp, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o600)
309
+ if err != nil {
310
+ return err
311
+ }
312
+ _, err = f.Write(b)
313
+ if err == nil {
314
+ err = f.Sync()
315
+ }
316
+ if cerr := f.Close(); err == nil {
317
+ err = cerr
318
+ }
319
+ if err == nil {
320
+ err = root.Rename(tmp, name)
321
+ }
322
+ if err != nil {
323
+ _ = root.Remove(tmp)
324
+ return err
325
+ }
326
+ return syncDir(root, ".")
327
+ }
328
+
329
+ func syncDir(root *os.Root, name string) error {
330
+ d, err := root.Open(name)
331
+ if err != nil {
332
+ return err
333
+ }
334
+ defer d.Close()
335
+ return d.Sync()
336
+ }
337
+
338
+ func newID() (string, error) {
339
+ b := make([]byte, 16)
340
+ if _, err := rand.Read(b); err != nil {
341
+ return "", err
342
+ }
343
+ return hex.EncodeToString(b), nil
344
+ }
345
+
346
+ func find(j *journal, id string) *Job {
347
+ if !jobID.MatchString(id) {
348
+ return nil
349
+ }
350
+ for i := range j.Jobs {
351
+ if j.Jobs[i].ID == id {
352
+ return &j.Jobs[i]
353
+ }
354
+ }
355
+ return nil
356
+ }
357
+
358
+ func (j *journal) pending() (count int, bytes int64) {
359
+ for _, job := range j.Jobs {
360
+ if !job.State.terminal() {
361
+ count++
362
+ bytes += int64(job.InputBytes + resultReserve)
363
+ } else {
364
+ if job.CopyRetained {
365
+ bytes += int64(job.InputBytes)
366
+ }
367
+ if job.Result != nil {
368
+ bytes += resultReserve
369
+ }
370
+ }
371
+ }
372
+ for _, sc := range j.Schedules {
373
+ bytes += int64(sc.InputBytes)
374
+ }
375
+ return count, bytes
376
+ }
377
+
378
+ // trim keeps pending jobs and the newest MaxHistory finished ones.
379
+ func (j *journal) trim() {
380
+ finished := 0
381
+ for _, job := range j.Jobs {
382
+ if job.State.terminal() {
383
+ finished++
384
+ }
385
+ }
386
+ kept := j.Jobs[:0]
387
+ for _, job := range j.Jobs {
388
+ if job.State.terminal() && finished > MaxHistory {
389
+ finished--
390
+ continue
391
+ }
392
+ kept = append(kept, job)
393
+ }
394
+ j.Jobs = kept
395
+ }
396
+
397
+ func (s *Store) removeInput(root *os.Root, id string) {
398
+ _ = root.Remove(inputs + "/" + id)
399
+ }
400
+
401
+ func (s *Store) SetEnabled(ctx context.Context, enabled bool) error {
402
+ return s.withJournal(ctx, func(root *os.Root, j *journal) (bool, error) {
403
+ if j.Enabled == enabled {
404
+ return false, nil
405
+ }
406
+ j.Enabled = enabled
407
+ if !enabled {
408
+ for i := range j.Schedules {
409
+ j.Schedules[i].Enabled = false
410
+ j.Schedules[i].Reason = "disabled"
411
+ }
412
+ for i := range j.Jobs {
413
+ switch job := &j.Jobs[i]; job.State {
414
+ case StateQueued:
415
+ s.finishJob(root, job, StateCanceled, "disabled")
416
+ case StateRunning:
417
+ job.CancelRequested = true
418
+ }
419
+ }
420
+ }
421
+ return true, nil
422
+ })
423
+ }
424
+
425
+ func (s *Store) finishJob(root *os.Root, job *Job, state State, code string) {
426
+ job.State, job.ErrorCode, job.FinishedAt = state, code, s.now().UTC()
427
+ if state != StateSucceeded {
428
+ job.CopyRetained = false
429
+ }
430
+ if !job.CopyRetained {
431
+ s.removeInput(root, job.ID)
432
+ }
433
+ }
434
+
435
+ func (s *Store) Submit(ctx context.Context, req SubmitRequest) (Job, bool, error) {
436
+ if len(req.Data) > MaxInputBytes {
437
+ return Job{}, false, ErrTooLarge
438
+ }
439
+ if !keyRE.MatchString(req.Key) || !validName(req.Name) || len(req.Data) == 0 || !req.Submitter.Valid() {
440
+ return Job{}, false, ErrInvalid
441
+ }
442
+ digest := sha256hex(req.Data)
443
+ var created Job
444
+ var duplicate bool
445
+ err := s.withJournal(ctx, func(root *os.Root, j *journal) (bool, error) {
446
+ if !j.Enabled {
447
+ return false, ErrDisabled
448
+ }
449
+ if !req.Admin && !j.AllowOrdinaryUsers {
450
+ return false, ErrOrdinaryDisabled
451
+ }
452
+ for _, job := range j.Jobs {
453
+ if job.Submitter == req.Submitter && job.Key == req.Key && !job.PurgeRequested {
454
+ if job.InputDigest != digest {
455
+ return false, ErrKeyConflict
456
+ }
457
+ created, duplicate = job, true
458
+ return false, nil
459
+ }
460
+ }
461
+ // Reserve the input and one bounded result for each pending job. Finished
462
+ // result charges remain until history trimming or an explicit admin purge.
463
+ pending, ownerBytes := j.ownerUsage(req.Submitter)
464
+ if pending >= MaxOwnerPending {
465
+ return false, ErrOwnerQueueFull
466
+ }
467
+ if ownerBytes+int64(len(req.Data)+resultReserve) > MaxOwnerBytes {
468
+ return false, ErrOwnerQuota
469
+ }
470
+ count, used := j.pending()
471
+ if count >= MaxQueued {
472
+ return false, ErrQueueFull
473
+ }
474
+ if used+int64(len(req.Data)+resultReserve) > s.limits.MaxTotalBytes {
475
+ return false, ErrQuota
476
+ }
477
+ id, err := newID()
478
+ if err != nil {
479
+ return false, err
480
+ }
481
+ if err := writeInput(root, id, req.Data); err != nil {
482
+ return false, err
483
+ }
484
+ created = Job{
485
+ ID: id, Key: req.Key, Name: req.Name, CopyRetained: true, State: StateQueued, Submitter: req.Submitter,
486
+ Worker: WorkerSHA256V1, WorkerRevision: s.revision, InputDigest: digest,
487
+ InputBytes: len(req.Data), SubmittedAt: s.now().UTC(),
488
+ }
489
+ j.Jobs = append(j.Jobs, created)
490
+ j.trim()
491
+ // A journal commit failure surfaces below; the input is then orphaned
492
+ // and removed by the next Recover.
493
+ return true, nil
494
+ })
495
+ return created, duplicate, err
496
+ }
497
+
498
+ func writeInput(root *os.Root, id string, data []byte) error {
499
+ f, err := root.OpenFile(inputs+"/"+id, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o600)
500
+ if err != nil {
501
+ return err
502
+ }
503
+ _, err = f.Write(data)
504
+ if err == nil {
505
+ err = f.Sync()
506
+ }
507
+ if cerr := f.Close(); err == nil {
508
+ err = cerr
509
+ }
510
+ if err == nil {
511
+ err = syncDir(root, inputs)
512
+ }
513
+ if err != nil {
514
+ _ = root.Remove(inputs + "/" + id)
515
+ }
516
+ return err
517
+ }
518
+
519
+ func (s *Store) List(ctx context.Context) ([]Job, error) { return s.ListFor(ctx, Access{Admin: true}) }
520
+ func (s *Store) ListFor(ctx context.Context, access Access) ([]Job, error) {
521
+ var jobs []Job
522
+ err := s.withJournal(ctx, func(_ *os.Root, j *journal) (bool, error) {
523
+ for _, job := range j.Jobs {
524
+ if access.sees(job) {
525
+ jobs = append(jobs, job)
526
+ }
527
+ }
528
+ return false, nil
529
+ })
530
+ return jobs, err
531
+ }
532
+
533
+ // Get is the internal worker view, including a pending purge so cancellation drains.
534
+ func (s *Store) Get(ctx context.Context, id string) (Job, error) { return s.get(ctx, id, nil) }
535
+ func (s *Store) GetFor(ctx context.Context, id string, access Access) (Job, error) {
536
+ return s.get(ctx, id, &access)
537
+ }
538
+ func (s *Store) get(ctx context.Context, id string, access *Access) (Job, error) {
539
+ var out Job
540
+ err := s.withJournal(ctx, func(_ *os.Root, j *journal) (bool, error) {
541
+ job := find(j, id)
542
+ if job == nil || (access != nil && !access.sees(*job)) {
543
+ return false, ErrNotFound
544
+ }
545
+ out = *job
546
+ return false, nil
547
+ })
548
+ return out, err
549
+ }
550
+
551
+ func (s *Store) Cancel(ctx context.Context, id string) (Job, error) {
552
+ return s.CancelFor(ctx, id, Access{Admin: true})
553
+ }
554
+ func (s *Store) CancelFor(ctx context.Context, id string, access Access) (Job, error) {
555
+ var out Job
556
+ err := s.withJournal(ctx, func(root *os.Root, j *journal) (bool, error) {
557
+ job := find(j, id)
558
+ if job == nil || !access.sees(*job) {
559
+ return false, ErrNotFound
560
+ }
561
+ switch job.State {
562
+ case StateQueued:
563
+ s.finishJob(root, job, StateCanceled, "")
564
+ case StateRunning:
565
+ job.CancelRequested = true
566
+ default:
567
+ return false, ErrNotCancelable
568
+ }
569
+ out = *job
570
+ return true, nil
571
+ })
572
+ return out, err
573
+ }
574
+
575
+ // Claim hands the oldest queued job to the worker, or nil when there is none,
576
+ // the mode is off or another job is still running.
577
+ func (s *Store) Claim(ctx context.Context) (*Job, error) {
578
+ var out *Job
579
+ err := s.withJournal(ctx, func(_ *os.Root, j *journal) (bool, error) {
580
+ if !j.Enabled {
581
+ return false, nil
582
+ }
583
+ var next *Job
584
+ for i := range j.Jobs {
585
+ switch job := &j.Jobs[i]; job.State {
586
+ case StateRunning:
587
+ return false, nil
588
+ case StateQueued:
589
+ if next == nil {
590
+ next = job
591
+ }
592
+ }
593
+ }
594
+ if next == nil {
595
+ return false, nil
596
+ }
597
+ next.State, next.StartedAt = StateRunning, s.now().UTC()
598
+ claimed := *next
599
+ out = &claimed
600
+ return true, nil
601
+ })
602
+ return out, err
603
+ }
604
+
605
+ // Finish records the outcome of a running job. A cancel request that was
606
+ // journaled first wins over a success or failure that arrives later.
607
+ func (s *Store) Finish(ctx context.Context, id string, outcome Outcome) error {
608
+ if !outcome.State.terminal() {
609
+ return ErrInvalid
610
+ }
611
+ return s.withJournal(ctx, func(root *os.Root, j *journal) (bool, error) {
612
+ job := find(j, id)
613
+ if job == nil || job.State != StateRunning {
614
+ return false, ErrNotRunning
615
+ }
616
+ if job.CancelRequested {
617
+ outcome = Outcome{State: StateCanceled}
618
+ }
619
+ s.finishJob(root, job, outcome.State, outcome.ErrorCode)
620
+ if outcome.State == StateSucceeded {
621
+ job.Result = outcome.Result
622
+ }
623
+ j.removePurged()
624
+ j.trim()
625
+ return true, nil
626
+ })
627
+ }
628
+
629
+ // Recover runs when the worker starts. A job still marked running lost its
630
+ // worker: it is interrupted (or canceled when a cancel was already requested)
631
+ // and never replayed. Queued jobs journaled for another worker revision are
632
+ // interrupted too, so an upgrade cannot silently run old work with new code.
633
+ func (s *Store) Recover(ctx context.Context) error {
634
+ return s.withJournal(ctx, func(root *os.Root, j *journal) (bool, error) {
635
+ changed := j.Revision != s.revision
636
+ for i := range j.Jobs {
637
+ job := &j.Jobs[i]
638
+ switch {
639
+ case job.State == StateRunning && job.CancelRequested:
640
+ s.finishJob(root, job, StateCanceled, "")
641
+ changed = true
642
+ case job.State == StateRunning:
643
+ s.finishJob(root, job, StateInterrupted, "worker-stopped")
644
+ changed = true
645
+ case job.State == StateQueued && j.Revision != s.revision:
646
+ s.finishJob(root, job, StateInterrupted, "worker-changed")
647
+ }
648
+ }
649
+ j.removePurged()
650
+ changed = s.reconcileSchedules(root, j, true) || changed
651
+ j.Revision = s.revision
652
+ s.removeOrphanInputs(root, j)
653
+ return changed, nil
654
+ })
655
+ }
656
+
657
+ func (s *Store) removeOrphanInputs(root *os.Root, j *journal) {
658
+ dir, err := root.Open(inputs)
659
+ if err != nil {
660
+ return
661
+ }
662
+ names, _ := dir.Readdirnames(-1)
663
+ dir.Close()
664
+ live := map[string]bool{}
665
+ for _, job := range j.Jobs {
666
+ if !job.State.terminal() || job.CopyRetained {
667
+ live[job.ID] = true
668
+ }
669
+ }
670
+ for _, sc := range j.Schedules {
671
+ live[sc.ID] = true
672
+ }
673
+ for _, name := range names {
674
+ if !live[name] {
675
+ _ = root.Remove(inputs + "/" + name)
676
+ }
677
+ }
678
+ }
679
+
680
+ // OpenInput returns the stored input of the job that is currently running.
681
+ func (s *Store) OpenInput(id string) (*os.File, error) {
682
+ var f *os.File
683
+ err := s.withJournal(context.Background(), func(root *os.Root, j *journal) (bool, error) {
684
+ job := find(j, id)
685
+ if job == nil || job.State != StateRunning {
686
+ return false, ErrNotRunning
687
+ }
688
+ var err error
689
+ f, err = root.OpenFile(inputs+"/"+id, os.O_RDONLY|unix.O_NOFOLLOW, 0)
690
+ return false, err
691
+ })
692
+ return f, err
693
+ }
694
+
695
+ func (s *Store) Status(ctx context.Context) (Status, error) {
696
+ return s.StatusFor(ctx, Access{Admin: true})
697
+ }
698
+ func (s *Store) StatusFor(ctx context.Context, access Access) (Status, error) {
699
+ st := Status{Algorithm: WorkerSHA256V1, Revision: s.revision}
700
+ err := s.withJournal(ctx, func(root *os.Root, j *journal) (bool, error) {
701
+ st.Enabled, st.AllowOrdinaryUsers = j.Enabled, j.AllowOrdinaryUsers
702
+ for _, job := range j.Jobs {
703
+ if !access.sees(job) {
704
+ continue
705
+ }
706
+ switch job.State {
707
+ case StateQueued:
708
+ st.Queued++
709
+ case StateRunning:
710
+ st.Running++
711
+ }
712
+ }
713
+ st.Worker = readWorker(root)
714
+ return false, nil
715
+ })
716
+ return st, err
717
+ }
718
+
719
+ func readWorker(root *os.Root) *WorkerInfo {
720
+ f, err := root.OpenFile("worker.json", os.O_RDONLY|unix.O_NOFOLLOW, 0)
721
+ if err != nil {
722
+ return nil
723
+ }
724
+ defer f.Close()
725
+ b, err := io.ReadAll(io.LimitReader(f, 4096))
726
+ var w WorkerInfo
727
+ if err != nil || checkPrivate(f) != nil || json.Unmarshal(b, &w) != nil {
728
+ return nil
729
+ }
730
+ return &w
731
+ }
732
+
733
+ // Heartbeat publishes who the worker is and when it last ran. It is kept out
734
+ // of the journal so an idle worker causes no journal rewrites.
735
+ func (s *Store) Heartbeat(ctx context.Context, info WorkerInfo) error {
736
+ root, err := s.openRoot()
737
+ if err != nil {
738
+ return err
739
+ }
740
+ defer root.Close()
741
+ info.Revision, info.At = s.revision, s.now().UTC()
742
+ return writeAtomic(root, "worker.json", info)
743
+ }
744
+
745
+ func ownedByUs(info os.FileInfo) bool {
746
+ st, ok := info.Sys().(*syscall.Stat_t)
747
+ return ok && int(st.Uid) == os.Getuid()
748
+ }
749
+
750
+ func sha256hex(b []byte) string {
751
+ sum := sha256.Sum256(b)
752
+ return hex.EncodeToString(sum[:])
753
+ }
754
+
755
+ // SetOrdinaryUsers is independent of background mode, and defaults off when
756
+ // reading an A0 journal. A submission rechecks it under the same flock as enqueue.
757
+ func (s *Store) SetOrdinaryUsers(ctx context.Context, allow bool) error {
758
+ return s.withJournal(ctx, func(_ *os.Root, j *journal) (bool, error) { j.AllowOrdinaryUsers = allow; return true, nil })
759
+ }
760
+ func (j *journal) removePurged() {
761
+ kept := j.Jobs[:0]
762
+ for _, job := range j.Jobs {
763
+ if !job.PurgeRequested || !job.State.terminal() {
764
+ kept = append(kept, job)
765
+ }
766
+ }
767
+ j.Jobs = kept
768
+ }
769
+
770
+ // PurgeOwner preserves other owners and records an audit in the same durable
771
+ // journal. Running jobs become hidden tombstones until Finish/Recover drains them.
772
+ func (s *Store) PurgeOwner(ctx context.Context, owner Submitter, actor string) (PurgeAudit, error) {
773
+ if owner.User == "" || actor == "" {
774
+ return PurgeAudit{}, ErrInvalid
775
+ }
776
+ audit := PurgeAudit{Owner: owner, Actor: actor, At: s.now().UTC()}
777
+ err := s.withJournal(ctx, func(root *os.Root, j *journal) (bool, error) {
778
+ for i := range j.Jobs {
779
+ job := &j.Jobs[i]
780
+ if job.Submitter != owner || job.PurgeRequested {
781
+ continue
782
+ }
783
+ job.PurgeRequested = true
784
+ if job.State == StateRunning {
785
+ job.CancelRequested = true
786
+ audit.Draining++
787
+ } else {
788
+ s.finishJob(root, job, StateCanceled, "purged")
789
+ audit.Removed++
790
+ }
791
+ }
792
+ kept := j.Schedules[:0]
793
+ for _, sc := range j.Schedules {
794
+ if sc.Owner != owner {
795
+ kept = append(kept, sc)
796
+ }
797
+ }
798
+ j.Schedules = kept
799
+ j.removePurged()
800
+ j.PurgeAudit = append(j.PurgeAudit, audit)
801
+ if len(j.PurgeAudit) > MaxPurgeAudit {
802
+ j.PurgeAudit = j.PurgeAudit[len(j.PurgeAudit)-MaxPurgeAudit:]
803
+ }
804
+ return true, nil
805
+ })
806
+ return audit, err
807
+ }