@synopackageland/cli 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +613 -0
- package/README.md +81 -89
- package/dist/add.js +39 -16
- package/dist/build-spk/delegate-scope.d.ts +6 -0
- package/dist/build-spk/delegate-scope.js +34 -0
- package/dist/build-spk/dsm-arch.d.ts +7 -1
- package/dist/build-spk/dsm-arch.js +24 -28
- package/dist/build-spk/dsm-platforms.json +39 -0
- package/dist/build-spk/dsm-version.d.ts +11 -0
- package/dist/build-spk/dsm-version.js +17 -0
- package/dist/build-spk/gateway.d.ts +1 -1
- package/dist/build-spk/gateway.js +2 -2
- package/dist/build-spk/generator.js +30 -5
- package/dist/build-spk/notices.js +4 -1
- package/dist/build-spk/resource-worker.js +3 -0
- package/dist/build-spk/wizard-messages.d.ts +66 -0
- package/dist/build-spk/wizard-messages.js +75 -9
- package/dist/cli.js +15 -7
- package/dist/contract/schema-validate.js +8 -0
- package/dist/contract/validate.js +30 -0
- package/dist/deploy/deploy.d.ts +1 -1
- package/dist/deploy/deploy.js +8 -0
- package/dist/deploy/plan.js +1 -1
- package/dist/deploy/spk-version.js +1 -1
- package/dist/error-registry.js +43 -15
- package/dist/host/dsm-client.d.ts +8 -4
- package/dist/host/dsm-client.js +10 -4
- package/dist/host/types.d.ts +2 -1
- package/dist/info.js +18 -2
- package/dist/init.d.ts +3 -0
- package/dist/init.js +49 -18
- package/dist/package-metadata.d.ts +21 -0
- package/dist/package-metadata.js +101 -0
- package/dist/portal/alias.d.ts +25 -0
- package/dist/portal/alias.js +48 -0
- package/dist/portal/package.d.ts +33 -0
- package/dist/portal/package.js +116 -0
- package/dist/runtime/delegate-contract.d.ts +79 -0
- package/dist/runtime/delegate-contract.js +27 -0
- package/dist/runtime/executor-build.d.ts +1 -1
- package/dist/runtime/executor-build.js +5 -4
- package/dist/runtime/executor-inspect.d.ts +3 -0
- package/dist/runtime/executor-inspect.js +11 -5
- package/dist/runtime/executor-policy.d.ts +12 -0
- package/dist/runtime/executor-policy.js +43 -3
- package/dist/runtime/executor-scope-task.d.ts +4 -0
- package/dist/runtime/executor-scope-task.js +21 -0
- package/dist/runtime/executor-tasks.d.ts +2 -1
- package/dist/runtime/executor-tasks.js +4 -4
- package/dist/skill.js +1 -0
- package/dist/standalone/api-permissions.d.ts +10 -0
- package/dist/standalone/api-permissions.js +19 -2
- package/dist/standalone/background.d.ts +16 -0
- package/dist/standalone/background.js +69 -2
- package/dist/standalone/binary.d.ts +1 -1
- package/dist/standalone/binary.js +22 -8
- package/dist/standalone/build.d.ts +1 -1
- package/dist/standalone/build.js +38 -8
- package/dist/standalone/daemon.d.ts +1 -1
- package/dist/standalone/daemon.js +2 -1
- package/dist/standalone/dsm-window.d.ts +3 -1
- package/dist/standalone/dsm-window.js +72 -15
- package/dist/standalone/inspect-spk.d.ts +8 -0
- package/dist/standalone/inspect-spk.js +105 -26
- package/dist/standalone/lifecycle.js +86 -8
- package/dist/standalone/manifest.d.ts +13 -0
- package/dist/standalone/manifest.js +57 -8
- package/dist/standalone/native-authorization-window.d.ts +1 -1
- package/dist/standalone/native-authorization-window.js +2 -0
- package/dist/standalone/native-layout.d.ts +3 -0
- package/dist/standalone/native-layout.js +37 -5
- package/dist/standalone/portal-window.d.ts +21 -0
- package/dist/standalone/portal-window.js +155 -0
- package/dist/standalone/portal.d.ts +4 -0
- package/dist/standalone/portal.js +4 -0
- package/dist/standalone/resource.d.ts +5 -3
- package/dist/standalone/resource.js +6 -3
- package/dist/standalone/root-window.js +62 -15
- package/dist/standalone/spk.d.ts +1 -1
- package/dist/standalone/spk.js +25 -7
- package/dist/templates/_daemon/main_test.go +61 -8
- package/dist/templates/_executor/README.md +127 -16
- package/dist/templates/_executor/anchor.go +146 -0
- package/dist/templates/_executor/anchor_test.go +126 -0
- package/dist/templates/_executor/apppriv_review_test.go +1 -1
- package/dist/templates/_executor/cancel_contract_test.go +236 -0
- package/dist/templates/_executor/copy.go +64 -0
- package/dist/templates/_executor/copy_test.go +88 -0
- package/dist/templates/_executor/dsm.go +23 -10
- package/dist/templates/_executor/dsm_test.go +95 -1
- package/dist/templates/_executor/executor.go +260 -49
- package/dist/templates/_executor/executor_test.go +36 -6
- package/dist/templates/_executor/identity.go +27 -1
- package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
- package/dist/templates/_executor/identity_linux.go +82 -0
- package/dist/templates/_executor/identity_security_test.go +43 -0
- package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
- package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
- package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
- package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
- package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
- package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
- package/dist/templates/_executor/lifecycle_test.go +11 -0
- package/dist/templates/_executor/link_linux.go +28 -0
- package/dist/templates/_executor/long_running_test.go +530 -0
- package/dist/templates/_executor/main.go +72 -20
- package/dist/templates/_executor/move_linux.go +490 -0
- package/dist/templates/_executor/move_linux_test.go +460 -0
- package/dist/templates/_executor/move_validation.go +46 -0
- package/dist/templates/_executor/move_validation_test.go +187 -0
- package/dist/templates/_executor/operations.go +926 -0
- package/dist/templates/_executor/platform_linux.go +24 -173
- package/dist/templates/_executor/platform_linux_test.go +9 -65
- package/dist/templates/_executor/platform_other.go +30 -4
- package/dist/templates/_executor/process.go +3 -0
- package/dist/templates/_executor/records.go +242 -0
- package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
- package/dist/templates/_executor/scope_client.go +37 -0
- package/dist/templates/_executor/scope_contract.go +12 -0
- package/dist/templates/_executor/selected_scope.go +146 -0
- package/dist/templates/_executor/selected_scope_test.go +186 -0
- package/dist/templates/_executor/status_disabled_test.go +33 -0
- package/dist/templates/_executor/store.go +4 -3
- package/dist/templates/_executor/supervise.go +109 -0
- package/dist/templates/_executor/supervise_test.go +130 -0
- package/dist/templates/_executor/task_race_review_test.go +1 -1
- package/dist/templates/_executor/tasks.go +7 -8
- package/dist/templates/_executor/tasks_review_test.go +1 -1
- package/dist/templates/_executor/tasks_test.go +4 -4
- package/dist/templates/_executor/watch.go +8 -0
- package/dist/templates/_executor/watch_test.go +23 -2
- package/dist/templates/_executor/write_review_linux_test.go +4 -12
- package/dist/templates/_shared/AGENTS.md +129 -0
- package/dist/templates/binary/dsm-package.yaml +24 -0
- package/dist/templates/binary/i18n/messages/de.json +4 -0
- package/dist/templates/binary/i18n/messages/en.json +4 -0
- package/dist/templates/binary/i18n/messages/es.json +4 -0
- package/dist/templates/binary/i18n/messages/fr.json +4 -0
- package/dist/templates/binary/i18n/messages/it.json +4 -0
- package/dist/templates/binary/i18n/messages/ja.json +4 -0
- package/dist/templates/binary/i18n/messages/ko.json +4 -0
- package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/dist/templates/binary/ui/app.js +19 -4
- package/dist/templates/native-authorization/AuthorizationGate.vue +5 -3
- package/dist/templates/native-authorization/i18n/de.json +1 -0
- package/dist/templates/native-authorization/i18n/en.json +1 -0
- package/dist/templates/native-authorization/i18n/es.json +2 -1
- package/dist/templates/native-authorization/i18n/fr.json +1 -0
- package/dist/templates/native-authorization/i18n/it.json +11 -10
- package/dist/templates/native-authorization/i18n/ja.json +1 -0
- package/dist/templates/native-authorization/i18n/ko.json +10 -9
- package/dist/templates/native-authorization/i18n/zh-CN.json +6 -5
- package/dist/templates/native-authorization/i18n/zh-TW.json +6 -5
- package/dist/templates/native-go/README.md +43 -10
- package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
- package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
- package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
- package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
- package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
- package/dist/templates/native-go/backend/internal/api/server.go +18 -5
- package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
- package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
- package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
- package/dist/templates/native-go/backend/internal/background/store.go +16 -14
- package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
- package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
- package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
- package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
- package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
- package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
- package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
- package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
- package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
- package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
- package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
- package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
- package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
- package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
- package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
- package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
- package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
- package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
- package/dist/templates/native-go/dsm-package.yaml +20 -1
- package/dist/templates/native-go/i18n/glossary.json +2 -1
- package/dist/templates/native-go/i18n/messages/de.json +1 -0
- package/dist/templates/native-go/i18n/messages/en.json +1 -0
- package/dist/templates/native-go/i18n/messages/es.json +1 -0
- package/dist/templates/native-go/i18n/messages/fr.json +1 -0
- package/dist/templates/native-go/i18n/messages/it.json +1 -0
- package/dist/templates/native-go/i18n/messages/ja.json +1 -0
- package/dist/templates/native-go/i18n/messages/ko.json +1 -0
- package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
- package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
- package/dist/templates/native-go/ui/app.css +10 -0
- package/dist/templates/native-go/ui/app.js +11 -1
- package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
- package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
- package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
- package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
- package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
- package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
- package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
- package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
- package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
- package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
- package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
- package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
- package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
- package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
- package/dist/templates/native-go-delegate/test.sh +1 -0
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
- package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
- package/dist/templates/native-go-vue/README.md +4 -0
- package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
- package/dist/templates/native-go-vue/frontend/package.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
- package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
- package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
- package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
- package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
- package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
- package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
- package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
- package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
- package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
- package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
- package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
- package/package.json +5 -1
- package/schema/package-metadata.schema.json +101 -0
- package/schema/synology-app.schema.json +112 -0
- package/skills/SKILL.md +106 -4
- package/skills/reference/create.md +101 -2
- package/skills/reference/deploy.md +2 -2
- package/skills/reference/files.md +113 -2
- package/skills/reference/identity.md +70 -1
- package/skills/reference/portal.md +17 -0
- package/skills/reference/ui-vue.md +12 -0
- package/templates/_daemon/main_test.go +61 -8
- package/templates/_executor/README.md +127 -16
- package/templates/_executor/anchor.go +146 -0
- package/templates/_executor/anchor_test.go +126 -0
- package/templates/_executor/apppriv_review_test.go +1 -1
- package/templates/_executor/cancel_contract_test.go +236 -0
- package/templates/_executor/copy.go +64 -0
- package/templates/_executor/copy_test.go +88 -0
- package/templates/_executor/dsm.go +23 -10
- package/templates/_executor/dsm_test.go +95 -1
- package/templates/_executor/executor.go +260 -49
- package/templates/_executor/executor_test.go +36 -6
- package/templates/_executor/identity.go +27 -1
- package/templates/_executor/identity_kernel_linux_test.go +60 -0
- package/templates/_executor/identity_linux.go +82 -0
- package/templates/_executor/identity_security_test.go +43 -0
- package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
- package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
- package/templates/_executor/internal/taskscript/boot.sh +9 -9
- package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
- package/templates/_executor/internal/taskscript/control.sh +15 -10
- package/templates/_executor/internal/taskscript/tasks.go +5 -3
- package/templates/_executor/lifecycle_test.go +11 -0
- package/templates/_executor/link_linux.go +28 -0
- package/templates/_executor/long_running_test.go +530 -0
- package/templates/_executor/main.go +72 -20
- package/templates/_executor/move_linux.go +490 -0
- package/templates/_executor/move_linux_test.go +460 -0
- package/templates/_executor/move_validation.go +46 -0
- package/templates/_executor/move_validation_test.go +187 -0
- package/templates/_executor/operations.go +926 -0
- package/templates/_executor/platform_linux.go +24 -173
- package/templates/_executor/platform_linux_test.go +9 -65
- package/templates/_executor/platform_other.go +30 -4
- package/templates/_executor/process.go +3 -0
- package/templates/_executor/records.go +242 -0
- package/templates/_executor/scope_cancel_contract_test.go +91 -0
- package/templates/_executor/scope_client.go +37 -0
- package/templates/_executor/scope_contract.go +12 -0
- package/templates/_executor/selected_scope.go +146 -0
- package/templates/_executor/selected_scope_test.go +186 -0
- package/templates/_executor/status_disabled_test.go +33 -0
- package/templates/_executor/store.go +4 -3
- package/templates/_executor/supervise.go +109 -0
- package/templates/_executor/supervise_test.go +130 -0
- package/templates/_executor/task_race_review_test.go +1 -1
- package/templates/_executor/tasks.go +7 -8
- package/templates/_executor/tasks_review_test.go +1 -1
- package/templates/_executor/tasks_test.go +4 -4
- package/templates/_executor/watch.go +8 -0
- package/templates/_executor/watch_test.go +23 -2
- package/templates/_executor/write_review_linux_test.go +4 -12
- package/templates/_shared/AGENTS.md +129 -0
- package/templates/binary/dsm-package.yaml +24 -0
- package/templates/binary/i18n/messages/de.json +4 -0
- package/templates/binary/i18n/messages/en.json +4 -0
- package/templates/binary/i18n/messages/es.json +4 -0
- package/templates/binary/i18n/messages/fr.json +4 -0
- package/templates/binary/i18n/messages/it.json +4 -0
- package/templates/binary/i18n/messages/ja.json +4 -0
- package/templates/binary/i18n/messages/ko.json +4 -0
- package/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/templates/binary/ui/app.js +19 -4
- package/templates/native-authorization/AuthorizationGate.vue +5 -3
- package/templates/native-authorization/i18n/de.json +1 -0
- package/templates/native-authorization/i18n/en.json +1 -0
- package/templates/native-authorization/i18n/es.json +2 -1
- package/templates/native-authorization/i18n/fr.json +1 -0
- package/templates/native-authorization/i18n/it.json +11 -10
- package/templates/native-authorization/i18n/ja.json +1 -0
- package/templates/native-authorization/i18n/ko.json +10 -9
- package/templates/native-authorization/i18n/zh-CN.json +6 -5
- package/templates/native-authorization/i18n/zh-TW.json +6 -5
- package/templates/native-go/README.md +43 -10
- package/templates/native-go/backend/cmd/app/main.go +27 -7
- package/templates/native-go/backend/internal/api/entry_test.go +47 -0
- package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
- package/templates/native-go/backend/internal/api/registry.go +11 -0
- package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
- package/templates/native-go/backend/internal/api/server.go +18 -5
- package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/templates/native-go/backend/internal/app/portal.go +30 -0
- package/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/templates/native-go/backend/internal/app/routes.go +8 -2
- package/templates/native-go/backend/internal/background/runner.go +1 -1
- package/templates/native-go/backend/internal/background/store.go +16 -14
- package/templates/native-go/backend/internal/dsm/admin.go +8 -2
- package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
- package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
- package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
- package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
- package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
- package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
- package/templates/native-go/backend/internal/dsm/entry.go +177 -0
- package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
- package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
- package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
- package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
- package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
- package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
- package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
- package/templates/native-go/backend/internal/filestation/service.go +1 -1
- package/templates/native-go/backend/internal/portal/portal.go +138 -0
- package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
- package/templates/native-go/dsm-package.yaml +20 -1
- package/templates/native-go/i18n/glossary.json +2 -1
- package/templates/native-go/i18n/messages/de.json +1 -0
- package/templates/native-go/i18n/messages/en.json +1 -0
- package/templates/native-go/i18n/messages/es.json +1 -0
- package/templates/native-go/i18n/messages/fr.json +1 -0
- package/templates/native-go/i18n/messages/it.json +1 -0
- package/templates/native-go/i18n/messages/ja.json +1 -0
- package/templates/native-go/i18n/messages/ko.json +1 -0
- package/templates/native-go/i18n/messages/zh-CN.json +1 -0
- package/templates/native-go/i18n/messages/zh-TW.json +1 -0
- package/templates/native-go/ui/app.css +10 -0
- package/templates/native-go/ui/app.js +11 -1
- package/templates/native-go-delegate/DELEGATE.md +126 -5
- package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
- package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
- package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
- package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
- package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
- package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
- package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
- package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
- package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
- package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
- package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
- package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
- package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
- package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
- package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
- package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
- package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
- package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
- package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
- package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
- package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
- package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
- package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
- package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
- package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
- package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
- package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
- package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
- package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
- package/templates/native-go-delegate/test.sh +1 -0
- package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
- package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
- package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
- package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
- package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
- package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
- package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
- package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
- package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
- package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
- package/templates/native-go-vue/README.md +4 -0
- package/templates/native-go-vue/frontend/package-lock.json +4 -4
- package/templates/native-go-vue/frontend/package.json +1 -1
- package/templates/native-go-vue/frontend/src/App.vue +18 -13
- package/templates/native-go-vue/frontend/src/context.ts +31 -0
- package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
- package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
- package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
- package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
- package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
- package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
- package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
- package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
- package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
- package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
- package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
- package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
- package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
- package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
- package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
- package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
- package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
- package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
- package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
- package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
- package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
- package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
- package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
- package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
- package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
- package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { PORTAL_ALIAS_PATTERN, RESERVED_PORTAL_ALIASES } from "../portal/alias.js";
|
|
2
|
+
/** SDK-owned portal panel text, shared by the plain panel and the Vue template. */
|
|
3
|
+
export const PORTAL_MESSAGES = {
|
|
4
|
+
title: { en: "Application Portal", "zh-TW": "應用程式入口", "zh-CN": "应用程序门户", ja: "アプリケーションポータル", ko: "응용 프로그램 포털", de: "Anwendungsportal", fr: "Portail d'application", es: "Portal de aplicaciones", it: "Portale applicazioni" },
|
|
5
|
+
link: { en: "Direct link after DSM sign-in:", "zh-TW": "DSM 登入後的直接連結:", "zh-CN": "DSM 登录后的直接链接:", ja: "DSM サインイン後の直接リンク:", ko: "DSM 로그인 후 바로 가기 링크:", de: "Direkter Link nach der DSM-Anmeldung:", fr: "Lien direct après connexion à DSM :", es: "Enlace directo tras iniciar sesión en DSM:", it: "Link diretto dopo l'accesso a DSM:" },
|
|
6
|
+
inactive: { en: "Not active. Apply an alias to let users open this app directly after DSM sign-in.", "zh-TW": "尚未啟用。套用別名後,使用者可在 DSM 登入後直接開啟這個 App。", "zh-CN": "尚未启用。应用别名后,用户可在 DSM 登录后直接打开此应用。", ja: "無効です。エイリアスを適用すると、DSM サインイン後にこのアプリを直接開けます。", ko: "비활성 상태입니다. 별칭을 적용하면 DSM 로그인 후 이 앱을 바로 열 수 있습니다.", de: "Nicht aktiv. Wenden Sie einen Alias an, damit Benutzer diese App nach der DSM-Anmeldung direkt öffnen können.", fr: "Inactif. Appliquez un alias pour ouvrir cette application directement après connexion à DSM.", es: "Inactivo. Aplique un alias para abrir esta aplicación directamente tras iniciar sesión en DSM.", it: "Non attivo. Applica un alias per aprire questa app direttamente dopo l'accesso a DSM." },
|
|
7
|
+
askAdmin: { en: "Ask an administrator to set this up", "zh-TW": "請管理員設定", "zh-CN": "请管理员设置", ja: "管理者に設定を依頼してください", ko: "관리자에게 설정을 요청하세요", de: "Bitten Sie einen Administrator, dies einzurichten", fr: "Demandez à un administrateur de le configurer", es: "Pida a un administrador que lo configure", it: "Chiedi a un amministratore di configurarlo" },
|
|
8
|
+
alias: { en: "Alias", "zh-TW": "別名", "zh-CN": "别名", ja: "エイリアス", ko: "별칭", de: "Alias", fr: "Alias", es: "Alias", it: "Alias" },
|
|
9
|
+
apply: { en: "Apply", "zh-TW": "套用", "zh-CN": "应用", ja: "適用", ko: "적용", de: "Übernehmen", fr: "Appliquer", es: "Aplicar", it: "Applica" },
|
|
10
|
+
disable: { en: "Turn off", "zh-TW": "停用", "zh-CN": "停用", ja: "無効にする", ko: "끄기", de: "Ausschalten", fr: "Désactiver", es: "Desactivar", it: "Disattiva" },
|
|
11
|
+
advanced: { en: "Advanced settings in Control Panel", "zh-TW": "在控制台進行進階設定", "zh-CN": "在控制面板中进行高级设置", ja: "コントロールパネルの詳細設定", ko: "제어판의 고급 설정", de: "Erweiterte Einstellungen in der Systemsteuerung", fr: "Paramètres avancés dans le Panneau de configuration", es: "Ajustes avanzados en el Panel de control", it: "Impostazioni avanzate nel Pannello di controllo" },
|
|
12
|
+
controlPanel: { en: "Open Control Panel Application Portal", "zh-TW": "開啟控制台 Application Portal", "zh-CN": "打开控制面板 Application Portal", ja: "コントロールパネルの Application Portal を開く", ko: "제어판 Application Portal 열기", de: "Application Portal in der Systemsteuerung öffnen", fr: "Ouvrir Application Portal dans le Panneau de configuration", es: "Abrir Application Portal en el Panel de control", it: "Apri Application Portal nel Pannello di controllo" },
|
|
13
|
+
portal_alias_invalid: { en: "Use 1-64 lowercase letters, digits or hyphens, not starting or ending with a hyphen.", "zh-TW": "請使用 1–64 個小寫英文字母、數字或連字號,且不可以連字號開頭或結尾。", "zh-CN": "请使用 1–64 个小写英文字母、数字或连字符,且不能以连字符开头或结尾。", ja: "1~64 文字の小文字英字・数字・ハイフンを使用し、先頭と末尾にハイフンは使えません。", ko: "1~64자의 영문 소문자, 숫자 또는 하이픈을 사용하고 하이픈으로 시작하거나 끝나지 않게 하세요.", de: "Verwenden Sie 1–64 Kleinbuchstaben, Ziffern oder Bindestriche, ohne Bindestrich am Anfang oder Ende.", fr: "Utilisez 1 à 64 lettres minuscules, chiffres ou tirets, sans tiret au début ni à la fin.", es: "Use de 1 a 64 letras minúsculas, dígitos o guiones, sin guion al principio ni al final.", it: "Usa da 1 a 64 lettere minuscole, cifre o trattini, senza trattino all'inizio o alla fine." },
|
|
14
|
+
portal_alias_reserved: { en: "DSM already uses this alias. Choose another one.", "zh-TW": "DSM 已使用這個別名,請改用其他別名。", "zh-CN": "DSM 已使用此别名,请改用其他别名。", ja: "このエイリアスは DSM で使用されています。別のものを選んでください。", ko: "DSM에서 이미 사용하는 별칭입니다. 다른 별칭을 선택하세요.", de: "DSM verwendet diesen Alias bereits. Wählen Sie einen anderen.", fr: "DSM utilise déjà cet alias. Choisissez-en un autre.", es: "DSM ya usa este alias. Elija otro.", it: "DSM usa già questo alias. Scegline un altro." },
|
|
15
|
+
portal_alias_in_use: { en: "Another app already uses this alias. Choose another one.", "zh-TW": "另一個 App 已使用這個別名,請改用其他別名。", "zh-CN": "另一个应用已使用此别名,请改用其他别名。", ja: "別のアプリがこのエイリアスを使用しています。別のものを選んでください。", ko: "다른 앱이 이미 이 별칭을 사용합니다. 다른 별칭을 선택하세요.", de: "Eine andere App verwendet diesen Alias bereits. Wählen Sie einen anderen.", fr: "Une autre application utilise déjà cet alias. Choisissez-en un autre.", es: "Otra aplicación ya usa este alias. Elija otro.", it: "Un'altra app usa già questo alias. Scegline un altro." },
|
|
16
|
+
admin_required: { en: "Only a DSM administrator can change this.", "zh-TW": "只有 DSM 管理員可以變更這項設定。", "zh-CN": "只有 DSM 管理员可以更改此设置。", ja: "これを変更できるのは DSM 管理者のみです。", ko: "DSM 관리자만 변경할 수 있습니다.", de: "Nur ein DSM-Administrator kann dies ändern.", fr: "Seul un administrateur DSM peut modifier ce paramètre.", es: "Solo un administrador de DSM puede cambiar esto.", it: "Solo un amministratore DSM può modificarlo." },
|
|
17
|
+
portal_unavailable: { en: "DSM did not accept the change. Try again or use Control Panel.", "zh-TW": "DSM 未接受變更。請再試一次或改用控制台。", "zh-CN": "DSM 未接受更改。请重试或改用控制面板。", ja: "DSM は変更を受け付けませんでした。再試行するか、コントロールパネルを使用してください。", ko: "DSM이 변경을 받아들이지 않았습니다. 다시 시도하거나 제어판을 사용하세요.", de: "DSM hat die Änderung nicht übernommen. Versuchen Sie es erneut oder verwenden Sie die Systemsteuerung.", fr: "DSM n'a pas accepté la modification. Réessayez ou utilisez le Panneau de configuration.", es: "DSM no aceptó el cambio. Inténtelo de nuevo o use el Panel de control.", it: "DSM non ha accettato la modifica. Riprova o usa il Pannello di controllo." },
|
|
18
|
+
};
|
|
19
|
+
function localizedMessages() {
|
|
20
|
+
const out = {};
|
|
21
|
+
for (const [key, texts] of Object.entries(PORTAL_MESSAGES)) {
|
|
22
|
+
for (const [locale, text] of Object.entries(texts))
|
|
23
|
+
(out[locale] ??= {})[key] = text;
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* `createPortalAccess(options)` → `ctx.portal`, plain ES5 for DSM's desktop.
|
|
29
|
+
*
|
|
30
|
+
* An administrator reads and sets the alias with DSM's own
|
|
31
|
+
* SYNO.Core.AppPortal API in their own session, after SYNO.API.Info shows the
|
|
32
|
+
* API; DSM itself refuses everyone else (105). An ordinary user reads the
|
|
33
|
+
* alias only through the package backend's `portal.status`. Anything
|
|
34
|
+
* unexpected reads as `unavailable`; an administrator then gets only the
|
|
35
|
+
* Control Panel shortcut.
|
|
36
|
+
*
|
|
37
|
+
* `status()` resolves `{state, alias?, url?, canManage, controlPanel,
|
|
38
|
+
* defaultAlias}`; `apply(alias)` and `disable()` resolve the new status or
|
|
39
|
+
* reject `{code}`; `openControlPanel()` opens Login Portal > Applications.
|
|
40
|
+
* `messages` is the panel text in the window's locale; `mountPanel(element)`
|
|
41
|
+
* renders a plain panel for UIs without their own.
|
|
42
|
+
*/
|
|
43
|
+
export const PORTAL_RUNTIME = `function createPortalAccess(options) {
|
|
44
|
+
var ALIAS = new RegExp(${JSON.stringify(PORTAL_ALIAS_PATTERN.source)});
|
|
45
|
+
var RESERVED = ${JSON.stringify(RESERVED_PORTAL_ALIASES)};
|
|
46
|
+
var LINKABLE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
|
47
|
+
var CATALOGS = ${JSON.stringify(localizedMessages())};
|
|
48
|
+
var messages = CATALOGS[options.locale] || CATALOGS.en;
|
|
49
|
+
var ERRORS = { dsm_4100: "portal_alias_invalid", dsm_4102: "portal_alias_reserved", dsm_4103: "portal_alias_in_use", dsm_105: "admin_required" };
|
|
50
|
+
function result(state, alias, managed) {
|
|
51
|
+
var out = { state: state, canManage: managed === true, controlPanel: managed !== undefined, defaultAlias: options.defaultAlias };
|
|
52
|
+
if (state === "active") {
|
|
53
|
+
out.alias = alias;
|
|
54
|
+
out.url = options.location.protocol + "//" + options.location.host + "/" + encodeURIComponent(alias) + "/";
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
function fromBackend() {
|
|
59
|
+
return options.call("portal.status", {}).then(function (data) {
|
|
60
|
+
if (data && data.state === "active" && typeof data.alias === "string" && LINKABLE.test(data.alias)) return result("active", data.alias);
|
|
61
|
+
return result(data && data.state === "inactive" ? "inactive" : "unavailable");
|
|
62
|
+
}, function () {
|
|
63
|
+
return result("unavailable");
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function fromDsm() {
|
|
67
|
+
return options.send("SYNO.API.Info", "query", 1, { query: "SYNO.Core.AppPortal" }).then(function (info) {
|
|
68
|
+
var api = info && info["SYNO.Core.AppPortal"];
|
|
69
|
+
if (!api || !(api.maxVersion >= 2)) return null;
|
|
70
|
+
return options.send("SYNO.Core.AppPortal", "get", 2, { id: options.appId, additional: ["default_setting"] });
|
|
71
|
+
}).then(function (item) {
|
|
72
|
+
if (!item || item.id !== options.appId) return result("unavailable", undefined, false);
|
|
73
|
+
var alias = typeof item.alias === "string" && LINKABLE.test(item.alias) ? item.alias : "";
|
|
74
|
+
var out = result(alias ? "active" : "inactive", alias, true);
|
|
75
|
+
var setting = item.additional && item.additional.default_setting;
|
|
76
|
+
if (setting && typeof setting.alias === "string" && ALIAS.test(setting.alias)) out.defaultAlias = setting.alias;
|
|
77
|
+
return out;
|
|
78
|
+
}, function () {
|
|
79
|
+
return result("unavailable", undefined, false);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function status() {
|
|
83
|
+
return options.isAdmin() ? fromDsm() : fromBackend();
|
|
84
|
+
}
|
|
85
|
+
function set(alias) {
|
|
86
|
+
if (!options.isAdmin()) return Promise.reject({ code: "admin_required" });
|
|
87
|
+
return options.send("SYNO.Core.AppPortal", "set", 2, { id: options.appId, alias: alias }).then(status, function (error) {
|
|
88
|
+
throw { code: ERRORS[error && error.code] || "portal_unavailable" };
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
var access = {
|
|
92
|
+
messages: messages,
|
|
93
|
+
status: status,
|
|
94
|
+
apply: function (alias) {
|
|
95
|
+
if (typeof alias !== "string" || !ALIAS.test(alias)) return Promise.reject({ code: "portal_alias_invalid" });
|
|
96
|
+
if (RESERVED.indexOf(alias) >= 0) return Promise.reject({ code: "portal_alias_reserved" });
|
|
97
|
+
return set(alias);
|
|
98
|
+
},
|
|
99
|
+
disable: function () {
|
|
100
|
+
return set(null);
|
|
101
|
+
},
|
|
102
|
+
openControlPanel: function () {
|
|
103
|
+
options.launch("SYNO.SDS.AdminCenter.Application", { fn: "SYNO.SDS.AdminCenter.Login.Main", tab: "applications" });
|
|
104
|
+
},
|
|
105
|
+
mountPanel: function (element) {
|
|
106
|
+
return mountPanel(element);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
function node(tag, attrs, children) {
|
|
110
|
+
var out = document.createElement(tag);
|
|
111
|
+
for (var key in attrs) {
|
|
112
|
+
if (key === "text") out.textContent = attrs[key];
|
|
113
|
+
else out.setAttribute(key, attrs[key]);
|
|
114
|
+
}
|
|
115
|
+
for (var i = 0; children && i < children.length; i++) out.appendChild(children[i]);
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
function button(text, onClick) {
|
|
119
|
+
var out = node("button", { type: "button", text: text });
|
|
120
|
+
out.addEventListener("click", function (event) { event.preventDefault(); onClick(); });
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
function mountPanel(element) {
|
|
124
|
+
var disposed = false;
|
|
125
|
+
function render(current, error) {
|
|
126
|
+
if (disposed) return;
|
|
127
|
+
var parts = [node("h2", { text: messages.title })];
|
|
128
|
+
var settle = function (next) { return next.then(function (fresh) { render(fresh); }, function (failure) { render(current, failure); }); };
|
|
129
|
+
if (current.state === "active") {
|
|
130
|
+
parts.push(node("p", {}, [node("span", { text: messages.link + " " }), node("a", { href: current.url, target: "_blank", rel: "noopener", text: current.url })]));
|
|
131
|
+
}
|
|
132
|
+
if (current.canManage) {
|
|
133
|
+
if (current.state !== "active") parts.push(node("p", { text: messages.inactive }));
|
|
134
|
+
var input = node("input", { type: "text", maxlength: "64", autocomplete: "off", "aria-label": messages.alias });
|
|
135
|
+
input.value = current.alias || current.defaultAlias;
|
|
136
|
+
var form = node("form", { class: "dsmapp-portal-form" }, [node("label", { text: messages.alias }), input, node("button", { type: "submit", text: messages.apply })]);
|
|
137
|
+
form.addEventListener("submit", function (event) { event.preventDefault(); settle(access.apply(input.value)); });
|
|
138
|
+
if (current.state === "active") form.appendChild(button(messages.disable, function () { settle(access.disable()); }));
|
|
139
|
+
parts.push(form, button(messages.advanced, access.openControlPanel));
|
|
140
|
+
} else if (current.controlPanel) {
|
|
141
|
+
parts.push(button(messages.controlPanel, access.openControlPanel));
|
|
142
|
+
} else if (current.state !== "active") {
|
|
143
|
+
parts.push(node("p", { text: messages.askAdmin }));
|
|
144
|
+
}
|
|
145
|
+
if (error) parts.push(node("p", { role: "alert", class: "dsmapp-portal-error", text: messages[error.code] || messages.portal_unavailable }));
|
|
146
|
+
element.replaceChildren.apply(element, parts);
|
|
147
|
+
}
|
|
148
|
+
status().then(function (current) { render(current); });
|
|
149
|
+
return {
|
|
150
|
+
refresh: function () { return status().then(function (current) { render(current); }); },
|
|
151
|
+
dispose: function () { disposed = true; element.replaceChildren(); }
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return access;
|
|
155
|
+
}`;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StandaloneManifest } from "./manifest.js";
|
|
2
|
+
import type { PortalPackage } from "../portal/package.js";
|
|
3
|
+
/** A native portal opens the package's own DSM window. */
|
|
4
|
+
export declare function nativePortal(manifest: StandaloneManifest): PortalPackage | undefined;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Capabilities } from "./manifest.js";
|
|
2
2
|
import { type SharedFolder } from "./shared-folder.js";
|
|
3
|
+
import { type PortalPackage } from "../portal/package.js";
|
|
3
4
|
/**
|
|
4
|
-
* `conf/resource` for a native package: only DSM's official `data-share
|
|
5
|
-
* `systemd-user-unit` workers, in a fixed key order.
|
|
5
|
+
* `conf/resource` for a native package: only DSM's official `data-share`,
|
|
6
|
+
* `systemd-user-unit` and `web-config` workers, in a fixed key order.
|
|
7
|
+
* Undefined when none applies.
|
|
6
8
|
*/
|
|
7
9
|
export declare function renderStandaloneResource(m: {
|
|
8
10
|
package: string;
|
|
9
11
|
capabilities: Capabilities;
|
|
10
12
|
sharedFolder?: SharedFolder;
|
|
11
|
-
}): string | undefined;
|
|
13
|
+
}, portal?: PortalPackage): string | undefined;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { sharedFolderResource } from "./shared-folder.js";
|
|
2
|
+
import { portalResource } from "../portal/package.js";
|
|
2
3
|
/**
|
|
3
|
-
* `conf/resource` for a native package: only DSM's official `data-share
|
|
4
|
-
* `systemd-user-unit` workers, in a fixed key order.
|
|
4
|
+
* `conf/resource` for a native package: only DSM's official `data-share`,
|
|
5
|
+
* `systemd-user-unit` and `web-config` workers, in a fixed key order.
|
|
6
|
+
* Undefined when none applies.
|
|
5
7
|
*/
|
|
6
|
-
export function renderStandaloneResource(m) {
|
|
8
|
+
export function renderStandaloneResource(m, portal) {
|
|
7
9
|
const dataShare = m.sharedFolder && sharedFolderResource(m.package, m.sharedFolder);
|
|
8
10
|
const resource = {
|
|
9
11
|
...(dataShare ? { "data-share": dataShare } : {}),
|
|
10
12
|
...(m.capabilities.jobs ? { "systemd-user-unit": {} } : {}),
|
|
13
|
+
...(portal ? portalResource() : {}),
|
|
11
14
|
};
|
|
12
15
|
return Object.keys(resource).length > 0 ? JSON.stringify(resource) : undefined;
|
|
13
16
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { bootDefinition, controlDefinition } from '../runtime/executor-tasks.js';
|
|
2
|
+
import { executorScopeTask } from '../runtime/executor-scope-task.js';
|
|
2
3
|
export { executorTasks as rootTasks } from '../runtime/executor-tasks.js';
|
|
3
4
|
/** Exact readback is authoritative. PasswordConfirm tokens are reused immediately,
|
|
4
5
|
* across both Root APIs, and never persisted (DSM validity is about 300 seconds). */
|
|
@@ -10,15 +11,9 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
10
11
|
var code = String(e && e.code || "executor_bad_response");
|
|
11
12
|
return code + (code === "105" || code === "dsm_105" ? ": DSM denied administrator scheduler access. Check the DSM session and scheduler; a NAS restart resolved this on the measured DSM. No automatic retry was made." : ": scheduler readback or operation failed.");
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
var value = params[key];
|
|
17
|
-
encoded[key] = value === "" || typeof value === "boolean" || typeof value === "object" ? JSON.stringify(value) : value;
|
|
18
|
-
});
|
|
19
|
-
return encoded;
|
|
20
|
-
}
|
|
21
|
-
function send(api, method, version, params) { return options.send(api, method, version, wire(params || {})); }
|
|
14
|
+
// AppWindow.sendWebAPI encodes JSON parameters. Preserve their native types;
|
|
15
|
+
// pre-encoding turns objects/booleans into strings and DSM rejects create.
|
|
16
|
+
function send(api, method, version, params) { return options.send(api, method, version, params || {}); }
|
|
22
17
|
function admin() { if (!options.user() || options.user().admin !== true) throw fail("admin_required"); }
|
|
23
18
|
function find(task) {
|
|
24
19
|
var boot = task.kind === "boot";
|
|
@@ -55,10 +50,12 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
55
50
|
});
|
|
56
51
|
}
|
|
57
52
|
function definition(task) { return task.kind === "boot" ? (${bootDefinition.toString()})(task) : (${controlDefinition.toString()})(task); }
|
|
58
|
-
function approve(password) {
|
|
53
|
+
function approve(password, selectedScope) {
|
|
54
|
+
var selectionTask;
|
|
55
|
+
if (selectedScope !== undefined) selectionTask = (${executorScopeTask.toString()})(options.pins, selectedScope, options.user() && options.user().name, 0);
|
|
59
56
|
return read().then(function (before) {
|
|
60
57
|
if (before.state === "blocked" || before.state === "unsupported") return before;
|
|
61
|
-
if (before.state === "ready") return start(before);
|
|
58
|
+
if (before.state === "ready" && !selectionTask) return start(before);
|
|
62
59
|
return options.confirmPassword(password).then(function (confirmation) {
|
|
63
60
|
if (!confirmation || confirmation.confirmed !== true) return {state: "cancelled", tasks: before.tasks};
|
|
64
61
|
if (typeof confirmation.token !== "string" || !confirmation.token) throw fail("executor_confirmation_missing");
|
|
@@ -84,15 +81,65 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
84
81
|
Object.keys(errors).forEach(function (kind) {
|
|
85
82
|
if (after.tasks[kind].state !== "ready") { after.tasks[kind].state = "blocked"; after.tasks[kind].reason = errors[kind]; after.state = "blocked"; after.reason = errors[kind]; }
|
|
86
83
|
});
|
|
87
|
-
|
|
84
|
+
// A scope change must not restart a running executor: the boot task
|
|
85
|
+
// stops it, which interrupts in-flight copies instead of canceling them.
|
|
86
|
+
return after.state === "ready" ? (selectionTask ? running(after) : Promise.resolve(null)).then(function (live) { return live || start(after); }).then(function (started) {
|
|
87
|
+
if (!selectionTask || started.state !== "ready") return started;
|
|
88
|
+
var generation = started.executor.selection ? started.executor.selection.generation : 0;
|
|
89
|
+
if (started.executor.selection && (!Number.isSafeInteger(generation) || generation <= 0)) throw fail("executor_selection_invalid");
|
|
90
|
+
selectionTask = (${executorScopeTask.toString()})(options.pins, selectedScope, options.user() && options.user().name, generation);
|
|
91
|
+
// The root task may still land after this reply. requested lets the
|
|
92
|
+
// app converge by readback: applied once status().executor.selection
|
|
93
|
+
// shows this scope above this generation. A resubmit is pinned and safe.
|
|
94
|
+
return selectScope(selectionTask, confirmation, started, selectedScope).catch(function (e) {
|
|
95
|
+
return {state: "blocked", reason: reason(e), tasks: started.tasks, requested: {scope: selectedScope, generation: generation}};
|
|
96
|
+
});
|
|
97
|
+
}) : after;
|
|
88
98
|
});
|
|
89
99
|
});
|
|
90
100
|
});
|
|
91
101
|
}
|
|
102
|
+
function selectScope(task, confirmation, verified, selectedScope) {
|
|
103
|
+
function removeExact() {
|
|
104
|
+
return find(task).then(function (current) {
|
|
105
|
+
if (current.state === "ready") return send(taskAPI, "delete", 2, {tasks: [current.ref]});
|
|
106
|
+
if (current.ref) throw fail("executor_selection_cleanup_conflict");
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return find(task).then(function (current) {
|
|
110
|
+
if (current.state === "blocked" || current.state === "unsupported") throw fail("executor_selection_conflict");
|
|
111
|
+
var removed = current.ref ? send(taskAPI, "delete", 2, {tasks: [current.ref]}) : Promise.resolve();
|
|
112
|
+
return removed.then(function () {
|
|
113
|
+
var params = definition(task); params.SynoConfirmPWToken = confirmation.token;
|
|
114
|
+
return send(taskAPI + ".Root", "create", 4, params);
|
|
115
|
+
});
|
|
116
|
+
}).then(function () { return find(task); }).then(function (current) {
|
|
117
|
+
if (current.state !== "ready") throw fail("executor_selection_readback_mismatch");
|
|
118
|
+
return send(taskAPI, "run", 2, {tasks: [current.ref]});
|
|
119
|
+
}).then(function () {
|
|
120
|
+
function readSelection(attempts) {
|
|
121
|
+
return health(verified, 1).then(function (current) {
|
|
122
|
+
if (current.state === "ready" && current.executor.selection && current.executor.selection.scope === selectedScope && Number.isSafeInteger(current.executor.selection.generation) && current.executor.selection.generation > 0) return current;
|
|
123
|
+
if (attempts > 1 && options.wait) return options.wait(500).then(function () { verified.state = "ready"; return readSelection(attempts - 1); });
|
|
124
|
+
throw fail("executor_selection_unconfirmed");
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return readSelection(40);
|
|
128
|
+
}).then(function (result) { return removeExact().then(function () { return result; }); }, function (error) {
|
|
129
|
+
return removeExact().then(function () { throw error; });
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function pinned(status) { return !!status && status.ready === true && !!options.pins && status.executor_digest === options.pins.executorDigest && status.policy_digest === options.pins.policyDigest; }
|
|
133
|
+
function running(verified) {
|
|
134
|
+
return options.call("executor.status", {}).then(function (status) {
|
|
135
|
+
if (!pinned(status)) return null;
|
|
136
|
+
verified.executor = status; return verified;
|
|
137
|
+
}, function () { return null; });
|
|
138
|
+
}
|
|
92
139
|
function health(verified, attempts) {
|
|
93
140
|
if (verified.state !== "ready") return Promise.resolve(verified);
|
|
94
141
|
return options.call("executor.status", {}).then(function (status) {
|
|
95
|
-
if (!status
|
|
142
|
+
if (!pinned(status)) throw fail("executor_status_mismatch");
|
|
96
143
|
verified.executor = status; return verified;
|
|
97
144
|
}).catch(function (e) {
|
|
98
145
|
if (attempts > 1 && options.wait) return options.wait(500).then(function () { return health(verified, attempts - 1); });
|
|
@@ -109,8 +156,8 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
109
156
|
}
|
|
110
157
|
return {
|
|
111
158
|
status: function () { return read().then(function (verified) { return health(verified, 1); }); },
|
|
112
|
-
authorize: function (password) {
|
|
113
|
-
if (!busy) busy = approve(password).catch(function (e) { return {state: "blocked", reason: reason(e), tasks: {}}; }).then(function (r) { busy = null; return r; });
|
|
159
|
+
authorize: function (password, selectedScope) {
|
|
160
|
+
if (!busy) busy = Promise.resolve().then(function () { return approve(password, selectedScope); }).catch(function (e) { return {state: "blocked", reason: reason(e), tasks: {}}; }).then(function (r) { busy = null; return r; });
|
|
114
161
|
return busy;
|
|
115
162
|
},
|
|
116
163
|
control: function (action) {
|
package/dist/standalone/spk.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface AssembleOptions {
|
|
|
14
14
|
outputPath: string;
|
|
15
15
|
executor?: ExecutorArtifact;
|
|
16
16
|
daemonControl?: string;
|
|
17
|
-
/** The compiled background worker, required exactly when
|
|
17
|
+
/** The compiled background worker, required exactly when capabilities.jobs is enabled. */
|
|
18
18
|
backgroundWorker?: string;
|
|
19
19
|
}
|
|
20
20
|
/**
|
package/dist/standalone/spk.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { metadataInfoFields } from "../package-metadata.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
3
4
|
import { tmpdir } from "node:os";
|
|
@@ -8,6 +9,7 @@ import { renderNativePrivilege } from "../build-spk/native-lifecycle.js";
|
|
|
8
9
|
import { renderUninstallWizardFiles } from "../build-spk/uninstall-wizard.js";
|
|
9
10
|
import { renderInstallWizardFiles, renderNativeInstallWizard } from "../build-spk/install-wizard.js";
|
|
10
11
|
import { writeWizardUiFiles } from "../build-spk/wizard-i18n.js";
|
|
12
|
+
import { renderDelegateScopeSteps } from '../build-spk/delegate-scope.js';
|
|
11
13
|
import { createReproducibleTar } from "../build-spk/reproducible-archive.js";
|
|
12
14
|
import { renderStandaloneScript } from "./lifecycle.js";
|
|
13
15
|
import { DSM_LANGS, LOCALES } from "./i18n.js";
|
|
@@ -17,7 +19,10 @@ import { hostScriptName, renderHostAdapterScript } from "./host-adapter.js";
|
|
|
17
19
|
import { copyDaemonPayload } from "./daemon.js";
|
|
18
20
|
import { BACKGROUND_UNIT_DIR, BACKGROUND_WORKER_PAYLOAD, backgroundUnitName, renderBackgroundUnit } from "./background.js";
|
|
19
21
|
import { renderStandaloneResource } from "./resource.js";
|
|
22
|
+
import { nativePortal } from "./portal.js";
|
|
23
|
+
import { PORTAL_JSON_RELPATH, PORTAL_MUSTACHE_RELPATH, renderPortalJson, renderPortalMustache, renderPortalWizardStep } from "../portal/package.js";
|
|
20
24
|
import { executorPlan } from "../runtime/executor-build.js";
|
|
25
|
+
import { EXECUTOR_ANCHOR } from "../runtime/executor-inspect.js";
|
|
21
26
|
import { renderSharedFolderUpgradeWizardFiles, sharedFolderInstallSteps } from "./shared-folder.js";
|
|
22
27
|
const FILE_MODE = 0o644;
|
|
23
28
|
const EXEC_MODE = 0o755;
|
|
@@ -77,6 +82,11 @@ export async function assembleStandaloneSpk(options) {
|
|
|
77
82
|
copyStandaloneNotices(manifest.root, manifest.ui.dir, join(staging, 'package'), manifest.backend.kind === 'go' || Boolean(manifest.daemon), manifest.backend.kind === 'go' ? manifest.backend.dir : undefined);
|
|
78
83
|
if (manifest.daemon)
|
|
79
84
|
copyFileSync(new URL('../../templates/_shared/LICENSES/TEMPLATE.txt', import.meta.url), join(staging, 'package', 'LICENSES', 'DAEMON-LICENSE.txt'));
|
|
85
|
+
const portal = nativePortal(manifest);
|
|
86
|
+
if (portal) {
|
|
87
|
+
writeFile(join(staging, "package", PORTAL_JSON_RELPATH), renderPortalJson(portal));
|
|
88
|
+
writeFile(join(staging, "package", PORTAL_MUSTACHE_RELPATH), renderPortalMustache());
|
|
89
|
+
}
|
|
80
90
|
if (options.executor) {
|
|
81
91
|
const executorDir = join(staging, "package", "executor");
|
|
82
92
|
mkdirSync(executorDir);
|
|
@@ -93,11 +103,11 @@ export async function assembleStandaloneSpk(options) {
|
|
|
93
103
|
await createReproducibleTar(join(staging, "package"), packageTgz, { gzip: true });
|
|
94
104
|
rmSync(join(staging, "package"), { recursive: true, force: true });
|
|
95
105
|
const checksum = createHash("md5").update(readFileSync(packageTgz)).digest("hex");
|
|
96
|
-
writeFile(join(staging, "sdk-package.json"), JSON.stringify({ schema: 2, backend: manifest.backend.kind, capabilities: Object.keys(manifest.capabilities).sort() }));
|
|
97
|
-
writeFile(join(staging, "INFO"), renderInfo(manifest, options.arch, checksum));
|
|
106
|
+
writeFile(join(staging, "sdk-package.json"), JSON.stringify({ schema: 2, backend: manifest.backend.kind, capabilities: Object.keys(manifest.capabilities).sort(), ...(manifest.entry ? { entry: manifest.entry } : {}) }));
|
|
107
|
+
writeFile(join(staging, "INFO"), renderInfo(manifest, options.arch, checksum, options.executor?.executorDigest));
|
|
98
108
|
mkdirSync(join(staging, "conf"));
|
|
99
109
|
writeFile(join(staging, "conf", "privilege"), renderNativePrivilege());
|
|
100
|
-
const resource = renderStandaloneResource(manifest);
|
|
110
|
+
const resource = renderStandaloneResource(manifest, portal);
|
|
101
111
|
if (resource)
|
|
102
112
|
writeFile(join(staging, "conf", "resource"), resource);
|
|
103
113
|
if (manifest.capabilities.jobs) {
|
|
@@ -109,7 +119,10 @@ export async function assembleStandaloneSpk(options) {
|
|
|
109
119
|
writeFile(join(staging, "scripts", name), renderStandaloneScript(name, manifest), EXEC_MODE);
|
|
110
120
|
}
|
|
111
121
|
const folder = manifest.sharedFolder;
|
|
112
|
-
const
|
|
122
|
+
const steps = manifest.capabilities.delegate?.scope === 'install-selected'
|
|
123
|
+
? (t) => [...renderDelegateScopeSteps(t), ...(folder ? sharedFolderInstallSteps(manifest.package, folder)(t) : [])]
|
|
124
|
+
: folder ? sharedFolderInstallSteps(manifest.package, folder) : renderNativeInstallWizard;
|
|
125
|
+
const install = renderInstallWizardFiles(manifest.package, portal ? (t) => [...steps(t), renderPortalWizardStep(t, portal.alias)] : steps);
|
|
113
126
|
writeWizardUiFiles(staging, {
|
|
114
127
|
...install.static,
|
|
115
128
|
...install.dynamic,
|
|
@@ -130,10 +143,10 @@ function writeFile(path, content, mode = FILE_MODE) {
|
|
|
130
143
|
chmodSync(path, mode);
|
|
131
144
|
}
|
|
132
145
|
function quote(value) {
|
|
133
|
-
return `"${value}"`;
|
|
146
|
+
return `"${value.replace(/([\\"$`])/g, "\\$1")}"`;
|
|
134
147
|
}
|
|
135
148
|
/** Manifest validation already refused quotes, backslashes and newlines. */
|
|
136
|
-
function renderInfo(manifest, arch, checksum) {
|
|
149
|
+
function renderInfo(manifest, arch, checksum, executorDigest) {
|
|
137
150
|
const fields = [
|
|
138
151
|
["package", manifest.package],
|
|
139
152
|
["version", manifest.spkVersion],
|
|
@@ -148,7 +161,12 @@ function renderInfo(manifest, arch, checksum) {
|
|
|
148
161
|
["startable", "yes"],
|
|
149
162
|
["checksum", checksum],
|
|
150
163
|
];
|
|
151
|
-
|
|
164
|
+
// Package Center writes INFO as root; root tasks accept only this executor.
|
|
165
|
+
if (executorDigest)
|
|
166
|
+
fields.push([EXECUTOR_ANCHOR, executorDigest]);
|
|
167
|
+
fields.push(...metadataInfoFields(manifest.metadata));
|
|
168
|
+
// Background packages need prestart: it runs before DSM's systemd-user-unit acquire.
|
|
169
|
+
if (manifest.daemon || manifest.capabilities.jobs)
|
|
152
170
|
fields.push(["precheckstartstop", "yes"]);
|
|
153
171
|
for (const locale of LOCALES) {
|
|
154
172
|
const text = manifest.i18n?.info[locale];
|
|
@@ -41,9 +41,15 @@ func fixture(t *testing.T, mode string) (string, string, string) {
|
|
|
41
41
|
if err != nil {
|
|
42
42
|
t.Fatal(err)
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
app := filepath.Join(dest, "daemon/payload/app")
|
|
45
|
+
if err := os.WriteFile(app, raw, 0755); err != nil {
|
|
45
46
|
t.Fatal(err)
|
|
46
47
|
}
|
|
48
|
+
// macOS verifies a newly written executable on its first exec, which takes
|
|
49
|
+
// seconds on a loaded host; pay it here, not inside a one-second budget.
|
|
50
|
+
if raw, err := exec.Command(app, "cleanup").CombinedOutput(); err != nil {
|
|
51
|
+
t.Fatalf("payload warm-up: %v %s", err, raw)
|
|
52
|
+
}
|
|
47
53
|
cfg := config{Package: "DaemonFixture", Exec: "app", Args: []string{"${SYNOPKG_PKGVAR}/a space", "$(touch BAD)'", "${SYNOPKG_PKGDEST}"}, Env: map[string]string{"APP_MODE": mode}, Timeouts: deadlines{Start: 2, Stop: 2, Status: 1}}
|
|
48
54
|
if os.Geteuid() == 0 {
|
|
49
55
|
cfg.Package = "nobody"
|
|
@@ -91,22 +97,69 @@ func runControl(control, action, dest, data string) (int, string) {
|
|
|
91
97
|
return -1, err.Error()
|
|
92
98
|
}
|
|
93
99
|
|
|
100
|
+
// Readiness only proves the child stayed alive for a second, not that it reached
|
|
101
|
+
// main: on a loaded host a stop can kill it before it writes its line. Spawn
|
|
102
|
+
// identity therefore comes from the inventory, and log content is awaited.
|
|
103
|
+
func recordedChild(t *testing.T, data string) int {
|
|
104
|
+
t.Helper()
|
|
105
|
+
raw, err := os.ReadFile(filepath.Join(data, "daemon/daemon.pid"))
|
|
106
|
+
if err != nil {
|
|
107
|
+
t.Fatal(err)
|
|
108
|
+
}
|
|
109
|
+
var r record
|
|
110
|
+
if err := json.Unmarshal(raw, &r); err != nil || r.Child < 1 {
|
|
111
|
+
t.Fatalf("daemon inventory: %v %s", err, raw)
|
|
112
|
+
}
|
|
113
|
+
return r.Child
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func awaitChildLines(t *testing.T, data string, want int) {
|
|
117
|
+
t.Helper()
|
|
118
|
+
path := filepath.Join(data, "daemon/daemon.log")
|
|
119
|
+
for deadline := time.Now().Add(10 * time.Second); ; time.Sleep(20 * time.Millisecond) {
|
|
120
|
+
raw, _ := os.ReadFile(path)
|
|
121
|
+
if got := strings.Count(string(raw), `"uid":`); got >= want || time.Now().After(deadline) {
|
|
122
|
+
if got != want {
|
|
123
|
+
t.Fatalf("child lines=%d want=%d: %s", got, want, raw)
|
|
124
|
+
}
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
94
130
|
func TestDaemonLifecycle(t *testing.T) {
|
|
95
131
|
control, dest, data := fixture(t, "normal")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
want
|
|
99
|
-
|
|
100
|
-
if rc, out := runControl(control, step.action, dest, data); rc != step.want {
|
|
101
|
-
t.Fatalf("%s rc=%d want=%d: %s", step.action, rc, step.want, out)
|
|
132
|
+
step := func(action string, want int) {
|
|
133
|
+
t.Helper()
|
|
134
|
+
if rc, out := runControl(control, action, dest, data); rc != want {
|
|
135
|
+
t.Fatalf("%s rc=%d want=%d: %s", action, rc, want, out)
|
|
102
136
|
}
|
|
103
137
|
}
|
|
138
|
+
step("status", 3)
|
|
139
|
+
step("stop", 0)
|
|
140
|
+
step("start", 0)
|
|
141
|
+
awaitChildLines(t, data, 1)
|
|
142
|
+
first := recordedChild(t, data)
|
|
143
|
+
step("status", 0)
|
|
144
|
+
step("start", 0)
|
|
145
|
+
if child := recordedChild(t, data); child != first {
|
|
146
|
+
t.Fatalf("duplicate start spawned another child: %d replaced %d", child, first)
|
|
147
|
+
}
|
|
148
|
+
step("restart", 0)
|
|
149
|
+
if child := recordedChild(t, data); child == first {
|
|
150
|
+
t.Fatalf("restart kept child %d", child)
|
|
151
|
+
}
|
|
152
|
+
awaitChildLines(t, data, 2)
|
|
153
|
+
step("stop", 0)
|
|
154
|
+
step("stop", 0)
|
|
155
|
+
step("status", 3)
|
|
156
|
+
step("unknown", 1)
|
|
104
157
|
raw, err := os.ReadFile(filepath.Join(data, "daemon/daemon.log"))
|
|
105
158
|
if err != nil {
|
|
106
159
|
t.Fatal(err)
|
|
107
160
|
}
|
|
108
161
|
if strings.Count(string(raw), `"uid":`) != 2 {
|
|
109
|
-
t.Fatalf("
|
|
162
|
+
t.Fatalf("unexpected child spawn: %s", raw)
|
|
110
163
|
}
|
|
111
164
|
if strings.Contains(string(raw), "must-not-leak") {
|
|
112
165
|
t.Fatalf("ambient environment leaked: %s", raw)
|