@synopackageland/cli 0.4.1 → 0.5.3
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.
- package/README.md +7 -3
- package/dist/authorization-sdk.d.ts +5 -0
- package/dist/authorization-sdk.js +5 -0
- package/dist/build-spk/delete-app-data.d.ts +27 -7
- package/dist/build-spk/delete-app-data.js +35 -34
- package/dist/build-spk/dsm-arch.d.ts +6 -1
- package/dist/build-spk/dsm-arch.js +25 -1
- package/dist/build-spk/dsm-version.d.ts +14 -0
- package/dist/build-spk/dsm-version.js +47 -0
- package/dist/build-spk/gateway.d.ts +31 -0
- package/dist/build-spk/gateway.js +55 -0
- package/dist/build-spk/generator.d.ts +5 -0
- package/dist/build-spk/generator.js +103 -107
- package/dist/build-spk/install-wizard.d.ts +20 -0
- package/dist/build-spk/install-wizard.js +76 -0
- package/dist/build-spk/native-lifecycle.d.ts +5 -0
- package/dist/build-spk/native-lifecycle.js +12 -2
- package/dist/build-spk/resource-worker.d.ts +9 -4
- package/dist/build-spk/resource-worker.js +15 -6
- package/dist/build-spk/share-combobox.d.ts +3 -0
- package/dist/build-spk/share-combobox.js +27 -0
- package/dist/build-spk/uninstall-wizard.d.ts +14 -0
- package/dist/build-spk/uninstall-wizard.js +33 -0
- package/dist/build-spk/wizard-i18n.d.ts +18 -0
- package/dist/build-spk/wizard-i18n.js +38 -0
- package/dist/build-spk/wizard-messages.d.ts +388 -0
- package/dist/build-spk/wizard-messages.js +387 -0
- package/dist/cli.js +132 -32
- package/dist/compose/analyze.d.ts +20 -0
- package/dist/compose/analyze.js +75 -11
- package/dist/contract/validate.js +33 -1
- package/dist/contract/web-launch.d.ts +22 -0
- package/dist/contract/web-launch.js +37 -0
- package/dist/deploy/deploy.d.ts +3 -0
- package/dist/deploy/deploy.js +11 -2
- package/dist/error-registry.js +62 -3
- package/dist/host/dsm-port-profile.d.ts +1 -1
- package/dist/host/dsm-port-profile.js +1 -1
- package/dist/host/open-url.d.ts +2 -0
- package/dist/host/open-url.js +4 -1
- package/dist/images/pin.d.ts +52 -0
- package/dist/images/pin.js +249 -0
- package/dist/init.d.ts +27 -3
- package/dist/init.js +126 -16
- package/dist/inspect.d.ts +3 -0
- package/dist/inspect.js +15 -3
- package/dist/standalone/authorization-window.d.ts +2 -0
- package/dist/standalone/authorization-window.js +28 -0
- package/dist/standalone/authorization.d.ts +48 -0
- package/dist/standalone/authorization.js +116 -0
- package/dist/standalone/background.d.ts +21 -0
- package/dist/standalone/background.js +52 -0
- package/dist/standalone/binary.d.ts +1 -0
- package/dist/standalone/binary.js +1 -1
- package/dist/standalone/build.d.ts +2 -0
- package/dist/standalone/build.js +54 -10
- package/dist/standalone/dsm-window.js +10 -3
- package/dist/standalone/helper-inventory.d.ts +15 -0
- package/dist/standalone/helper-inventory.js +9 -0
- package/dist/standalone/helper.d.ts +1 -0
- package/dist/standalone/helper.js +29 -11
- package/dist/standalone/host-adapter.d.ts +1 -1
- package/dist/standalone/host-adapter.js +33 -15
- package/dist/standalone/host-file-navigation.d.ts +7 -0
- package/dist/standalone/host-file-navigation.js +172 -0
- package/dist/standalone/inspect-helper.js +21 -6
- package/dist/standalone/inspect-spk.d.ts +1 -1
- package/dist/standalone/inspect-spk.js +211 -7
- package/dist/standalone/job-diagnostics.d.ts +1 -0
- package/dist/standalone/job-diagnostics.js +49 -0
- package/dist/standalone/lifecycle-helper.d.ts +1 -1
- package/dist/standalone/lifecycle-helper.js +2 -2
- package/dist/standalone/lifecycle.d.ts +1 -1
- package/dist/standalone/lifecycle.js +14 -4
- package/dist/standalone/manifest.d.ts +15 -2
- package/dist/standalone/manifest.js +37 -6
- package/dist/standalone/native-layout.d.ts +74 -0
- package/dist/standalone/native-layout.js +318 -0
- package/dist/standalone/resource.d.ts +11 -0
- package/dist/standalone/resource.js +13 -0
- package/dist/standalone/root-ops.d.ts +2 -0
- package/dist/standalone/root-ops.js +10 -0
- package/dist/standalone/root-window.d.ts +3 -1
- package/dist/standalone/root-window.js +156 -38
- package/dist/standalone/shared-folder.d.ts +39 -0
- package/dist/standalone/shared-folder.js +141 -0
- package/dist/standalone/spk.d.ts +4 -0
- package/dist/standalone/spk.js +47 -3
- package/dist/standalone/worker-contract-json.d.ts +8 -0
- package/dist/standalone/worker-contract-json.js +141 -0
- package/dist/standalone/worker-contract.d.ts +189 -0
- package/dist/standalone/worker-contract.js +175 -0
- package/dist/standalone/worker-registry.d.ts +40 -0
- package/dist/standalone/worker-registry.js +167 -0
- package/dist/templates/_authorization/main.go +104 -0
- package/dist/templates/_authorization/main_test.go +35 -0
- package/dist/templates/_daemon/go.mod +2 -0
- package/dist/templates/_gateway/auth.go +101 -0
- package/dist/templates/_gateway/auth_test.go +216 -0
- package/dist/templates/_gateway/cgi.go +133 -0
- package/dist/templates/_gateway/cgi_test.go +156 -0
- package/dist/templates/_gateway/csrf.go +73 -0
- package/dist/templates/_gateway/csrf_test.go +155 -0
- package/dist/templates/_gateway/directory.go +108 -0
- package/dist/templates/_gateway/directory_test.go +202 -0
- package/dist/templates/_gateway/gateway.go +412 -0
- package/dist/templates/_gateway/gateway_test.go +676 -0
- package/dist/templates/_gateway/go.mod +3 -0
- package/dist/templates/_gateway/groups.go +66 -0
- package/dist/templates/_gateway/main.go +45 -0
- package/dist/templates/binary/synology-app.yaml +1 -1
- package/dist/templates/compose-import/compose.yaml +1 -1
- package/dist/templates/compose-import/synology-app.yaml +1 -1
- package/dist/templates/hello-files/compose.yaml +1 -1
- package/dist/templates/hello-files/synology-app.yaml +1 -1
- package/dist/templates/native-go/README.md +118 -5
- package/dist/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +3 -1
- package/dist/templates/native-go/backend/cmd/app/main.go +25 -6
- package/dist/templates/native-go/backend/cmd/app/sdk_main.go +62 -0
- package/dist/templates/native-go/backend/cmd/background-worker/main.go +38 -0
- package/dist/templates/native-go/backend/cmd/helper/main.go +27 -1
- package/dist/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
- package/dist/templates/native-go/backend/go.mod +5 -3
- package/dist/templates/native-go/backend/go.sum +4 -4
- package/dist/templates/native-go/backend/internal/api/registry.go +17 -6
- package/dist/templates/native-go/backend/internal/api/server.go +7 -1
- package/dist/templates/native-go/backend/internal/app/authorization_none.go +5 -0
- package/dist/templates/native-go/backend/internal/app/background.go +270 -0
- package/dist/templates/native-go/backend/internal/app/background_none.go +8 -0
- package/dist/templates/native-go/backend/internal/app/background_owner.go +59 -0
- package/dist/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
- package/dist/templates/native-go/backend/internal/app/background_schedule.go +74 -0
- package/dist/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
- package/dist/templates/native-go/backend/internal/app/background_test.go +346 -0
- package/dist/templates/native-go/backend/internal/app/integration_state.go +16 -0
- package/dist/templates/native-go/backend/internal/app/migrations.go +41 -0
- package/dist/templates/native-go/backend/internal/app/migrations_test.go +41 -0
- package/dist/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +8 -0
- package/dist/templates/native-go/backend/internal/app/routes.go +22 -5
- package/dist/templates/native-go/backend/internal/app/routes_test.go +20 -3
- package/dist/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
- package/dist/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
- package/dist/templates/native-go/backend/internal/app/sdk_routes.go +177 -0
- package/dist/templates/native-go/backend/internal/app/session_files.go +15 -0
- package/dist/templates/native-go/backend/internal/app/session_files_test.go +26 -0
- package/dist/templates/native-go/backend/internal/app/shared_folder.go +144 -0
- package/dist/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
- package/dist/templates/native-go/backend/internal/background/access.go +57 -0
- package/dist/templates/native-go/backend/internal/background/owner_test.go +126 -0
- package/dist/templates/native-go/backend/internal/background/runner.go +185 -0
- package/dist/templates/native-go/backend/internal/background/runner_test.go +209 -0
- package/dist/templates/native-go/backend/internal/background/schedule.go +300 -0
- package/dist/templates/native-go/backend/internal/background/schedule_test.go +335 -0
- package/dist/templates/native-go/backend/internal/background/store.go +807 -0
- package/dist/templates/native-go/backend/internal/background/store_test.go +407 -0
- package/dist/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
- package/dist/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
- package/dist/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
- package/dist/templates/native-go/backend/internal/filestation/client.go +251 -0
- package/dist/templates/native-go/backend/internal/filestation/client_test.go +155 -0
- package/dist/templates/native-go/backend/internal/filestation/doc.go +4 -0
- package/dist/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
- package/dist/templates/native-go/backend/internal/filestation/repository.go +207 -0
- package/dist/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
- package/dist/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
- package/dist/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
- package/dist/templates/native-go/backend/internal/filestation/service.go +254 -0
- package/dist/templates/native-go/backend/internal/filestation/service_test.go +94 -0
- package/dist/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
- package/dist/templates/native-go/backend/internal/filestation/write.go +72 -0
- package/dist/templates/native-go/backend/internal/filestation/write_test.go +123 -0
- package/dist/templates/native-go/backend/internal/helper/background_proof.go +163 -0
- package/dist/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
- package/dist/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
- package/dist/templates/native-go/backend/internal/helper/data_contract.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/data_protocol.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/data_protocol_test.go +1 -1
- package/dist/templates/native-go/backend/internal/helper/grant_authority.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/grant_authority_test.go +1 -1
- package/dist/templates/native-go/backend/internal/helper/grant_repository_linux.go +2 -1
- package/dist/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +4 -3
- package/dist/templates/native-go/backend/internal/helper/grant_snapshot.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
- package/dist/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
- package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
- package/dist/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
- package/dist/templates/native-go/backend/internal/helper/management.go +86 -0
- package/dist/templates/native-go/backend/internal/helper/observation.go +42 -2
- package/dist/templates/native-go/backend/internal/helper/observation_health_test.go +13 -1
- package/dist/templates/native-go/backend/internal/helper/observer_diagnostic.go +56 -10
- package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +6 -0
- package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
- package/dist/templates/native-go/backend/internal/helper/process_linux.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/purge.go +115 -0
- package/dist/templates/native-go/backend/internal/helper/purge_test.go +59 -0
- package/dist/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
- package/dist/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
- package/dist/templates/native-go/backend/internal/helper/relaxed_invalidation.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/revoke.go +109 -0
- package/dist/templates/native-go/backend/internal/helper/revoke_test.go +121 -0
- package/dist/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +23 -4
- package/dist/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_server_linux.go +161 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
- package/dist/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
- package/dist/templates/native-go/backend/internal/helper/server_linux.go +14 -2
- package/dist/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
- package/dist/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
- package/dist/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
- package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
- package/dist/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
- package/dist/templates/native-go/backend/internal/helper/status.go +22 -13
- package/dist/templates/native-go/backend/internal/helper/status_test.go +45 -0
- package/dist/templates/native-go/backend/internal/helper/supervision.go +1 -1
- package/dist/templates/native-go/backend/internal/helper/supervisor_frame.go +3 -0
- package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +6 -2
- package/dist/templates/native-go/backend/internal/helper/unit_connection_test.go +22 -4
- package/dist/templates/native-go/backend/internal/helper/unit_linux.go +7 -3
- package/dist/templates/native-go/backend/internal/helper/unit_query_linux.go +5 -1
- package/dist/templates/native-go/backend/internal/helper/write_files_linux.go +7 -4
- package/dist/templates/native-go/backend/internal/helper/write_files_linux_test.go +26 -0
- package/dist/templates/native-go/dsm-package.yaml +2 -2
- package/dist/templates/native-go-authorization/backend/internal/app/authorization.go +298 -0
- package/dist/templates/native-go-authorization/backend/internal/app/authorization_test.go +96 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/AuthorizationGate.vue +89 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/de.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/en.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/es.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/fr.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/index.ts +15 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/it.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/ja.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/ko.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/zh-CN.json +36 -0
- package/dist/templates/native-go-authorization/frontend/src/authorization/i18n/zh-TW.json +36 -0
- package/dist/templates/native-go-authorization/frontend/test/authorization-preview.html +14 -0
- package/dist/templates/native-go-authorization/frontend/test/authorization.test.ts +59 -0
- package/dist/templates/native-go-background/BACKGROUND.md +111 -0
- package/dist/templates/native-go-background/backend/internal/app/background_on.go +7 -0
- package/dist/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
- package/dist/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
- package/dist/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
- package/dist/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
- package/dist/templates/native-go-background/frontend/test/background.test.ts +179 -0
- package/dist/templates/native-go-integration/backend/internal/app/personal.go +2 -2
- package/dist/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
- package/dist/templates/native-go-vue/README.md +38 -7
- package/dist/templates/native-go-vue/frontend/DESIGN.md +15 -3
- package/dist/templates/native-go-vue/frontend/README-JOBS.md +75 -0
- package/dist/templates/native-go-vue/frontend/README-M2.md +64 -0
- package/dist/templates/native-go-vue/frontend/package-lock.json +5 -4
- package/dist/templates/native-go-vue/frontend/package.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/App.vue +39 -11
- package/dist/templates/native-go-vue/frontend/src/M2App.vue +57 -0
- package/dist/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
- package/dist/templates/native-go-vue/frontend/src/context.ts +3 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
- package/dist/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
- package/dist/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
- package/dist/templates/native-go-vue/frontend/src/m2-style.css +7 -0
- package/dist/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
- package/dist/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
- package/dist/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
- package/dist/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
- package/dist/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
- package/dist/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
- package/dist/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
- package/dist/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
- package/dist/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
- package/dist/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
- package/dist/templates/native-go-vue/frontend/src/style.css +2 -6
- package/dist/templates/native-go-vue/frontend/test/apps.test.ts +21 -0
- package/dist/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
- package/dist/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
- package/dist/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
- package/dist/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
- package/dist/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
- package/dist/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
- package/dist/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
- package/dist/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
- package/dist/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
- package/dist/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
- package/dist/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
- package/dist/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
- package/dist/templates/native-go-vue/frontend/vite.config.ts +2 -2
- package/dist/types.d.ts +1 -1
- package/dist/validate.js +6 -3
- package/package.json +5 -2
- package/schema/synology-app.schema.json +19 -0
- package/skills/reference/create.md +6 -2
- package/templates/_authorization/main.go +104 -0
- package/templates/_authorization/main_test.go +35 -0
- package/templates/_daemon/go.mod +2 -0
- package/templates/_gateway/auth.go +101 -0
- package/templates/_gateway/auth_test.go +216 -0
- package/templates/_gateway/cgi.go +133 -0
- package/templates/_gateway/cgi_test.go +156 -0
- package/templates/_gateway/csrf.go +73 -0
- package/templates/_gateway/csrf_test.go +155 -0
- package/templates/_gateway/directory.go +108 -0
- package/templates/_gateway/directory_test.go +202 -0
- package/templates/_gateway/gateway.go +412 -0
- package/templates/_gateway/gateway_test.go +676 -0
- package/templates/_gateway/go.mod +3 -0
- package/templates/_gateway/groups.go +66 -0
- package/templates/_gateway/main.go +45 -0
- package/templates/binary/synology-app.yaml +1 -1
- package/templates/compose-import/compose.yaml +1 -1
- package/templates/compose-import/synology-app.yaml +1 -1
- package/templates/hello-files/compose.yaml +1 -1
- package/templates/hello-files/synology-app.yaml +1 -1
- package/templates/native-go/README.md +118 -5
- package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +3 -1
- package/templates/native-go/backend/cmd/app/main.go +25 -6
- package/templates/native-go/backend/cmd/app/sdk_main.go +62 -0
- package/templates/native-go/backend/cmd/background-worker/main.go +38 -0
- package/templates/native-go/backend/cmd/helper/main.go +27 -1
- package/templates/native-go/backend/cmd/helper/sdk_registry.go +19 -0
- package/templates/native-go/backend/go.mod +5 -3
- package/templates/native-go/backend/go.sum +4 -4
- package/templates/native-go/backend/internal/api/registry.go +17 -6
- package/templates/native-go/backend/internal/api/server.go +7 -1
- package/templates/native-go/backend/internal/app/authorization_none.go +5 -0
- package/templates/native-go/backend/internal/app/background.go +270 -0
- package/templates/native-go/backend/internal/app/background_none.go +8 -0
- package/templates/native-go/backend/internal/app/background_owner.go +59 -0
- package/templates/native-go/backend/internal/app/background_owner_test.go +145 -0
- package/templates/native-go/backend/internal/app/background_schedule.go +74 -0
- package/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
- package/templates/native-go/backend/internal/app/background_test.go +346 -0
- package/templates/native-go/backend/internal/app/integration_state.go +16 -0
- package/templates/native-go/backend/internal/app/migrations.go +41 -0
- package/templates/native-go/backend/internal/app/migrations_test.go +41 -0
- package/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +8 -0
- package/templates/native-go/backend/internal/app/routes.go +22 -5
- package/templates/native-go/backend/internal/app/routes_test.go +20 -3
- package/templates/native-go/backend/internal/app/sdk_jobs.go +70 -0
- package/templates/native-go/backend/internal/app/sdk_jobs_test.go +116 -0
- package/templates/native-go/backend/internal/app/sdk_routes.go +177 -0
- package/templates/native-go/backend/internal/app/session_files.go +15 -0
- package/templates/native-go/backend/internal/app/session_files_test.go +26 -0
- package/templates/native-go/backend/internal/app/shared_folder.go +144 -0
- package/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
- package/templates/native-go/backend/internal/background/access.go +57 -0
- package/templates/native-go/backend/internal/background/owner_test.go +126 -0
- package/templates/native-go/backend/internal/background/runner.go +185 -0
- package/templates/native-go/backend/internal/background/runner_test.go +209 -0
- package/templates/native-go/backend/internal/background/schedule.go +300 -0
- package/templates/native-go/backend/internal/background/schedule_test.go +335 -0
- package/templates/native-go/backend/internal/background/store.go +807 -0
- package/templates/native-go/backend/internal/background/store_test.go +407 -0
- package/templates/native-go/backend/internal/datamigrate/migrate.go +191 -0
- package/templates/native-go/backend/internal/datamigrate/migrate_test.go +177 -0
- package/templates/native-go/backend/internal/filestation/browse_test.go +67 -0
- package/templates/native-go/backend/internal/filestation/client.go +251 -0
- package/templates/native-go/backend/internal/filestation/client_test.go +155 -0
- package/templates/native-go/backend/internal/filestation/doc.go +4 -0
- package/templates/native-go/backend/internal/filestation/read_file_test.go +90 -0
- package/templates/native-go/backend/internal/filestation/repository.go +207 -0
- package/templates/native-go/backend/internal/filestation/repository_test.go +104 -0
- package/templates/native-go/backend/internal/filestation/sdk_session.go +241 -0
- package/templates/native-go/backend/internal/filestation/sdk_session_test.go +183 -0
- package/templates/native-go/backend/internal/filestation/service.go +254 -0
- package/templates/native-go/backend/internal/filestation/service_test.go +94 -0
- package/templates/native-go/backend/internal/filestation/session_semantics_test.go +383 -0
- package/templates/native-go/backend/internal/filestation/write.go +72 -0
- package/templates/native-go/backend/internal/filestation/write_test.go +123 -0
- package/templates/native-go/backend/internal/helper/background_proof.go +163 -0
- package/templates/native-go/backend/internal/helper/background_proof_contract.go +46 -0
- package/templates/native-go/backend/internal/helper/background_proof_test.go +161 -0
- package/templates/native-go/backend/internal/helper/data_contract.go +3 -0
- package/templates/native-go/backend/internal/helper/data_protocol.go +3 -0
- package/templates/native-go/backend/internal/helper/data_protocol_test.go +1 -1
- package/templates/native-go/backend/internal/helper/grant_authority.go +3 -0
- package/templates/native-go/backend/internal/helper/grant_authority_test.go +1 -1
- package/templates/native-go/backend/internal/helper/grant_repository_linux.go +2 -1
- package/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +4 -3
- package/templates/native-go/backend/internal/helper/grant_snapshot.go +3 -0
- package/templates/native-go/backend/internal/helper/jobcontract/bindings.go +48 -0
- package/templates/native-go/backend/internal/helper/jobcontract/contract_test.go +436 -0
- package/templates/native-go/backend/internal/helper/jobcontract/decode.go +185 -0
- package/templates/native-go/backend/internal/helper/jobcontract/digest.go +55 -0
- package/templates/native-go/backend/internal/helper/jobcontract/registry.go +85 -0
- package/templates/native-go/backend/internal/helper/jobcontract/registry_test.go +73 -0
- package/templates/native-go/backend/internal/helper/jobcontract/result.go +53 -0
- package/templates/native-go/backend/internal/helper/jobcontract/stub.go +8 -0
- package/templates/native-go/backend/internal/helper/jobcontract/testdata/input-digests.json +127 -0
- package/templates/native-go/backend/internal/helper/jobcontract/types.go +234 -0
- package/templates/native-go/backend/internal/helper/jobcontract/types_test.go +29 -0
- package/templates/native-go/backend/internal/helper/jobcontract/validate.go +462 -0
- package/templates/native-go/backend/internal/helper/legacy_authority_schema_linux_test.go +34 -0
- package/templates/native-go/backend/internal/helper/legacy_authority_schema_test.go +6 -0
- package/templates/native-go/backend/internal/helper/management.go +86 -0
- package/templates/native-go/backend/internal/helper/observation.go +42 -2
- package/templates/native-go/backend/internal/helper/observation_health_test.go +13 -1
- package/templates/native-go/backend/internal/helper/observer_diagnostic.go +56 -10
- package/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +6 -0
- package/templates/native-go/backend/internal/helper/observer_diagnostic_writer.go +40 -0
- package/templates/native-go/backend/internal/helper/process_linux.go +3 -0
- package/templates/native-go/backend/internal/helper/purge.go +115 -0
- package/templates/native-go/backend/internal/helper/purge_test.go +59 -0
- package/templates/native-go/backend/internal/helper/query_deadline_linux_test.go +115 -0
- package/templates/native-go/backend/internal/helper/query_pending_diagnostic_test.go +254 -0
- package/templates/native-go/backend/internal/helper/relaxed_invalidation.go +3 -0
- package/templates/native-go/backend/internal/helper/revoke.go +109 -0
- package/templates/native-go/backend/internal/helper/revoke_test.go +121 -0
- package/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +23 -4
- package/templates/native-go/backend/internal/helper/sdk_assembly_linux.go +51 -0
- package/templates/native-go/backend/internal/helper/sdk_attach.go +83 -0
- package/templates/native-go/backend/internal/helper/sdk_attach_contract.go +32 -0
- package/templates/native-go/backend/internal/helper/sdk_attach_test.go +184 -0
- package/templates/native-go/backend/internal/helper/sdk_authority_schema_test.go +6 -0
- package/templates/native-go/backend/internal/helper/sdk_background_authority.go +832 -0
- package/templates/native-go/backend/internal/helper/sdk_background_authority_test.go +714 -0
- package/templates/native-go/backend/internal/helper/sdk_background_invalidation.go +218 -0
- package/templates/native-go/backend/internal/helper/sdk_background_lease.go +218 -0
- package/templates/native-go/backend/internal/helper/sdk_background_snapshot.go +110 -0
- package/templates/native-go/backend/internal/helper/sdk_background_store_linux_test.go +261 -0
- package/templates/native-go/backend/internal/helper/sdk_background_store_test.go +58 -0
- package/templates/native-go/backend/internal/helper/sdk_bindings.go +60 -0
- package/templates/native-go/backend/internal/helper/sdk_data_contract.go +251 -0
- package/templates/native-go/backend/internal/helper/sdk_data_protocol.go +424 -0
- package/templates/native-go/backend/internal/helper/sdk_dispatch_absence_test.go +51 -0
- package/templates/native-go/backend/internal/helper/sdk_display.go +488 -0
- package/templates/native-go/backend/internal/helper/sdk_display_contract.go +121 -0
- package/templates/native-go/backend/internal/helper/sdk_display_test.go +459 -0
- package/templates/native-go/backend/internal/helper/sdk_grant_authority.go +559 -0
- package/templates/native-go/backend/internal/helper/sdk_grant_repository_linux.go +417 -0
- package/templates/native-go/backend/internal/helper/sdk_grant_snapshot.go +94 -0
- package/templates/native-go/backend/internal/helper/sdk_history.go +80 -0
- package/templates/native-go/backend/internal/helper/sdk_history_test.go +76 -0
- package/templates/native-go/backend/internal/helper/sdk_job.go +697 -0
- package/templates/native-go/backend/internal/helper/sdk_job_child_linux.go +309 -0
- package/templates/native-go/backend/internal/helper/sdk_job_contract.go +122 -0
- package/templates/native-go/backend/internal/helper/sdk_job_linux_test.go +159 -0
- package/templates/native-go/backend/internal/helper/sdk_job_process_linux.go +327 -0
- package/templates/native-go/backend/internal/helper/sdk_job_test.go +501 -0
- package/templates/native-go/backend/internal/helper/sdk_job_vm_linux_test.go +343 -0
- package/templates/native-go/backend/internal/helper/sdk_journal.go +77 -0
- package/templates/native-go/backend/internal/helper/sdk_journal_linux.go +244 -0
- package/templates/native-go/backend/internal/helper/sdk_journal_linux_test.go +295 -0
- package/templates/native-go/backend/internal/helper/sdk_journal_test.go +71 -0
- package/templates/native-go/backend/internal/helper/sdk_picker_test.go +50 -0
- package/templates/native-go/backend/internal/helper/sdk_process_linux.go +184 -0
- package/templates/native-go/backend/internal/helper/sdk_public_vm_linux_test.go +129 -0
- package/templates/native-go/backend/internal/helper/sdk_relaxed_invalidation.go +242 -0
- package/templates/native-go/backend/internal/helper/sdk_rpc.go +299 -0
- package/templates/native-go/backend/internal/helper/sdk_rpc_contract.go +70 -0
- package/templates/native-go/backend/internal/helper/sdk_rpc_test.go +135 -0
- package/templates/native-go/backend/internal/helper/sdk_server_linux.go +161 -0
- package/templates/native-go/backend/internal/helper/sdk_session.go +677 -0
- package/templates/native-go/backend/internal/helper/sdk_session_contract.go +72 -0
- package/templates/native-go/backend/internal/helper/sdk_session_fence_test.go +215 -0
- package/templates/native-go/backend/internal/helper/sdk_session_test.go +475 -0
- package/templates/native-go/backend/internal/helper/sdk_supervisor_frame.go +78 -0
- package/templates/native-go/backend/internal/helper/sdk_supervisor_linux.go +414 -0
- package/templates/native-go/backend/internal/helper/sdk_transport.go +79 -0
- package/templates/native-go/backend/internal/helper/sdk_transport_linux.go +82 -0
- package/templates/native-go/backend/internal/helper/sdk_transport_test.go +64 -0
- package/templates/native-go/backend/internal/helper/server_linux.go +14 -2
- package/templates/native-go/backend/internal/helper/stale_management_linux_test.go +126 -0
- package/templates/native-go/backend/internal/helper/stale_management_test.go +122 -0
- package/templates/native-go/backend/internal/helper/startup_diagnostic.go +68 -0
- package/templates/native-go/backend/internal/helper/startup_diagnostic_linux_test.go +126 -0
- package/templates/native-go/backend/internal/helper/startup_diagnostic_test.go +117 -0
- package/templates/native-go/backend/internal/helper/status.go +22 -13
- package/templates/native-go/backend/internal/helper/status_test.go +45 -0
- package/templates/native-go/backend/internal/helper/supervision.go +1 -1
- package/templates/native-go/backend/internal/helper/supervisor_frame.go +3 -0
- package/templates/native-go/backend/internal/helper/supervisor_linux.go +6 -2
- package/templates/native-go/backend/internal/helper/unit_connection_test.go +22 -4
- package/templates/native-go/backend/internal/helper/unit_linux.go +7 -3
- package/templates/native-go/backend/internal/helper/unit_query_linux.go +5 -1
- package/templates/native-go/backend/internal/helper/write_files_linux.go +7 -4
- package/templates/native-go/backend/internal/helper/write_files_linux_test.go +26 -0
- package/templates/native-go/dsm-package.yaml +2 -2
- package/templates/native-go-authorization/backend/internal/app/authorization.go +298 -0
- package/templates/native-go-authorization/backend/internal/app/authorization_test.go +96 -0
- package/templates/native-go-authorization/frontend/src/authorization/AuthorizationGate.vue +89 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/de.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/en.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/es.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/fr.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/index.ts +15 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/it.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/ja.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/ko.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/zh-CN.json +36 -0
- package/templates/native-go-authorization/frontend/src/authorization/i18n/zh-TW.json +36 -0
- package/templates/native-go-authorization/frontend/test/authorization-preview.html +14 -0
- package/templates/native-go-authorization/frontend/test/authorization.test.ts +59 -0
- package/templates/native-go-background/BACKGROUND.md +111 -0
- package/templates/native-go-background/backend/internal/app/background_on.go +7 -0
- package/templates/native-go-background/backend/internal/app/background_routes_test.go +32 -0
- package/templates/native-go-background/frontend/src/background/BackgroundPanel.vue +178 -0
- package/templates/native-go-background/frontend/src/background/i18n/de.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/en.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/es.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/fr.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/it.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/ja.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/ko.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/zh-CN.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n/zh-TW.json +83 -0
- package/templates/native-go-background/frontend/src/background/i18n.ts +19 -0
- package/templates/native-go-background/frontend/src/background/picker-provider.ts +13 -0
- package/templates/native-go-background/frontend/test/background.test.ts +179 -0
- package/templates/native-go-integration/backend/internal/app/personal.go +2 -2
- package/templates/native-go-integration/backend/internal/app/personal_test.go +37 -0
- package/templates/native-go-vue/README.md +38 -7
- package/templates/native-go-vue/frontend/DESIGN.md +15 -3
- package/templates/native-go-vue/frontend/README-JOBS.md +75 -0
- package/templates/native-go-vue/frontend/README-M2.md +64 -0
- package/templates/native-go-vue/frontend/package-lock.json +5 -4
- package/templates/native-go-vue/frontend/package.json +1 -1
- package/templates/native-go-vue/frontend/src/App.vue +39 -11
- package/templates/native-go-vue/frontend/src/M2App.vue +57 -0
- package/templates/native-go-vue/frontend/src/SDKApp.vue +203 -0
- package/templates/native-go-vue/frontend/src/context.ts +3 -0
- package/templates/native-go-vue/frontend/src/jobs/InteractiveJobForm.vue +70 -0
- package/templates/native-go-vue/frontend/src/jobs/JobsAdminPanel.vue +33 -0
- package/templates/native-go-vue/frontend/src/jobs/JobsPanel.vue +135 -0
- package/templates/native-go-vue/frontend/src/jobs/connected-provider.ts +179 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/de.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/en.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/es.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/fr.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/it.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/ja.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/ko.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/zh-CN.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n/zh-TW.json +62 -0
- package/templates/native-go-vue/frontend/src/jobs/i18n.ts +15 -0
- package/templates/native-go-vue/frontend/src/jobs/mock-provider.ts +67 -0
- package/templates/native-go-vue/frontend/src/jobs/provider.ts +60 -0
- package/templates/native-go-vue/frontend/src/jobs/validate.ts +44 -0
- package/templates/native-go-vue/frontend/src/m2-main.ts +21 -0
- package/templates/native-go-vue/frontend/src/m2-style.css +7 -0
- package/templates/native-go-vue/frontend/src/nas/M2Files.vue +94 -0
- package/templates/native-go-vue/frontend/src/nas/M2PathPicker.vue +70 -0
- package/templates/native-go-vue/frontend/src/nas/M2Settings.vue +69 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/de.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/en.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/es.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/fr.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/it.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/ja.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/ko.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-CN.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/m2/zh-TW.json +56 -0
- package/templates/native-go-vue/frontend/src/nas/m2-contract.ts +33 -0
- package/templates/native-go-vue/frontend/src/nas/m2-i18n.ts +24 -0
- package/templates/native-go-vue/frontend/src/nas/m2-provider.ts +104 -0
- package/templates/native-go-vue/frontend/src/nas/use-m2-request.ts +18 -0
- package/templates/native-go-vue/frontend/src/sdk-main.ts +39 -0
- package/templates/native-go-vue/frontend/src/shell/AppShell.vue +48 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/de.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/en.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/es.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/it.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/ko.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/zh-CN.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/zh-TW.json +10 -0
- package/templates/native-go-vue/frontend/src/shell/i18n.ts +17 -0
- package/templates/native-go-vue/frontend/src/shell/pages.ts +34 -0
- package/templates/native-go-vue/frontend/src/style.css +2 -6
- package/templates/native-go-vue/frontend/test/apps.test.ts +21 -0
- package/templates/native-go-vue/frontend/test/jobs-connected.test.ts +163 -0
- package/templates/native-go-vue/frontend/test/jobs-preview.html +22 -0
- package/templates/native-go-vue/frontend/test/jobs.test.ts +176 -0
- package/templates/native-go-vue/frontend/test/m2-preview.html +27 -0
- package/templates/native-go-vue/frontend/test/m2-provider.test.ts +87 -0
- package/templates/native-go-vue/frontend/test/m2-ui.test.ts +209 -0
- package/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
- package/templates/native-go-vue/frontend/test/picker-wire.test.ts +110 -0
- package/templates/native-go-vue/frontend/test/shell-preview.html +19 -0
- package/templates/native-go-vue/frontend/test/shell-sdk.test.ts +73 -0
- package/templates/native-go-vue/frontend/test/shell-ui.test.ts +114 -0
- package/templates/native-go-vue/frontend/test/shell.test.ts +45 -0
- package/templates/native-go-vue/frontend/vite.config.ts +2 -2
- package/dist/templates/hello-web/compose.yaml +0 -21
- package/dist/templates/hello-web/html/app.js +0 -1
- package/dist/templates/hello-web/html/index.html +0 -13
- package/dist/templates/hello-web/synology-app.yaml +0 -13
- package/dist/templates/hello-web-page/compose.yaml +0 -21
- package/dist/templates/hello-web-page/html/app.js +0 -1
- package/dist/templates/hello-web-page/html/index.html +0 -13
- package/dist/templates/hello-web-page/synology-app.yaml +0 -13
- package/templates/hello-web/compose.yaml +0 -21
- package/templates/hello-web/html/app.js +0 -1
- package/templates/hello-web/html/index.html +0 -13
- package/templates/hello-web/synology-app.yaml +0 -13
- package/templates/hello-web-page/compose.yaml +0 -21
- package/templates/hello-web-page/html/app.js +0 -1
- package/templates/hello-web-page/html/index.html +0 -13
- package/templates/hello-web-page/synology-app.yaml +0 -13
|
@@ -5,6 +5,8 @@ export interface RootTask {
|
|
|
5
5
|
name: string;
|
|
6
6
|
header: string;
|
|
7
7
|
script: string;
|
|
8
|
+
/** Whether the package backend serves `root.output` for this op; helper ops report through the helper instead. */
|
|
9
|
+
output: boolean;
|
|
8
10
|
}
|
|
9
11
|
export declare function rootTasks(manifest: {
|
|
10
12
|
package: string;
|
|
@@ -26,7 +28,7 @@ export declare function rootTasks(manifest: {
|
|
|
26
28
|
* again replaces it. A same-named task that is not ours is a "conflict" and
|
|
27
29
|
* is never run, replaced or deleted.
|
|
28
30
|
*/
|
|
29
|
-
export declare const ROOT_RUNTIME = "function createRootAccess(options) {\n var API = \"SYNO.Core.TaskScheduler\";\n var POLL_MS = 500, POLLS = 60;\n var byOp = {};\n options.tasks.forEach(function (task) { byOp[task.op] = task; });\n\n function fail(code) {\n var error = new Error(code);\n error.code = code;\n return error;\n }\n function begin(op) {\n if (!Object.prototype.hasOwnProperty.call(byOp, op)) return Promise.reject(fail(\"root_unknown_op\"));\n if (options.user().admin !== true) return Promise.reject(fail(\"admin_required\"));\n return Promise.resolve(byOp[op]);\n }\n function isRootTask(summary) {\n return summary.owner === \"root\" && summary.real_owner === \"root\" && summary.enable === false && summary.type === \"script\";\n }\n function find(task) {\n return options.send(API, \"list\", 3, { start: 0, limit: 500 }).then(function (data) {\n if (!data || !Array.isArray(data.tasks)) throw fail(\"root_bad_response\");\n var named = data.tasks.filter(function (summary) { return summary && summary.name === task.name; });\n if (named.length === 0) return { state: \"missing\" };\n if (named.length > 1 || !isRootTask(named[0])) return { state: \"conflict\" };\n var ref = { id: named[0].id, real_owner: named[0].real_owner };\n return options.send(API, \"get\", 4, ref).then(function (detail) {\n var script = detail && detail.extra && detail.extra.script;\n if (!detail || String(detail.id) !== String(ref.id) || detail.name !== task.name\n || detail.owner !== \"root\" || detail.enable !== false || detail.type !== \"script\" || typeof script !== \"string\") {\n return { state: \"conflict\" };\n }\n if (script === task.script) return { state: \"ready\", ref: ref };\n if (script.indexOf(task.header) === 0) return { state: \"outdated\", ref: ref };\n return { state: \"conflict\" };\n });\n });\n }\n function definition(task, user) {\n var hours = [];\n for (var h = 1; h <= 23; h++) hours.push(h);\n return {\n name: task.name,\n real_owner: user,\n owner: \"root\",\n enable: false,\n type: \"script\",\n schedule: {\n date_type: 0, week_day: \"0,1,2,3,4,5,6\", repeat_date: 1001, monthly_week: [], hour: 0, minute: 0,\n repeat_hour: 0, repeat_min: 0, last_work_hour: 0,\n repeat_min_store_config: [1, 5, 10, 15, 20, 30], repeat_hour_store_config: hours\n },\n extra: { notify_enable: false, script: task.script, notify_mail: \"\", notify_if_error: false }\n };\n }\n function newest(history) {\n if (!Array.isArray(history)) throw fail(\"root_bad_response\");\n return history.reduce(function (latest, entry) {\n return entry && (!latest || Number(entry.timestamp) > Number(latest.timestamp)) ? entry : latest;\n }, null);\n }\n function history(ref) {\n return options.send(API, \"get_history_status_list\", 1, { id: ref.id }).then(newest);\n }\n function waitForRun(ref, before, polls) {\n return history(ref).then(function (latest) {\n var finished = latest && (!before || latest.timestamp !== before.timestamp)\n && latest.exit_type !== \"running\" && latest.stop_time;\n if (finished) {\n if (latest.exit_code !== 0) throw fail(\"root_task_failed\");\n return;\n }\n if (polls <= 1) throw fail(\"root_timeout\");\n return options.wait(POLL_MS).then(function () { return waitForRun(ref, before, polls - 1); });\n });\n }\n\n return {\n state: function (op) {\n return begin(op).then(find).then(function (found) { return found.state; });\n },\n authorize: function (op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state === \"ready\") return \"ready\";\n if (found.state === \"conflict\") throw fail(\"root_conflict\");\n return options.confirmPassword().then(function (token) {\n if (!token) return \"cancelled\";\n var params = definition(task, options.user().name);\n params.SynoConfirmPWToken = token;\n var replaced = found.state === \"outdated\"\n ? options.send(API, \"delete\", 2, { tasks: [found.ref] })\n : Promise.resolve();\n return replaced.then(function () {\n return options.send(API + \".Root\", \"create\", 4, params);\n }).then(function () {\n return find(task);\n }).then(function (after) {\n if (after.state !== \"ready\") throw fail(\"root_verify_failed\");\n return \"ready\";\n });\n });\n });\n });\n },\n run: function (op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state !== \"ready\") throw fail(\"root_not_ready\");\n // Repair requires fresh interactive consent even for a retained task.\n // Confirmation tokens are never cached or reused as scheduler tokens.\n var consent = op === \"helper_repair\" ? options.confirmPassword() : Promise.resolve(true);\n return consent.then(function (token) {\n if (!token) throw fail(\"root_cancelled\");\n // The user may leave the dialog open while the scheduler changes.\n return op === \"helper_repair\" ? begin(op).then(find) : found;\n }).then(function (verified) {\n if (verified.state !== \"ready\") throw fail(\"root_not_ready\");\n return history(verified.ref).then(function (before) {\n return options.send(API, \"run\", 2, { tasks: [verified.ref] }).then(function () {\n return waitForRun(verified.ref, before, POLLS);\n });\n });\n });\n }).then(function () {\n return options.call(\"root.output\", { op: op });\n });\n });\n },\n remove: function (op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state === \"missing\") return \"missing\";\n if (found.state === \"conflict\") throw fail(\"root_conflict\");\n return options.send(API, \"delete\", 2, { tasks: [found.ref] }).then(function () {\n return find(task);\n }).then(function (after) {\n if (after.state !== \"missing\") throw fail(\"root_verify_failed\");\n return \"missing\";\n });\n });\n });\n },\n output: function (op) {\n return begin(op).then(function () {\n return options.call(\"root.output\", { op: op });\n });\n }\n };\n}";
|
|
31
|
+
export declare const ROOT_RUNTIME = "function createRootAccess(options) {\n var API = \"SYNO.Core.TaskScheduler\";\n var POLL_MS = 500, POLLS = 60;\n var byOp = {}, running = {};\n var legacy = null, probe = null;\n options.tasks.forEach(function (task) { byOp[task.op] = task; });\n\n function fail(code) {\n var error = new Error(code);\n error.code = code;\n return error;\n }\n function begin(op) {\n if (!Object.prototype.hasOwnProperty.call(byOp, op)) return Promise.reject(fail(\"root_unknown_op\"));\n if (options.user().admin !== true) return Promise.reject(fail(\"admin_required\"));\n return Promise.resolve(byOp[op]);\n }\n function readOutput(task) {\n return task.output ? options.call(\"root.output\", { op: task.op }) : Promise.resolve(null);\n }\n function isRootTask(summary) {\n return summary.owner === \"root\" && summary.real_owner === \"root\" && summary.enable === false && summary.type === \"script\";\n }\n function listTasks() {\n if (legacy === false) return options.send(API, \"list\", 3, { start: 0, limit: 500 });\n if (legacy === true) return legacyList();\n if (!probe) {\n probe = options.send(API, \"list\", 3, { start: 0, limit: 500 }).then(function (data) {\n legacy = false;\n return data;\n }, function (error) {\n if (!error || (error.code !== \"dsm_103\" && error.code !== 103)) {\n probe = null;\n throw error;\n }\n legacy = true;\n return legacyList();\n });\n }\n return probe;\n }\n function legacyList() {\n return options.send(API, \"list\", 2, { offset: 0, limit: 500 }).then(function (data) {\n // Refuse a truncated snapshot: a same-named task could lie outside it.\n if (!data || !Array.isArray(data.tasks) || data.tasks.length > 500\n || !(typeof data.total === \"number\" && isFinite(data.total) && Math.floor(data.total) === data.total) || data.total !== data.tasks.length) throw fail(\"root_bad_response\");\n return data;\n });\n }\n function readTask(ref) {\n return options.send(API, \"get\", legacy ? 3 : 4, ref);\n }\n function createTask(params) {\n return options.send(legacy ? API : API + \".Root\", \"create\", legacy ? 3 : 4, params);\n }\n function deleteTask(ref) {\n return options.send(API, \"delete\", 2, { tasks: [ref] });\n }\n function runTask(ref) {\n return options.send(API, \"run\", 2, { tasks: [ref] });\n }\n function find(task) {\n return listTasks().then(function (data) {\n if (!data || !Array.isArray(data.tasks)) throw fail(\"root_bad_response\");\n var named = data.tasks.filter(function (summary) { return summary && summary.name === task.name; });\n if (named.length === 0) return { state: \"missing\" };\n if (named.length > 1 || !isRootTask(named[0])) return { state: \"conflict\" };\n var ref = { id: named[0].id, real_owner: named[0].real_owner };\n return readTask(ref).then(function (detail) {\n var script = detail && detail.extra && detail.extra.script;\n if (!detail || String(detail.id) !== String(ref.id) || detail.name !== task.name\n || detail.owner !== \"root\" || detail.real_owner !== ref.real_owner || detail.enable !== false || detail.type !== \"script\" || typeof script !== \"string\") {\n return { state: \"conflict\" };\n }\n if (script === task.script) return { state: \"ready\", ref: ref };\n if (script.indexOf(task.header) === 0) return { state: \"outdated\", ref: ref };\n return { state: \"conflict\" };\n });\n });\n }\n function definition(task, user) {\n var hours = [];\n for (var h = 1; h <= 23; h++) hours.push(h);\n return {\n name: task.name,\n real_owner: user,\n owner: \"root\",\n enable: false,\n type: \"script\",\n schedule: {\n date_type: 0, week_day: \"0,1,2,3,4,5,6\", repeat_date: 1001, monthly_week: [], hour: 0, minute: 0,\n repeat_hour: 0, repeat_min: 0, last_work_hour: 0,\n repeat_min_store_config: [1, 5, 10, 15, 20, 30], repeat_hour_store_config: hours\n },\n extra: { notify_enable: false, script: task.script, notify_mail: \"\", notify_if_error: false }\n };\n }\n function newest(history) {\n if (!Array.isArray(history)) throw fail(\"root_bad_response\");\n return history.reduce(function (latest, entry) {\n return entry && (!latest || Number(entry.timestamp) > Number(latest.timestamp)) ? entry : latest;\n }, null);\n }\n function history(ref) {\n return options.send(API, \"get_history_status_list\", 1, { id: ref.id }).then(newest);\n }\n function waitForRun(ref, before, polls) {\n return history(ref).then(function (latest) {\n var finished = latest && (!before || latest.timestamp !== before.timestamp)\n && latest.exit_type !== \"running\" && latest.stop_time;\n if (finished) {\n if (latest.exit_code !== 0) throw fail(\"root_task_failed\");\n return;\n }\n if (polls <= 1) throw fail(\"root_timeout\");\n return options.wait(POLL_MS).then(function () { return waitForRun(ref, before, polls - 1); });\n });\n }\n\n function validTime(value) {\n if (typeof value !== \"string\" || !/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(value)) return false;\n var normalized = value.replace(\" \", \"T\") + \"Z\";\n var date = new Date(normalized);\n return !isNaN(date.getTime()) && date.toISOString().slice(0, 19) === normalized.slice(0, 19);\n }\n function bounded(call, deadline) {\n // A poll count alone cannot bound a stalled DSM callback. Discard late replies.\n return new Promise(function (resolve, reject) {\n var remaining = deadline - Date.now();\n if (remaining <= 0) { reject(fail(\"root_timeout\")); return; }\n var timer = setTimeout(function () { reject(fail(\"root_timeout\")); }, remaining);\n Promise.resolve().then(call).then(function (value) {\n clearTimeout(timer);\n if (Date.now() >= deadline) reject(fail(\"root_timeout\"));\n else resolve(value);\n }, function (error) { clearTimeout(timer); reject(error); });\n });\n }\n function legacyHistory(ref, deadline) {\n return bounded(function () { return options.send(API, \"view\", 1, { id: ref.id }); }, deadline).then(function (records) {\n // DSM 7.1 omits data entirely when a task has never run.\n if (records === undefined) records = [];\n if (!Array.isArray(records) || records.length > 500) throw fail(\"root_bad_response\");\n var seen = {};\n records.forEach(function (record) {\n if (!record || !validTime(record.start_time) || typeof record.stop_time !== \"string\"\n || (record.stop_time && (!validTime(record.stop_time) || record.stop_time < record.start_time))\n || typeof record.exit_type !== \"string\" || !(typeof record.exit_code === \"number\" && isFinite(record.exit_code) && Math.floor(record.exit_code) === record.exit_code)\n || seen[record.start_time]) throw fail(\"root_bad_response\");\n seen[record.start_time] = true;\n });\n return records;\n });\n }\n function waitForLegacyRun(ref, before, deadline, polls) {\n return legacyHistory(ref, deadline).then(function (records) {\n var previous = before.map(function (record) { return record.start_time; });\n var newestBefore = previous.slice().sort().pop();\n var fresh = records.filter(function (record) { return previous.indexOf(record.start_time) === -1; });\n if (fresh.length > 1) throw fail(\"root_bad_response\");\n var latest = fresh[0];\n if (latest && (!newestBefore || latest.start_time > newestBefore) && latest.stop_time) {\n if (latest.exit_code !== 0 || latest.exit_type !== \"normal\") throw fail(\"root_task_failed\");\n return;\n }\n if (polls <= 1 || Date.now() >= deadline) throw fail(\"root_timeout\");\n return options.wait(Math.min(POLL_MS, deadline - Date.now())).then(function () {\n return waitForLegacyRun(ref, before, deadline, polls - 1);\n });\n });\n }\n function execute(task, verified) {\n if (!legacy) {\n return history(verified.ref).then(function (before) {\n return runTask(verified.ref).then(function () { return waitForRun(verified.ref, before, POLLS); });\n });\n }\n var deadline = Date.now() + POLL_MS * POLLS;\n return legacyHistory(verified.ref, deadline).then(function (before) {\n if (before.some(function (record) { return !record.stop_time || record.exit_type === \"running\"; })) throw fail(\"root_not_ready\");\n // Mutating calls are sent exactly once, never retried with another profile.\n return bounded(function () { return runTask(verified.ref); }, deadline).then(function () {\n return waitForLegacyRun(verified.ref, before, deadline, POLLS);\n });\n }).then(function () {\n return bounded(function () { return find(task); }, deadline).then(function (after) {\n if (after.state !== \"ready\" || String(after.ref.id) !== String(verified.ref.id)) throw fail(\"root_verify_failed\");\n });\n });\n }\n function performRun(op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state !== \"ready\") throw fail(\"root_not_ready\");\n var consent = op === \"helper_repair\" ? options.confirmPassword() : Promise.resolve({ confirmed: true });\n return consent.then(function (confirmation) {\n if (!confirmation || confirmation.confirmed !== true) throw fail(\"root_cancelled\");\n return op === \"helper_repair\" ? begin(op).then(find) : found;\n }).then(function (verified) {\n if (verified.state !== \"ready\") throw fail(\"root_not_ready\");\n return execute(task, verified);\n });\n }).then(function () { return readOutput(task); });\n });\n }\n\n return {\n state: function (op) {\n return begin(op).then(find).then(function (found) { return found.state; });\n },\n authorize: function (op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state === \"ready\") return \"ready\";\n if (found.state === \"conflict\") throw fail(\"root_conflict\");\n return options.confirmPassword().then(function (confirmation) {\n if (!confirmation || confirmation.confirmed !== true) return \"cancelled\";\n if (!legacy && (typeof confirmation.token !== \"string\" || !confirmation.token)) throw fail(\"root_verify_failed\");\n var params = definition(task, options.user().name);\n if (!legacy) params.SynoConfirmPWToken = confirmation.token;\n // Re-read after the legacy client-side dialog before replacing a task.\n var checked = legacy ? begin(op).then(find) : Promise.resolve(found);\n return checked.then(function (current) {\n if (current.state === \"conflict\") throw fail(\"root_conflict\");\n if (current.state === \"ready\") return;\n var replaced = current.state === \"outdated\" ? deleteTask(current.ref) : Promise.resolve();\n return replaced.then(function () { return createTask(params); });\n }).then(function () {\n return find(task);\n }).then(function (after) {\n if (after.state !== \"ready\") throw fail(\"root_verify_failed\");\n return \"ready\";\n });\n });\n });\n });\n },\n run: function (op) {\n if (!Object.prototype.hasOwnProperty.call(byOp, op)) return Promise.reject(fail(\"root_unknown_op\"));\n if (options.user().admin !== true) return Promise.reject(fail(\"admin_required\"));\n if (running[op]) return running[op];\n var pending = performRun(op).then(function (value) {\n delete running[op];\n return value;\n }, function (error) { delete running[op]; throw error; });\n running[op] = pending;\n return pending;\n },\n remove: function (op) {\n return begin(op).then(function (task) {\n return find(task).then(function (found) {\n if (found.state === \"missing\") return \"missing\";\n if (found.state === \"conflict\") throw fail(\"root_conflict\");\n return deleteTask(found.ref).then(function () {\n return find(task);\n }).then(function (after) {\n if (after.state !== \"missing\") throw fail(\"root_verify_failed\");\n return \"missing\";\n });\n });\n });\n },\n output: function (op) {\n return begin(op).then(readOutput);\n }\n };\n}";
|
|
30
32
|
/**
|
|
31
33
|
* The authorization panel the window shows above the app for each root
|
|
32
34
|
* operation, identical in every package. `rootPanelView(model)` decides what
|
|
@@ -5,6 +5,7 @@ export function rootTasks(manifest) {
|
|
|
5
5
|
name: rootTaskName(manifest.package, op.name),
|
|
6
6
|
header: rootTaskHeader(manifest.package, op.name),
|
|
7
7
|
script: renderRootTaskScript(manifest, op),
|
|
8
|
+
output: op.exposeOutput ?? op.protectedOutput !== true,
|
|
8
9
|
}));
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
@@ -25,7 +26,8 @@ export function rootTasks(manifest) {
|
|
|
25
26
|
export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
26
27
|
var API = "SYNO.Core.TaskScheduler";
|
|
27
28
|
var POLL_MS = 500, POLLS = 60;
|
|
28
|
-
var byOp = {};
|
|
29
|
+
var byOp = {}, running = {};
|
|
30
|
+
var legacy = null, probe = null;
|
|
29
31
|
options.tasks.forEach(function (task) { byOp[task.op] = task; });
|
|
30
32
|
|
|
31
33
|
function fail(code) {
|
|
@@ -38,20 +40,61 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
38
40
|
if (options.user().admin !== true) return Promise.reject(fail("admin_required"));
|
|
39
41
|
return Promise.resolve(byOp[op]);
|
|
40
42
|
}
|
|
43
|
+
function readOutput(task) {
|
|
44
|
+
return task.output ? options.call("root.output", { op: task.op }) : Promise.resolve(null);
|
|
45
|
+
}
|
|
41
46
|
function isRootTask(summary) {
|
|
42
47
|
return summary.owner === "root" && summary.real_owner === "root" && summary.enable === false && summary.type === "script";
|
|
43
48
|
}
|
|
49
|
+
function listTasks() {
|
|
50
|
+
if (legacy === false) return options.send(API, "list", 3, { start: 0, limit: 500 });
|
|
51
|
+
if (legacy === true) return legacyList();
|
|
52
|
+
if (!probe) {
|
|
53
|
+
probe = options.send(API, "list", 3, { start: 0, limit: 500 }).then(function (data) {
|
|
54
|
+
legacy = false;
|
|
55
|
+
return data;
|
|
56
|
+
}, function (error) {
|
|
57
|
+
if (!error || (error.code !== "dsm_103" && error.code !== 103)) {
|
|
58
|
+
probe = null;
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
legacy = true;
|
|
62
|
+
return legacyList();
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return probe;
|
|
66
|
+
}
|
|
67
|
+
function legacyList() {
|
|
68
|
+
return options.send(API, "list", 2, { offset: 0, limit: 500 }).then(function (data) {
|
|
69
|
+
// Refuse a truncated snapshot: a same-named task could lie outside it.
|
|
70
|
+
if (!data || !Array.isArray(data.tasks) || data.tasks.length > 500
|
|
71
|
+
|| !(typeof data.total === "number" && isFinite(data.total) && Math.floor(data.total) === data.total) || data.total !== data.tasks.length) throw fail("root_bad_response");
|
|
72
|
+
return data;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function readTask(ref) {
|
|
76
|
+
return options.send(API, "get", legacy ? 3 : 4, ref);
|
|
77
|
+
}
|
|
78
|
+
function createTask(params) {
|
|
79
|
+
return options.send(legacy ? API : API + ".Root", "create", legacy ? 3 : 4, params);
|
|
80
|
+
}
|
|
81
|
+
function deleteTask(ref) {
|
|
82
|
+
return options.send(API, "delete", 2, { tasks: [ref] });
|
|
83
|
+
}
|
|
84
|
+
function runTask(ref) {
|
|
85
|
+
return options.send(API, "run", 2, { tasks: [ref] });
|
|
86
|
+
}
|
|
44
87
|
function find(task) {
|
|
45
|
-
return
|
|
88
|
+
return listTasks().then(function (data) {
|
|
46
89
|
if (!data || !Array.isArray(data.tasks)) throw fail("root_bad_response");
|
|
47
90
|
var named = data.tasks.filter(function (summary) { return summary && summary.name === task.name; });
|
|
48
91
|
if (named.length === 0) return { state: "missing" };
|
|
49
92
|
if (named.length > 1 || !isRootTask(named[0])) return { state: "conflict" };
|
|
50
93
|
var ref = { id: named[0].id, real_owner: named[0].real_owner };
|
|
51
|
-
return
|
|
94
|
+
return readTask(ref).then(function (detail) {
|
|
52
95
|
var script = detail && detail.extra && detail.extra.script;
|
|
53
96
|
if (!detail || String(detail.id) !== String(ref.id) || detail.name !== task.name
|
|
54
|
-
|| detail.owner !== "root" || detail.enable !== false || detail.type !== "script" || typeof script !== "string") {
|
|
97
|
+
|| detail.owner !== "root" || detail.real_owner !== ref.real_owner || detail.enable !== false || detail.type !== "script" || typeof script !== "string") {
|
|
55
98
|
return { state: "conflict" };
|
|
56
99
|
}
|
|
57
100
|
if (script === task.script) return { state: "ready", ref: ref };
|
|
@@ -99,6 +142,93 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
99
142
|
});
|
|
100
143
|
}
|
|
101
144
|
|
|
145
|
+
function validTime(value) {
|
|
146
|
+
if (typeof value !== "string" || !/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(value)) return false;
|
|
147
|
+
var normalized = value.replace(" ", "T") + "Z";
|
|
148
|
+
var date = new Date(normalized);
|
|
149
|
+
return !isNaN(date.getTime()) && date.toISOString().slice(0, 19) === normalized.slice(0, 19);
|
|
150
|
+
}
|
|
151
|
+
function bounded(call, deadline) {
|
|
152
|
+
// A poll count alone cannot bound a stalled DSM callback. Discard late replies.
|
|
153
|
+
return new Promise(function (resolve, reject) {
|
|
154
|
+
var remaining = deadline - Date.now();
|
|
155
|
+
if (remaining <= 0) { reject(fail("root_timeout")); return; }
|
|
156
|
+
var timer = setTimeout(function () { reject(fail("root_timeout")); }, remaining);
|
|
157
|
+
Promise.resolve().then(call).then(function (value) {
|
|
158
|
+
clearTimeout(timer);
|
|
159
|
+
if (Date.now() >= deadline) reject(fail("root_timeout"));
|
|
160
|
+
else resolve(value);
|
|
161
|
+
}, function (error) { clearTimeout(timer); reject(error); });
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function legacyHistory(ref, deadline) {
|
|
165
|
+
return bounded(function () { return options.send(API, "view", 1, { id: ref.id }); }, deadline).then(function (records) {
|
|
166
|
+
// DSM 7.1 omits data entirely when a task has never run.
|
|
167
|
+
if (records === undefined) records = [];
|
|
168
|
+
if (!Array.isArray(records) || records.length > 500) throw fail("root_bad_response");
|
|
169
|
+
var seen = {};
|
|
170
|
+
records.forEach(function (record) {
|
|
171
|
+
if (!record || !validTime(record.start_time) || typeof record.stop_time !== "string"
|
|
172
|
+
|| (record.stop_time && (!validTime(record.stop_time) || record.stop_time < record.start_time))
|
|
173
|
+
|| typeof record.exit_type !== "string" || !(typeof record.exit_code === "number" && isFinite(record.exit_code) && Math.floor(record.exit_code) === record.exit_code)
|
|
174
|
+
|| seen[record.start_time]) throw fail("root_bad_response");
|
|
175
|
+
seen[record.start_time] = true;
|
|
176
|
+
});
|
|
177
|
+
return records;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function waitForLegacyRun(ref, before, deadline, polls) {
|
|
181
|
+
return legacyHistory(ref, deadline).then(function (records) {
|
|
182
|
+
var previous = before.map(function (record) { return record.start_time; });
|
|
183
|
+
var newestBefore = previous.slice().sort().pop();
|
|
184
|
+
var fresh = records.filter(function (record) { return previous.indexOf(record.start_time) === -1; });
|
|
185
|
+
if (fresh.length > 1) throw fail("root_bad_response");
|
|
186
|
+
var latest = fresh[0];
|
|
187
|
+
if (latest && (!newestBefore || latest.start_time > newestBefore) && latest.stop_time) {
|
|
188
|
+
if (latest.exit_code !== 0 || latest.exit_type !== "normal") throw fail("root_task_failed");
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (polls <= 1 || Date.now() >= deadline) throw fail("root_timeout");
|
|
192
|
+
return options.wait(Math.min(POLL_MS, deadline - Date.now())).then(function () {
|
|
193
|
+
return waitForLegacyRun(ref, before, deadline, polls - 1);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function execute(task, verified) {
|
|
198
|
+
if (!legacy) {
|
|
199
|
+
return history(verified.ref).then(function (before) {
|
|
200
|
+
return runTask(verified.ref).then(function () { return waitForRun(verified.ref, before, POLLS); });
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
var deadline = Date.now() + POLL_MS * POLLS;
|
|
204
|
+
return legacyHistory(verified.ref, deadline).then(function (before) {
|
|
205
|
+
if (before.some(function (record) { return !record.stop_time || record.exit_type === "running"; })) throw fail("root_not_ready");
|
|
206
|
+
// Mutating calls are sent exactly once, never retried with another profile.
|
|
207
|
+
return bounded(function () { return runTask(verified.ref); }, deadline).then(function () {
|
|
208
|
+
return waitForLegacyRun(verified.ref, before, deadline, POLLS);
|
|
209
|
+
});
|
|
210
|
+
}).then(function () {
|
|
211
|
+
return bounded(function () { return find(task); }, deadline).then(function (after) {
|
|
212
|
+
if (after.state !== "ready" || String(after.ref.id) !== String(verified.ref.id)) throw fail("root_verify_failed");
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function performRun(op) {
|
|
217
|
+
return begin(op).then(function (task) {
|
|
218
|
+
return find(task).then(function (found) {
|
|
219
|
+
if (found.state !== "ready") throw fail("root_not_ready");
|
|
220
|
+
var consent = op === "helper_repair" ? options.confirmPassword() : Promise.resolve({ confirmed: true });
|
|
221
|
+
return consent.then(function (confirmation) {
|
|
222
|
+
if (!confirmation || confirmation.confirmed !== true) throw fail("root_cancelled");
|
|
223
|
+
return op === "helper_repair" ? begin(op).then(find) : found;
|
|
224
|
+
}).then(function (verified) {
|
|
225
|
+
if (verified.state !== "ready") throw fail("root_not_ready");
|
|
226
|
+
return execute(task, verified);
|
|
227
|
+
});
|
|
228
|
+
}).then(function () { return readOutput(task); });
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
102
232
|
return {
|
|
103
233
|
state: function (op) {
|
|
104
234
|
return begin(op).then(find).then(function (found) { return found.state; });
|
|
@@ -108,15 +238,18 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
108
238
|
return find(task).then(function (found) {
|
|
109
239
|
if (found.state === "ready") return "ready";
|
|
110
240
|
if (found.state === "conflict") throw fail("root_conflict");
|
|
111
|
-
return options.confirmPassword().then(function (
|
|
112
|
-
if (!
|
|
241
|
+
return options.confirmPassword().then(function (confirmation) {
|
|
242
|
+
if (!confirmation || confirmation.confirmed !== true) return "cancelled";
|
|
243
|
+
if (!legacy && (typeof confirmation.token !== "string" || !confirmation.token)) throw fail("root_verify_failed");
|
|
113
244
|
var params = definition(task, options.user().name);
|
|
114
|
-
params.SynoConfirmPWToken = token;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
245
|
+
if (!legacy) params.SynoConfirmPWToken = confirmation.token;
|
|
246
|
+
// Re-read after the legacy client-side dialog before replacing a task.
|
|
247
|
+
var checked = legacy ? begin(op).then(find) : Promise.resolve(found);
|
|
248
|
+
return checked.then(function (current) {
|
|
249
|
+
if (current.state === "conflict") throw fail("root_conflict");
|
|
250
|
+
if (current.state === "ready") return;
|
|
251
|
+
var replaced = current.state === "outdated" ? deleteTask(current.ref) : Promise.resolve();
|
|
252
|
+
return replaced.then(function () { return createTask(params); });
|
|
120
253
|
}).then(function () {
|
|
121
254
|
return find(task);
|
|
122
255
|
}).then(function (after) {
|
|
@@ -128,35 +261,22 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
128
261
|
});
|
|
129
262
|
},
|
|
130
263
|
run: function (op) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return op === "helper_repair" ? begin(op).then(find) : found;
|
|
141
|
-
}).then(function (verified) {
|
|
142
|
-
if (verified.state !== "ready") throw fail("root_not_ready");
|
|
143
|
-
return history(verified.ref).then(function (before) {
|
|
144
|
-
return options.send(API, "run", 2, { tasks: [verified.ref] }).then(function () {
|
|
145
|
-
return waitForRun(verified.ref, before, POLLS);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
}).then(function () {
|
|
150
|
-
return options.call("root.output", { op: op });
|
|
151
|
-
});
|
|
152
|
-
});
|
|
264
|
+
if (!Object.prototype.hasOwnProperty.call(byOp, op)) return Promise.reject(fail("root_unknown_op"));
|
|
265
|
+
if (options.user().admin !== true) return Promise.reject(fail("admin_required"));
|
|
266
|
+
if (running[op]) return running[op];
|
|
267
|
+
var pending = performRun(op).then(function (value) {
|
|
268
|
+
delete running[op];
|
|
269
|
+
return value;
|
|
270
|
+
}, function (error) { delete running[op]; throw error; });
|
|
271
|
+
running[op] = pending;
|
|
272
|
+
return pending;
|
|
153
273
|
},
|
|
154
274
|
remove: function (op) {
|
|
155
275
|
return begin(op).then(function (task) {
|
|
156
276
|
return find(task).then(function (found) {
|
|
157
277
|
if (found.state === "missing") return "missing";
|
|
158
278
|
if (found.state === "conflict") throw fail("root_conflict");
|
|
159
|
-
return
|
|
279
|
+
return deleteTask(found.ref).then(function () {
|
|
160
280
|
return find(task);
|
|
161
281
|
}).then(function (after) {
|
|
162
282
|
if (after.state !== "missing") throw fail("root_verify_failed");
|
|
@@ -166,9 +286,7 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
166
286
|
});
|
|
167
287
|
},
|
|
168
288
|
output: function (op) {
|
|
169
|
-
return begin(op).then(
|
|
170
|
-
return options.call("root.output", { op: op });
|
|
171
|
-
});
|
|
289
|
+
return begin(op).then(readOutput);
|
|
172
290
|
}
|
|
173
291
|
};
|
|
174
292
|
}`;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { StandaloneError } from "./manifest.js";
|
|
2
|
+
import { type Translate } from "../build-spk/wizard-i18n.js";
|
|
3
|
+
import type { InstallWizardStep } from "../build-spk/install-wizard.js";
|
|
4
|
+
/**
|
|
5
|
+
* `install.sharedFolder`: the Shared Folder a package keeps its files in.
|
|
6
|
+
*
|
|
7
|
+
* `select`: the install and upgrade wizard offer the NAS's existing Shared
|
|
8
|
+
* Folders. DSM cannot grant a package account access to a folder chosen at
|
|
9
|
+
* install time, so the administrator grants `permission` afterwards.
|
|
10
|
+
* `create`: DSM's official `data-share` resource creates the fixed `name` and
|
|
11
|
+
* gives the package account `permission`. Removing the package never deletes it.
|
|
12
|
+
*/
|
|
13
|
+
export interface SharedFolder {
|
|
14
|
+
mode: "select" | "create";
|
|
15
|
+
/** The wizard variable and the `var/config.json` entry for this folder. */
|
|
16
|
+
key: string;
|
|
17
|
+
/** `create` only: the Shared Folder `data-share` creates. */
|
|
18
|
+
name?: string;
|
|
19
|
+
permission: "ro" | "rw";
|
|
20
|
+
}
|
|
21
|
+
export declare function readSharedFolder(value: unknown, fail: (error: StandaloneError) => void): SharedFolder | undefined;
|
|
22
|
+
/** The first line `inspect` looks for to recover the declaration from an SPK. */
|
|
23
|
+
export declare const SHARED_FOLDER_MARKER = "# synopkgland:install.sharedFolder ";
|
|
24
|
+
/**
|
|
25
|
+
* `scripts/postinst` and `scripts/postupgrade`: store the Shared Folder *name*
|
|
26
|
+
* in `$SYNOPKG_PKGVAR/config.json`. The volume path is resolved at run time,
|
|
27
|
+
* so a moved folder keeps working. Runs as the package account.
|
|
28
|
+
*/
|
|
29
|
+
export declare function renderSharedFolderScript(pkg: string, folder: SharedFolder): string;
|
|
30
|
+
/** `install_uifile` and `upgrade_uifile`, English plus one file per DSM language. */
|
|
31
|
+
export declare function renderSharedFolderWizardFiles(pkg: string, folder: SharedFolder): Record<string, string>;
|
|
32
|
+
/** The install wizard steps that ask for the shared folder, for static or dynamic wizards. */
|
|
33
|
+
export declare function sharedFolderInstallSteps(pkg: string, folder: SharedFolder): (t: Translate) => InstallWizardStep[];
|
|
34
|
+
/** The upgrade wizard files that let the administrator keep or change the shared folder. */
|
|
35
|
+
export declare function renderSharedFolderUpgradeWizardFiles(pkg: string, folder: SharedFolder): Record<string, string>;
|
|
36
|
+
/** `conf/resource` `data-share` entry: create mode only; DSM never deletes the share on uninstall. */
|
|
37
|
+
export declare function sharedFolderResource(pkg: string, folder: SharedFolder): Record<string, unknown> | undefined;
|
|
38
|
+
/** The declaration an SPK's postinst carries, or undefined when it has none or it is no longer valid. */
|
|
39
|
+
export declare function recoverSharedFolder(postinst: string | undefined): SharedFolder | undefined;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { sharedFolderCombobox } from "../build-spk/share-combobox.js";
|
|
2
|
+
import { renderWizardFiles } from "../build-spk/wizard-i18n.js";
|
|
3
|
+
const FIELDS = new Set(["mode", "key", "name", "permission"]);
|
|
4
|
+
const KEY = /^[a-z][a-z0-9_]{0,31}$/;
|
|
5
|
+
const RESERVED_KEY = /^(pkgwizard_|synopkg|change_)/;
|
|
6
|
+
const SHARE_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;
|
|
7
|
+
const SYSTEM_SHARE = /^(homes?|users|ftp|root|admin|guest|system|volume\d*|(usb|sata|sd)share\d*)$/i;
|
|
8
|
+
function isRecord(value) {
|
|
9
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
export function readSharedFolder(value, fail) {
|
|
12
|
+
const refuse = (why) => {
|
|
13
|
+
fail({ code: "STANDALONE_SHARED_FOLDER_INVALID", message: `install.sharedFolder ${why}` });
|
|
14
|
+
return undefined;
|
|
15
|
+
};
|
|
16
|
+
if (!isRecord(value) || Object.keys(value).some((key) => key !== "sharedFolder")) {
|
|
17
|
+
return refuse(":install 只接受 sharedFolder。");
|
|
18
|
+
}
|
|
19
|
+
const folder = value.sharedFolder;
|
|
20
|
+
if (!isRecord(folder) || Object.keys(folder).some((key) => !FIELDS.has(key))) {
|
|
21
|
+
return refuse("只接受 mode、key、name 與 permission。");
|
|
22
|
+
}
|
|
23
|
+
const { mode, key, name, permission } = folder;
|
|
24
|
+
if (mode !== "select" && mode !== "create")
|
|
25
|
+
return refuse("的 mode 必須是 select 或 create。");
|
|
26
|
+
if (permission !== "ro" && permission !== "rw")
|
|
27
|
+
return refuse("的 permission 必須是 ro 或 rw。");
|
|
28
|
+
if (typeof key !== "string" || !KEY.test(key) || RESERVED_KEY.test(key)) {
|
|
29
|
+
return refuse("的 key 必須是小寫英文字母開頭、只含小寫英數與底線(最長 32 字),且不能以 pkgwizard_、synopkg、change_ 開頭。");
|
|
30
|
+
}
|
|
31
|
+
if (mode === "select") {
|
|
32
|
+
return name === undefined ? { mode, key, permission } : refuse("的 name 只用於 create;select 由安裝精靈選擇。");
|
|
33
|
+
}
|
|
34
|
+
if (typeof name !== "string" || !SHARE_NAME.test(name) || SYSTEM_SHARE.test(name)) {
|
|
35
|
+
return refuse("create 需要 name:英數字開頭、只含英數字、底線與連字號(最長 32 字),且不能是 DSM 系統共用資料夾名稱。");
|
|
36
|
+
}
|
|
37
|
+
return { mode, key, name, permission };
|
|
38
|
+
}
|
|
39
|
+
/** The first line `inspect` looks for to recover the declaration from an SPK. */
|
|
40
|
+
export const SHARED_FOLDER_MARKER = "# synopkgland:install.sharedFolder ";
|
|
41
|
+
/**
|
|
42
|
+
* `scripts/postinst` and `scripts/postupgrade`: store the Shared Folder *name*
|
|
43
|
+
* in `$SYNOPKG_PKGVAR/config.json`. The volume path is resolved at run time,
|
|
44
|
+
* so a moved folder keeps working. Runs as the package account.
|
|
45
|
+
*/
|
|
46
|
+
export function renderSharedFolderScript(pkg, folder) {
|
|
47
|
+
const { key } = folder;
|
|
48
|
+
const pick = folder.mode === "create"
|
|
49
|
+
? `name='${folder.name}'`
|
|
50
|
+
: `name=""
|
|
51
|
+
if [ "\${SYNOPKG_PKG_STATUS:-}" = "UPGRADE" ] && ! change_enabled "\${CHANGE_${key}:-}"; then
|
|
52
|
+
exit 0
|
|
53
|
+
fi
|
|
54
|
+
name="\${${key}:-}"
|
|
55
|
+
case "$name" in
|
|
56
|
+
''|*/*|*..*|@*|.*|*[[:cntrl:]]*|*'"'*|*'\\'*) echo "invalid shared folder name for ${key}" >&2; exit 1 ;;
|
|
57
|
+
esac`;
|
|
58
|
+
const gate = folder.mode === "create" ? "" : `change_enabled() {
|
|
59
|
+
case "$1" in true|1|yes|on) return 0 ;; *) return 1 ;; esac
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
return `#!/bin/sh
|
|
63
|
+
${SHARED_FOLDER_MARKER}${JSON.stringify(folder)}
|
|
64
|
+
set -eu
|
|
65
|
+
PKGVAR="\${SYNOPKG_PKGVAR:-/var/packages/${pkg}/var}"
|
|
66
|
+
CONFIG="$PKGVAR/config.json"
|
|
67
|
+
${gate}${pick}
|
|
68
|
+
umask 077
|
|
69
|
+
mkdir -p "$PKGVAR"
|
|
70
|
+
tmp="$CONFIG.tmp.$$"
|
|
71
|
+
printf '{"schema":1,"shared_folders":{"${key}":"%s"}}\\n' "$name" > "$tmp"
|
|
72
|
+
mv "$tmp" "$CONFIG"
|
|
73
|
+
exit 0
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
function intro(t, pkg, folder) {
|
|
77
|
+
const permission = t(`nativeShare.permission.${folder.permission}`);
|
|
78
|
+
return {
|
|
79
|
+
desc: folder.mode === "create"
|
|
80
|
+
? t("nativeShare.createIntro", { name: folder.name, permission })
|
|
81
|
+
: t("nativeShare.selectIntro", { account: pkg, permission }),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Install: the share picker (select) or a note (create). */
|
|
85
|
+
function installItems(t, pkg, folder) {
|
|
86
|
+
return folder.mode === "create" ? [intro(t, pkg, folder)] : [intro(t, pkg, folder), sharedFolderCombobox(t, folder.key)];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Upgrade: DSM prefills the first share, so a checked `CHANGE_<key>` box is what
|
|
90
|
+
* switches shares; unchecked keeps the stored one and the picker may stay blank.
|
|
91
|
+
*/
|
|
92
|
+
function upgradeItems(t, pkg, folder) {
|
|
93
|
+
if (folder.mode === "create")
|
|
94
|
+
return [intro(t, pkg, folder)];
|
|
95
|
+
const label = t("label.sharedFolder");
|
|
96
|
+
const picker = sharedFolderCombobox(t, folder.key);
|
|
97
|
+
const [subitem] = picker.subitems;
|
|
98
|
+
const { defaultValue: _unused, ...blankable } = subitem;
|
|
99
|
+
return [
|
|
100
|
+
intro(t, pkg, folder),
|
|
101
|
+
{
|
|
102
|
+
type: "multiselect",
|
|
103
|
+
desc: t("upgrade.changeDesc", { label }),
|
|
104
|
+
subitems: [{ key: `CHANGE_${folder.key}`, desc: t("upgrade.changeSub", { label }), defaultValue: false }],
|
|
105
|
+
},
|
|
106
|
+
{ ...picker, desc: t("upgrade.reuseDesc", { desc: String(picker.desc) }), subitems: [{ ...blankable, validator: { allowBlank: true } }] },
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
/** `install_uifile` and `upgrade_uifile`, English plus one file per DSM language. */
|
|
110
|
+
export function renderSharedFolderWizardFiles(pkg, folder) {
|
|
111
|
+
return {
|
|
112
|
+
...renderWizardFiles("install_uifile", sharedFolderInstallSteps(pkg, folder)),
|
|
113
|
+
...renderSharedFolderUpgradeWizardFiles(pkg, folder),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/** The install wizard steps that ask for the shared folder, for static or dynamic wizards. */
|
|
117
|
+
export function sharedFolderInstallSteps(pkg, folder) {
|
|
118
|
+
return t => [{ step_title: t("install.step"), items: installItems(t, pkg, folder) }];
|
|
119
|
+
}
|
|
120
|
+
/** The upgrade wizard files that let the administrator keep or change the shared folder. */
|
|
121
|
+
export function renderSharedFolderUpgradeWizardFiles(pkg, folder) {
|
|
122
|
+
return renderWizardFiles("upgrade_uifile", t => [{ step_title: t("upgrade.step"), items: upgradeItems(t, pkg, folder) }]);
|
|
123
|
+
}
|
|
124
|
+
/** `conf/resource` `data-share` entry: create mode only; DSM never deletes the share on uninstall. */
|
|
125
|
+
export function sharedFolderResource(pkg, folder) {
|
|
126
|
+
if (folder.mode !== "create")
|
|
127
|
+
return undefined;
|
|
128
|
+
return { shares: [{ name: folder.name, permission: { [folder.permission]: [pkg] } }] };
|
|
129
|
+
}
|
|
130
|
+
/** The declaration an SPK's postinst carries, or undefined when it has none or it is no longer valid. */
|
|
131
|
+
export function recoverSharedFolder(postinst) {
|
|
132
|
+
const line = postinst?.split("\n").find(l => l.startsWith(SHARED_FOLDER_MARKER));
|
|
133
|
+
if (!line)
|
|
134
|
+
return undefined;
|
|
135
|
+
try {
|
|
136
|
+
return readSharedFolder({ sharedFolder: JSON.parse(line.slice(SHARED_FOLDER_MARKER.length)) }, () => { });
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
}
|
package/dist/standalone/spk.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type NativeArchFamily } from "../build-spk/dsm-arch.js";
|
|
2
2
|
import type { StandaloneManifest } from "./manifest.js";
|
|
3
3
|
import type { HelperArtifact } from "./helper.js";
|
|
4
|
+
import { type AuthorizationArtifact } from "./authorization.js";
|
|
4
5
|
export declare const LIFECYCLE_SCRIPTS: readonly ["preinst", "postinst", "preuninst", "postuninst", "preupgrade", "postupgrade", "start-stop-status"];
|
|
5
6
|
export declare class StandaloneBuildError extends Error {
|
|
6
7
|
readonly code: string;
|
|
@@ -13,7 +14,10 @@ export interface AssembleOptions {
|
|
|
13
14
|
cgiPath: string;
|
|
14
15
|
outputPath: string;
|
|
15
16
|
helper?: HelperArtifact;
|
|
17
|
+
authorization?: AuthorizationArtifact;
|
|
16
18
|
daemonControl?: string;
|
|
19
|
+
/** The compiled background worker, required exactly when the manifest declares background. */
|
|
20
|
+
backgroundWorker?: string;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* Packs an unsigned Standalone Package SPK. DSM runs installation/lifecycle
|
package/dist/standalone/spk.js
CHANGED
|
@@ -5,13 +5,21 @@ import { dirname, join, relative, isAbsolute } from "node:path";
|
|
|
5
5
|
import { infoArchValue } from "../build-spk/dsm-arch.js";
|
|
6
6
|
import { writeDsmWindowIcons, writePackageCenterIcons } from "../build-spk/dsm-icons.js";
|
|
7
7
|
import { renderNativePrivilege } from "../build-spk/native-lifecycle.js";
|
|
8
|
+
import { renderUninstallWizardFiles } from "../build-spk/uninstall-wizard.js";
|
|
9
|
+
import { renderInstallWizardFiles, renderNativeInstallWizard } from "../build-spk/install-wizard.js";
|
|
10
|
+
import { writeWizardUiFiles } from "../build-spk/wizard-i18n.js";
|
|
8
11
|
import { createReproducibleTar } from "../build-spk/reproducible-archive.js";
|
|
9
12
|
import { renderStandaloneScript } from "./lifecycle.js";
|
|
10
13
|
import { DSM_LANGS, LOCALES } from "./i18n.js";
|
|
11
14
|
import { CGI_PAYLOAD_PATH, renderUiConfig, renderWindowScript, windowScriptName } from "./dsm-window.js";
|
|
15
|
+
import { hasHelper, inertWorkerRegistry } from "./helper-inventory.js";
|
|
12
16
|
import { copyStandaloneNotices } from "../build-spk/notices.js";
|
|
13
17
|
import { hostScriptName, renderHostAdapterScript } from "./host-adapter.js";
|
|
14
18
|
import { copyDaemonPayload } from "./daemon.js";
|
|
19
|
+
import { BACKGROUND_UNIT_DIR, BACKGROUND_WORKER_PAYLOAD, backgroundUnitName, renderBackgroundUnit } from "./background.js";
|
|
20
|
+
import { renderStandaloneResource } from "./resource.js";
|
|
21
|
+
import { authorizationPlan } from "./authorization.js";
|
|
22
|
+
import { renderSharedFolderUpgradeWizardFiles, sharedFolderInstallSteps } from "./shared-folder.js";
|
|
15
23
|
const FILE_MODE = 0o644;
|
|
16
24
|
const EXEC_MODE = 0o755;
|
|
17
25
|
const MAX_UI_BYTES = 64 * 1024 * 1024;
|
|
@@ -40,6 +48,8 @@ export async function assembleStandaloneSpk(options) {
|
|
|
40
48
|
const { manifest } = options;
|
|
41
49
|
const staging = mkdtempSync(join(tmpdir(), "syno-standalone-spk-"));
|
|
42
50
|
try {
|
|
51
|
+
if (manifest.privilege === "root" && !options.authorization)
|
|
52
|
+
throw new StandaloneBuildError("AUTHORIZATION_PIN_REQUIRED", "root package requires pinned authorization bootstrap");
|
|
43
53
|
const uiRoot = join(staging, "package", "ui");
|
|
44
54
|
const appDir = join(uiRoot, "app");
|
|
45
55
|
copyUiTree(manifest.ui.dir, appDir);
|
|
@@ -57,7 +67,15 @@ export async function assembleStandaloneSpk(options) {
|
|
|
57
67
|
throw new StandaloneBuildError("STANDALONE_DAEMON_ARTIFACT_REQUIRED", "daemon controller artifact required.");
|
|
58
68
|
copyDaemonPayload(manifest, options.arch, join(staging, "package", "daemon"), options.daemonControl);
|
|
59
69
|
}
|
|
60
|
-
if (manifest.
|
|
70
|
+
if (manifest.background) {
|
|
71
|
+
if (!options.backgroundWorker)
|
|
72
|
+
throw new StandaloneBuildError("STANDALONE_BACKGROUND_ARTIFACT_REQUIRED", "background worker artifact required.");
|
|
73
|
+
const worker = join(staging, "package", BACKGROUND_WORKER_PAYLOAD);
|
|
74
|
+
mkdirSync(dirname(worker), { recursive: true });
|
|
75
|
+
copyFileSync(options.backgroundWorker, worker);
|
|
76
|
+
chmodSync(worker, EXEC_MODE);
|
|
77
|
+
}
|
|
78
|
+
if (hasHelper(manifest) && !options.helper)
|
|
61
79
|
throw new StandaloneBuildError("HELPER_ARTIFACT_REQUIRED", "integration SPK 缺少已建置的 helper inventory。");
|
|
62
80
|
if (options.helper) {
|
|
63
81
|
const dir = join(staging, "package", "integration");
|
|
@@ -66,7 +84,7 @@ export async function assembleStandaloneSpk(options) {
|
|
|
66
84
|
copyFileSync(new URL("../../templates/native-go/backend/THIRD_PARTY_NOTICES.txt", import.meta.url), join(dir, "THIRD_PARTY_NOTICES.txt"));
|
|
67
85
|
chmodSync(join(dir, "helper"), EXEC_MODE);
|
|
68
86
|
writeFile(join(dir, "inventory.json"), JSON.stringify(options.helper.inventory));
|
|
69
|
-
writeFile(join(dir, "workers.json"),
|
|
87
|
+
writeFile(join(dir, "workers.json"), options.helper.registry ?? inertWorkerRegistry(options.helper.workers));
|
|
70
88
|
mkdirSync(join(dir, "workers"));
|
|
71
89
|
for (const worker of options.helper.workers) {
|
|
72
90
|
writeFileSync(join(dir, "workers", worker.id), worker.bytes, { mode: FILE_MODE });
|
|
@@ -85,6 +103,15 @@ export async function assembleStandaloneSpk(options) {
|
|
|
85
103
|
copyStandaloneNotices(manifest.root, manifest.ui.dir, join(staging, 'package'), manifest.backend.kind === 'go' || Boolean(manifest.daemon), Boolean(options.helper), manifest.integration?.identity === 'better-auth', manifest.backend.kind === 'go' ? manifest.backend.dir : undefined);
|
|
86
104
|
if (manifest.daemon)
|
|
87
105
|
copyFileSync(new URL('../../templates/_shared/LICENSES/TEMPLATE.txt', import.meta.url), join(staging, 'package', 'LICENSES', 'DAEMON-LICENSE.txt'));
|
|
106
|
+
if (manifest.privilege === "root") {
|
|
107
|
+
if (!options.authorization || !/^[a-f0-9]{64}$/.test(options.authorization.bootstrapSha256))
|
|
108
|
+
throw new StandaloneBuildError("AUTHORIZATION_PIN_REQUIRED", "root package requires pinned authorization bootstrap");
|
|
109
|
+
const authDir = join(staging, "package", "authorization");
|
|
110
|
+
mkdirSync(authDir);
|
|
111
|
+
copyFileSync(options.authorization.binary, join(authDir, "bootstrap"));
|
|
112
|
+
chmodSync(join(authDir, "bootstrap"), EXEC_MODE);
|
|
113
|
+
writeFile(join(authDir, "manifest.json"), JSON.stringify(authorizationPlan(options.authorization, manifest)));
|
|
114
|
+
}
|
|
88
115
|
const packageTgz = join(staging, "package.tgz");
|
|
89
116
|
await createReproducibleTar(join(staging, "package"), packageTgz, { gzip: true });
|
|
90
117
|
rmSync(join(staging, "package"), { recursive: true, force: true });
|
|
@@ -92,10 +119,25 @@ export async function assembleStandaloneSpk(options) {
|
|
|
92
119
|
writeFile(join(staging, "INFO"), renderInfo(manifest, options.arch, checksum));
|
|
93
120
|
mkdirSync(join(staging, "conf"));
|
|
94
121
|
writeFile(join(staging, "conf", "privilege"), renderNativePrivilege());
|
|
122
|
+
const resource = renderStandaloneResource(manifest);
|
|
123
|
+
if (resource)
|
|
124
|
+
writeFile(join(staging, "conf", "resource"), resource);
|
|
125
|
+
if (manifest.background) {
|
|
126
|
+
mkdirSync(join(staging, BACKGROUND_UNIT_DIR), { recursive: true });
|
|
127
|
+
writeFile(join(staging, BACKGROUND_UNIT_DIR, backgroundUnitName(manifest.package)), renderBackgroundUnit(manifest.package));
|
|
128
|
+
}
|
|
95
129
|
mkdirSync(join(staging, "scripts"));
|
|
96
130
|
for (const name of LIFECYCLE_SCRIPTS) {
|
|
97
131
|
writeFile(join(staging, "scripts", name), renderStandaloneScript(name, manifest), EXEC_MODE);
|
|
98
132
|
}
|
|
133
|
+
const folder = manifest.sharedFolder;
|
|
134
|
+
const install = renderInstallWizardFiles(manifest.package, folder ? sharedFolderInstallSteps(manifest.package, folder) : renderNativeInstallWizard);
|
|
135
|
+
writeWizardUiFiles(staging, {
|
|
136
|
+
...install.static,
|
|
137
|
+
...install.dynamic,
|
|
138
|
+
...(folder ? renderSharedFolderUpgradeWizardFiles(manifest.package, folder) : {}),
|
|
139
|
+
...renderUninstallWizardFiles(manifest.package, "native", { integration: hasHelper(manifest) }),
|
|
140
|
+
});
|
|
99
141
|
writePackageCenterIcons(staging);
|
|
100
142
|
mkdirSync(dirname(options.outputPath), { recursive: true });
|
|
101
143
|
await createReproducibleTar(staging, options.outputPath);
|
|
@@ -127,7 +169,9 @@ function renderInfo(manifest, arch, checksum) {
|
|
|
127
169
|
["startable", "yes"],
|
|
128
170
|
["checksum", checksum],
|
|
129
171
|
];
|
|
130
|
-
if (manifest.
|
|
172
|
+
if (manifest.privilege === "root")
|
|
173
|
+
fields.push(["sdk_root_authorization", "2"]);
|
|
174
|
+
if (hasHelper(manifest) || manifest.daemon)
|
|
131
175
|
fields.push(["precheckstartstop", "yes"]);
|
|
132
176
|
if (manifest.integration?.identity === "better-auth")
|
|
133
177
|
fields.push(["install_dep_packages", "Node.js_v22"]);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { WorkerSafeReason } from "./worker-contract.js";
|
|
2
|
+
export declare class WorkerContractError extends Error {
|
|
3
|
+
readonly code: WorkerSafeReason;
|
|
4
|
+
constructor(code: WorkerSafeReason);
|
|
5
|
+
}
|
|
6
|
+
export declare function fail(code?: WorkerSafeReason): never;
|
|
7
|
+
export declare function validUnicode(s: string): boolean;
|
|
8
|
+
export declare function strictJSON(raw: string | Uint8Array, cap: number): unknown;
|