@synopackageland/cli 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +846 -0
- package/README.md +81 -89
- package/dist/add.d.ts +4 -1
- package/dist/add.js +45 -17
- 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 +42 -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.js +8 -4
- package/dist/build-spk/generator.js +30 -5
- package/dist/build-spk/go-toolchain.d.ts +20 -0
- package/dist/build-spk/go-toolchain.js +44 -0
- 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 +28 -14
- 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/native-install-values.d.ts +17 -0
- package/dist/deploy/native-install-values.js +32 -0
- package/dist/deploy/plan.d.ts +6 -2
- package/dist/deploy/plan.js +58 -7
- package/dist/deploy/spk-version.js +1 -1
- package/dist/error-registry.js +54 -20
- package/dist/host/dsm-client.d.ts +8 -4
- package/dist/host/dsm-client.js +63 -21
- package/dist/host/dsm-http.js +24 -2
- package/dist/host/types.d.ts +3 -1
- package/dist/info.js +45 -10
- package/dist/init.d.ts +3 -0
- package/dist/init.js +50 -19
- 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/dsm-version.d.ts +6 -0
- package/dist/runtime/dsm-version.js +8 -0
- package/dist/runtime/executor-build.js +10 -6
- 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 -0
- package/dist/standalone/daemon.js +10 -5
- package/dist/standalone/dsm-window.d.ts +3 -1
- package/dist/standalone/dsm-window.js +78 -49
- package/dist/standalone/inspect-spk.d.ts +8 -0
- package/dist/standalone/inspect-spk.js +110 -27
- 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 +9 -1
- package/dist/standalone/native-layout.d.ts +3 -0
- package/dist/standalone/native-layout.js +37 -5
- package/dist/standalone/native-root-window.d.ts +4 -2
- package/dist/standalone/native-root-window.js +33 -18
- 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.d.ts +4 -1
- package/dist/standalone/root-window.js +193 -36
- package/dist/standalone/spk.d.ts +1 -1
- package/dist/standalone/spk.js +25 -7
- package/dist/templates/_daemon/go.mod +1 -1
- package/dist/templates/_daemon/main.go +6 -3
- package/dist/templates/_daemon/main_test.go +82 -9
- package/dist/templates/_daemon/testdata/child.go +3 -0
- package/dist/templates/_executor/README.md +130 -16
- package/dist/templates/_executor/anchor.go +156 -0
- package/dist/templates/_executor/anchor_test.go +161 -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/digest_review_test.go +2 -2
- package/dist/templates/_executor/dsm.go +63 -13
- 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/go.mod +2 -0
- 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 +83 -25
- package/dist/templates/_executor/managed.go +3 -3
- package/dist/templates/_executor/managed_test.go +3 -3
- 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/path_test.go +18 -0
- package/dist/templates/_executor/pid.go +37 -0
- package/dist/templates/_executor/pid_test.go +113 -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 +38 -4
- package/dist/templates/_executor/process.go +3 -0
- package/dist/templates/_executor/purge_log.go +18 -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 +52 -15
- package/dist/templates/_executor/tasks_dsm71_test.go +114 -0
- package/dist/templates/_executor/tasks_review_test.go +1 -1
- package/dist/templates/_executor/tasks_test.go +62 -5
- package/dist/templates/_executor/upgrade_watch_test.go +13 -5
- 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/_gateway/go.mod +2 -0
- 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/go.mod +1 -1
- 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/client.go +39 -3
- package/dist/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -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/identity/README.md +5 -1
- package/dist/templates/native-go/backend/internal/identity/dsm.go +24 -5
- package/dist/templates/native-go/backend/internal/identity/http.go +1 -1
- package/dist/templates/native-go/backend/internal/identity/identity_test.go +48 -1
- package/dist/templates/native-go/backend/internal/identity/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/delegate.test.ts +15 -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-root-ops/backend/internal/app/executor.go +30 -2
- package/dist/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
- 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 +54 -9
- 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-settings.test.ts +23 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -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 +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -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 +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -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/go.mod +1 -1
- package/templates/_daemon/main.go +6 -3
- package/templates/_daemon/main_test.go +82 -9
- package/templates/_daemon/testdata/child.go +3 -0
- package/templates/_executor/README.md +130 -16
- package/templates/_executor/anchor.go +156 -0
- package/templates/_executor/anchor_test.go +161 -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/digest_review_test.go +2 -2
- package/templates/_executor/dsm.go +63 -13
- 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/go.mod +2 -0
- 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 +83 -25
- package/templates/_executor/managed.go +3 -3
- package/templates/_executor/managed_test.go +3 -3
- 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/path_test.go +18 -0
- package/templates/_executor/pid.go +37 -0
- package/templates/_executor/pid_test.go +113 -0
- package/templates/_executor/platform_linux.go +24 -173
- package/templates/_executor/platform_linux_test.go +9 -65
- package/templates/_executor/platform_other.go +38 -4
- package/templates/_executor/process.go +3 -0
- package/templates/_executor/purge_log.go +18 -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 +52 -15
- package/templates/_executor/tasks_dsm71_test.go +114 -0
- package/templates/_executor/tasks_review_test.go +1 -1
- package/templates/_executor/tasks_test.go +62 -5
- package/templates/_executor/upgrade_watch_test.go +13 -5
- 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/_gateway/go.mod +2 -0
- 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/go.mod +1 -1
- 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/client.go +39 -3
- package/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -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/identity/README.md +5 -1
- package/templates/native-go/backend/internal/identity/dsm.go +24 -5
- package/templates/native-go/backend/internal/identity/http.go +1 -1
- package/templates/native-go/backend/internal/identity/identity_test.go +48 -1
- package/templates/native-go/backend/internal/identity/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/delegate.test.ts +15 -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-root-ops/backend/internal/app/executor.go +30 -2
- package/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
- 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 +54 -9
- 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-settings.test.ts +23 -0
- package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -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 +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
- package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -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 +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -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
|
@@ -4,6 +4,8 @@ export const AUTHORIZATION_RUNTIME = `function createAuthorizationAccess(options
|
|
|
4
4
|
function fail(code) { var error = new Error(code); error.code = code; return error; }
|
|
5
5
|
function status() { return options.call("authorization.status").then(function (d) {
|
|
6
6
|
if (!d || d.command !== "authorization" || d.schema_version !== 1 || ["ready","authorization_required","not_admin","session_expired","unavailable"].indexOf(d.state) < 0) throw fail("authorization_bad_response");
|
|
7
|
+
// upgrade_reapproval is a reason-only tombstone: it can only explain a pending request.
|
|
8
|
+
if (d.reason === "upgrade_reapproval" && d.state !== "authorization_required") throw fail("authorization_bad_response");
|
|
7
9
|
return d;
|
|
8
10
|
}); }
|
|
9
11
|
function plan(method) { return options.call(method).then(function (p) {
|
|
@@ -12,9 +14,15 @@ export const AUTHORIZATION_RUNTIME = `function createAuthorizationAccess(options
|
|
|
12
14
|
p.operations.forEach(function (op) { if (seen[op] || !options.tasks.some(function (t) { return t.op === op; })) throw fail("authorization_bad_response"); seen[op] = true; });
|
|
13
15
|
return p;
|
|
14
16
|
}); }
|
|
17
|
+
// The backend's grant decides: a task still waiting at the window's limit, or
|
|
18
|
+
// one signalled after it wrote the grant, has still authorized the package.
|
|
19
|
+
function settled(e) {
|
|
20
|
+
if (!e || (e.code !== "root_timeout" && e.code !== "root_task_failed")) throw e;
|
|
21
|
+
return status().then(function (d) { if (d.state !== "ready") throw e; });
|
|
22
|
+
}
|
|
15
23
|
function exclusive(fn) { if (busy) return busy; busy = Promise.resolve().then(fn).then(function (s) { busy = null; return s; },function (e) { busy = null; throw e; });return busy; }
|
|
16
24
|
function authorize(ops,run) { return ops.reduce(function (previous,op) { return previous.then(function () {
|
|
17
|
-
return options.root.authorize(op).then(function (state) { if (state !== "ready") throw fail("root_cancelled"); return run ? options.root.run(op) : null; });
|
|
25
|
+
return options.root.authorize(op).then(function (state) { if (state !== "ready") throw fail("root_cancelled"); return run ? options.root.run(op).catch(settled) : null; });
|
|
18
26
|
}); },Promise.resolve()); }
|
|
19
27
|
return {canManage:function () {return !!options.user && options.user().admin === true;},status:status,request:function () { return exclusive(function () {
|
|
20
28
|
return plan("authorization.request").then(function (p) { return authorize(p.operations,p.run === true); }).then(status,function (e) { if (e.code === "root_cancelled") return status();throw e; });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PackageMetadata } from "../package-metadata.js";
|
|
1
2
|
import type { CommandRunner } from './build.js';
|
|
2
3
|
export declare const LAYOUT_ARCHES: {
|
|
3
4
|
readonly x86_64: readonly [2, 62];
|
|
@@ -21,6 +22,7 @@ type Binary = {
|
|
|
21
22
|
arches?: LayoutArch[];
|
|
22
23
|
};
|
|
23
24
|
export interface NativeLayout {
|
|
25
|
+
metadata?: PackageMetadata;
|
|
24
26
|
root: string;
|
|
25
27
|
package: string;
|
|
26
28
|
version: string;
|
|
@@ -39,6 +41,7 @@ export interface NativeLayout {
|
|
|
39
41
|
payload: string;
|
|
40
42
|
metadata: string;
|
|
41
43
|
binaries: Binary[];
|
|
44
|
+
anchors?: Record<string, string>;
|
|
42
45
|
};
|
|
43
46
|
native: {
|
|
44
47
|
prepare?: Hook;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateMetadata, metadataInfoFields } from "../package-metadata.js";
|
|
1
2
|
/** Existing native products: the CLI owns archives/INFO, the project owns its layout. */
|
|
2
3
|
import { createHash } from 'node:crypto';
|
|
3
4
|
import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
@@ -36,6 +37,20 @@ function inside(root, path) {
|
|
|
36
37
|
fail('path escapes project');
|
|
37
38
|
return full;
|
|
38
39
|
}
|
|
40
|
+
// Package Center writes INFO as root, so product root helpers can trust these
|
|
41
|
+
// payload digests across upgrades. The synopkgland_ prefix stays reserved.
|
|
42
|
+
function anchors(value) {
|
|
43
|
+
const a = object(value, Object.keys(value ?? {}));
|
|
44
|
+
if (Object.keys(a).length > 16)
|
|
45
|
+
fail('at most 16 INFO anchors');
|
|
46
|
+
for (const [key, path] of Object.entries(a)) {
|
|
47
|
+
if (!/^[a-z][a-z0-9_]{0,48}_sha256$/.test(key) || key.startsWith('synopkgland_'))
|
|
48
|
+
fail(`invalid INFO anchor key: ${key}`);
|
|
49
|
+
if (pathText(path).includes('{arch}'))
|
|
50
|
+
fail('INFO anchor path is relative to the architecture payload');
|
|
51
|
+
}
|
|
52
|
+
return a;
|
|
53
|
+
}
|
|
39
54
|
function hook(value) {
|
|
40
55
|
const h = object(value, ['command', 'cwd', 'env']);
|
|
41
56
|
if (!Array.isArray(h.command) || !h.command.length || !h.command.every((x) => typeof x === 'string' && x.length > 0 && !x.includes('\0')))
|
|
@@ -56,13 +71,15 @@ export function isNativeLayout(root) {
|
|
|
56
71
|
}
|
|
57
72
|
export function loadNativeLayout(root) {
|
|
58
73
|
try {
|
|
59
|
-
const m = object(parse(readFileSync(join(root, 'dsm-package.yaml'), 'utf8')), ['schema', 'backend', 'package', 'version', 'build', 'displayname', 'description', 'maintainer', 'os_min_ver', 'privilege', 'arches', 'layout', 'native']);
|
|
74
|
+
const m = object(parse(readFileSync(join(root, 'dsm-package.yaml'), 'utf8')), ['schema', 'backend', 'package', 'version', 'build', 'displayname', 'description', 'maintainer', 'metadata', 'os_min_ver', 'privilege', 'arches', 'layout', 'native']);
|
|
60
75
|
if (m.schema !== 2)
|
|
61
76
|
fail('schema 2 required; migrate schema: 1 to schema: 2 and add backend: {kind: native}');
|
|
62
77
|
const backend = object(m.backend, ['kind']);
|
|
63
78
|
if (backend.kind !== 'native' || (m.privilege !== undefined && m.privilege !== 'none'))
|
|
64
79
|
fail('backend.kind: native and package-only privilege required');
|
|
65
80
|
m.privilege = 'none';
|
|
81
|
+
if (m.metadata !== undefined)
|
|
82
|
+
m.metadata = validateMetadata(m.metadata);
|
|
66
83
|
if (existsSync(join(root, 'compose.yaml')))
|
|
67
84
|
fail('compose.yaml and dsm-package.yaml are mutually exclusive');
|
|
68
85
|
if (!/^[A-Za-z][A-Za-z0-9]{1,63}$/.test(text(m.package)) || !/^\d+(\.\d+){0,3}$/.test(text(m.version)) || !/^7\.\d+(\.\d+)?-\d+$/.test(text(m.os_min_ver)))
|
|
@@ -73,11 +90,13 @@ export function loadNativeLayout(root) {
|
|
|
73
90
|
text(m[k]);
|
|
74
91
|
if (!Array.isArray(m.arches) || !m.arches.length || new Set(m.arches).size !== m.arches.length || m.arches.some((a) => !Object.hasOwn(LAYOUT_ARCHES, a)))
|
|
75
92
|
fail('invalid architecture list');
|
|
76
|
-
const layout = object(m.layout, ['payload', 'metadata', 'binaries']);
|
|
93
|
+
const layout = object(m.layout, ['payload', 'metadata', 'binaries', 'anchors']);
|
|
77
94
|
layout.payload = pathText(layout.payload);
|
|
78
95
|
layout.metadata = pathText(layout.metadata);
|
|
79
96
|
if (!Array.isArray(layout.binaries) || !layout.binaries.length)
|
|
80
97
|
fail('binary assertions required');
|
|
98
|
+
if (layout.anchors !== undefined)
|
|
99
|
+
layout.anchors = anchors(layout.anchors);
|
|
81
100
|
for (const b of layout.binaries) {
|
|
82
101
|
object(b, ['path', 'linkage', 'arches']);
|
|
83
102
|
pathText(b.path);
|
|
@@ -300,8 +319,11 @@ export async function buildNativeLayout(options) {
|
|
|
300
319
|
await createReproducibleTar(target, join(stage, 'package.tgz'), { gzip: true });
|
|
301
320
|
rmSync(target, { recursive: true });
|
|
302
321
|
const fields = { package: m.package, version, arch, os_min_ver: m.os_min_ver, displayname: m.displayname, description: m.description, maintainer: m.maintainer, dsmuidir: 'ui', dsmappname: `SYNO.SDS.${m.package}.Instance`, startable: 'yes', thirdparty: 'yes', checksum: createHash('md5').update(readFileSync(join(stage, 'package.tgz'))).digest('hex') };
|
|
303
|
-
|
|
304
|
-
|
|
322
|
+
const info = [...Object.entries(fields), ...metadataInfoFields(m.metadata), ...anchorFields(m.layout.anchors ?? {}, files)];
|
|
323
|
+
if (new Set(info.map(([k]) => k)).size !== info.length)
|
|
324
|
+
fail('INFO anchor collides with an INFO field');
|
|
325
|
+
writeFileSync(join(stage, 'INFO'), info.map(([k, v]) => `${k}="${v.replace(/([\\"$`])/g, '\\$1')}"\n`).join(''));
|
|
326
|
+
writeFileSync(join(stage, 'native-layout.json'), JSON.stringify({ format: 1, arch, binaries: binaries.map(({ path, linkage }) => ({ path, linkage })), files, ...(m.layout.anchors ? { anchors: m.layout.anchors } : {}) }));
|
|
305
327
|
const output = join(options.outDir ?? join(m.root, 'dist'), `${m.package}-${version}-${arch}.spk`);
|
|
306
328
|
mkdirSync(dirname(output), { recursive: true });
|
|
307
329
|
await createReproducibleTar(stage, output);
|
|
@@ -319,7 +341,7 @@ export function inspectNativeLayout(dir, payload, info) {
|
|
|
319
341
|
try {
|
|
320
342
|
if (!/^[A-Za-z][A-Za-z0-9]{1,63}$/.test(info.package ?? '') || !/^\d+(\.\d+){0,3}-\d+$/.test(info.version ?? '') || !/^7\.\d+(\.\d+)?-\d+$/.test(info.os_min_ver ?? ''))
|
|
321
343
|
fail('invalid native INFO identity/version/DSM');
|
|
322
|
-
const inv = object(JSON.parse(readFileSync(join(dir, 'native-layout.json'), 'utf8')), ['format', 'arch', 'binaries', 'files']);
|
|
344
|
+
const inv = object(JSON.parse(readFileSync(join(dir, 'native-layout.json'), 'utf8')), ['format', 'arch', 'binaries', 'files', 'anchors']);
|
|
323
345
|
if (inv.format !== 1 || inv.arch !== info.arch || !Object.hasOwn(LAYOUT_ARCHES, inv.arch))
|
|
324
346
|
fail('invalid native layout inventory');
|
|
325
347
|
checkLayoutMetadata(dir, true, info.package);
|
|
@@ -337,9 +359,19 @@ export function inspectNativeLayout(dir, payload, info) {
|
|
|
337
359
|
}
|
|
338
360
|
if (createHash('md5').update(readFileSync(join(dir, 'package.tgz'))).digest('hex') !== info.checksum)
|
|
339
361
|
fail('package checksum mismatch');
|
|
362
|
+
checkInfoAnchors(readFileSync(join(dir, 'INFO'), 'utf8'), inv.anchors === undefined ? {} : anchors(inv.anchors), actual);
|
|
340
363
|
return [];
|
|
341
364
|
}
|
|
342
365
|
catch (e) {
|
|
343
366
|
return [String(e)];
|
|
344
367
|
}
|
|
345
368
|
}
|
|
369
|
+
function anchorFields(declared, files) {
|
|
370
|
+
return Object.entries(declared).map(([key, path]) => [key, files.find(f => f.path === path)?.sha256 ?? fail(`INFO anchor file missing: ${path}`)]);
|
|
371
|
+
}
|
|
372
|
+
function checkInfoAnchors(info, declared, files) {
|
|
373
|
+
const lines = info.split('\n').filter(line => /^[a-z0-9_]+_sha256=/.test(line));
|
|
374
|
+
const expected = anchorFields(declared, files).map(([key, digest]) => `${key}="${digest}"`);
|
|
375
|
+
if (JSON.stringify(lines.sort()) !== JSON.stringify(expected.sort()))
|
|
376
|
+
fail('INFO anchors do not match the payload');
|
|
377
|
+
}
|
|
@@ -17,10 +17,12 @@ export interface RootTask {
|
|
|
17
17
|
* with exactly the embedded script. The one-use token goes into that single
|
|
18
18
|
* create call and is never kept.
|
|
19
19
|
* - run: re-reads the task and runs it only if it is still exactly ours, then
|
|
20
|
-
* waits for its history entry and asks the backend for the output.
|
|
20
|
+
* waits for its history entry and asks the backend for the output. A queued
|
|
21
|
+
* or running task keeps the wait going, up to RUN_LIMIT_MS (loaded NAS took
|
|
22
|
+
* 4.5 minutes), and `options.progress({op, state, elapsedMs})` hears each poll. Repair
|
|
21
23
|
* additionally requires fresh PasswordConfirm and another exact task check.
|
|
22
24
|
* - an older version of our task is "outdated" and never runs; authorizing
|
|
23
25
|
* again replaces it. A same-named task that is not ours is a "conflict" and
|
|
24
26
|
* is never run, replaced or deleted.
|
|
25
27
|
*/
|
|
26
|
-
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}";
|
|
28
|
+
export declare const ROOT_RUNTIME: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { versionUnsupported } from "../runtime/dsm-version.js";
|
|
1
2
|
/**
|
|
2
3
|
* `createRootAccess(options)` → `{ state, authorize, run, remove }`, plain
|
|
3
4
|
* ES5 for DSM's desktop. Every DSM call goes through `options.send` (the
|
|
@@ -7,7 +8,9 @@
|
|
|
7
8
|
* with exactly the embedded script. The one-use token goes into that single
|
|
8
9
|
* create call and is never kept.
|
|
9
10
|
* - run: re-reads the task and runs it only if it is still exactly ours, then
|
|
10
|
-
* waits for its history entry and asks the backend for the output.
|
|
11
|
+
* waits for its history entry and asks the backend for the output. A queued
|
|
12
|
+
* or running task keeps the wait going, up to RUN_LIMIT_MS (loaded NAS took
|
|
13
|
+
* 4.5 minutes), and `options.progress({op, state, elapsedMs})` hears each poll. Repair
|
|
11
14
|
* additionally requires fresh PasswordConfirm and another exact task check.
|
|
12
15
|
* - an older version of our task is "outdated" and never runs; authorizing
|
|
13
16
|
* again replaces it. A same-named task that is not ours is a "conflict" and
|
|
@@ -15,11 +18,20 @@
|
|
|
15
18
|
*/
|
|
16
19
|
export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
17
20
|
var API = "SYNO.Core.TaskScheduler";
|
|
18
|
-
var POLL_MS = 500,
|
|
21
|
+
var POLL_MS = 500, MAX_POLL_MS = 2000, RUN_LIMIT_MS = 10 * 60 * 1000;
|
|
19
22
|
var byOp = {}, running = {};
|
|
20
23
|
var legacy = null, probe = null;
|
|
24
|
+
var versionUnsupported = ${versionUnsupported.toString()};
|
|
21
25
|
options.tasks.forEach(function (task) { byOp[task.op] = task; });
|
|
22
26
|
|
|
27
|
+
function now() { return options.now ? options.now() : Date.now(); }
|
|
28
|
+
function report(task, state, started) {
|
|
29
|
+
if (typeof options.progress !== "function") return;
|
|
30
|
+
try { options.progress({ op: task.op, state: state, elapsedMs: now() - started }); } catch (error) {}
|
|
31
|
+
}
|
|
32
|
+
function pause(interval, deadline) {
|
|
33
|
+
return options.wait(Math.max(0, Math.min(interval, deadline - now())));
|
|
34
|
+
}
|
|
23
35
|
function fail(code) {
|
|
24
36
|
var error = new Error(code);
|
|
25
37
|
error.code = code;
|
|
@@ -44,7 +56,7 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
44
56
|
legacy = false;
|
|
45
57
|
return data;
|
|
46
58
|
}, function (error) {
|
|
47
|
-
if (!error || (error.code
|
|
59
|
+
if (!error || !versionUnsupported(error.code)) {
|
|
48
60
|
probe = null;
|
|
49
61
|
throw error;
|
|
50
62
|
}
|
|
@@ -119,16 +131,18 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
119
131
|
function history(ref) {
|
|
120
132
|
return options.send(API, "get_history_status_list", 1, { id: ref.id }).then(newest);
|
|
121
133
|
}
|
|
122
|
-
function waitForRun(ref, before,
|
|
134
|
+
function waitForRun(task, ref, before, started, deadline, interval) {
|
|
123
135
|
return history(ref).then(function (latest) {
|
|
124
|
-
var
|
|
125
|
-
|
|
126
|
-
if (finished) {
|
|
136
|
+
var fresh = latest && (!before || latest.timestamp !== before.timestamp);
|
|
137
|
+
if (fresh && latest.exit_type !== "running" && latest.stop_time) {
|
|
127
138
|
if (latest.exit_code !== 0) throw fail("root_task_failed");
|
|
128
139
|
return;
|
|
129
140
|
}
|
|
130
|
-
|
|
131
|
-
|
|
141
|
+
report(task, fresh ? "running" : "queued", started);
|
|
142
|
+
if (now() >= deadline) throw fail("root_timeout");
|
|
143
|
+
return pause(interval, deadline).then(function () {
|
|
144
|
+
return waitForRun(task, ref, before, started, deadline, Math.min(interval * 2, MAX_POLL_MS));
|
|
145
|
+
});
|
|
132
146
|
});
|
|
133
147
|
}
|
|
134
148
|
|
|
@@ -141,12 +155,12 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
141
155
|
function bounded(call, deadline) {
|
|
142
156
|
// A poll count alone cannot bound a stalled DSM callback. Discard late replies.
|
|
143
157
|
return new Promise(function (resolve, reject) {
|
|
144
|
-
var remaining = deadline -
|
|
158
|
+
var remaining = deadline - now();
|
|
145
159
|
if (remaining <= 0) { reject(fail("root_timeout")); return; }
|
|
146
160
|
var timer = setTimeout(function () { reject(fail("root_timeout")); }, remaining);
|
|
147
161
|
Promise.resolve().then(call).then(function (value) {
|
|
148
162
|
clearTimeout(timer);
|
|
149
|
-
if (
|
|
163
|
+
if (now() >= deadline) reject(fail("root_timeout"));
|
|
150
164
|
else resolve(value);
|
|
151
165
|
}, function (error) { clearTimeout(timer); reject(error); });
|
|
152
166
|
});
|
|
@@ -167,7 +181,7 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
167
181
|
return records;
|
|
168
182
|
});
|
|
169
183
|
}
|
|
170
|
-
function waitForLegacyRun(ref, before, deadline,
|
|
184
|
+
function waitForLegacyRun(task, ref, before, started, deadline, interval) {
|
|
171
185
|
return legacyHistory(ref, deadline).then(function (records) {
|
|
172
186
|
var previous = before.map(function (record) { return record.start_time; });
|
|
173
187
|
var newestBefore = previous.slice().sort().pop();
|
|
@@ -178,24 +192,25 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
178
192
|
if (latest.exit_code !== 0 || latest.exit_type !== "normal") throw fail("root_task_failed");
|
|
179
193
|
return;
|
|
180
194
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
195
|
+
report(task, latest ? "running" : "queued", started);
|
|
196
|
+
if (now() >= deadline) throw fail("root_timeout");
|
|
197
|
+
return pause(interval, deadline).then(function () {
|
|
198
|
+
return waitForLegacyRun(task, ref, before, started, deadline, Math.min(interval * 2, MAX_POLL_MS));
|
|
184
199
|
});
|
|
185
200
|
});
|
|
186
201
|
}
|
|
187
202
|
function execute(task, verified) {
|
|
203
|
+
var started = now(), deadline = started + RUN_LIMIT_MS;
|
|
188
204
|
if (!legacy) {
|
|
189
205
|
return history(verified.ref).then(function (before) {
|
|
190
|
-
return runTask(verified.ref).then(function () { return waitForRun(verified.ref, before,
|
|
206
|
+
return runTask(verified.ref).then(function () { return waitForRun(task, verified.ref, before, started, deadline, POLL_MS); });
|
|
191
207
|
});
|
|
192
208
|
}
|
|
193
|
-
var deadline = Date.now() + POLL_MS * POLLS;
|
|
194
209
|
return legacyHistory(verified.ref, deadline).then(function (before) {
|
|
195
210
|
if (before.some(function (record) { return !record.stop_time || record.exit_type === "running"; })) throw fail("root_not_ready");
|
|
196
211
|
// Mutating calls are sent exactly once, never retried with another profile.
|
|
197
212
|
return bounded(function () { return runTask(verified.ref); }, deadline).then(function () {
|
|
198
|
-
return waitForLegacyRun(verified.ref, before, deadline,
|
|
213
|
+
return waitForLegacyRun(task, verified.ref, before, started, deadline, POLL_MS);
|
|
199
214
|
});
|
|
200
215
|
}).then(function () {
|
|
201
216
|
return bounded(function () { return find(task); }, deadline).then(function (after) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type PortalLocale = "en" | "zh-TW" | "zh-CN" | "ja" | "ko" | "de" | "fr" | "es" | "it";
|
|
2
|
+
/** SDK-owned portal panel text, shared by the plain panel and the Vue template. */
|
|
3
|
+
export declare const PORTAL_MESSAGES: Record<string, Record<PortalLocale, string>>;
|
|
4
|
+
/**
|
|
5
|
+
* `createPortalAccess(options)` → `ctx.portal`, plain ES5 for DSM's desktop.
|
|
6
|
+
*
|
|
7
|
+
* An administrator reads and sets the alias with DSM's own
|
|
8
|
+
* SYNO.Core.AppPortal API in their own session, after SYNO.API.Info shows the
|
|
9
|
+
* API; DSM itself refuses everyone else (105). An ordinary user reads the
|
|
10
|
+
* alias only through the package backend's `portal.status`. Anything
|
|
11
|
+
* unexpected reads as `unavailable`; an administrator then gets only the
|
|
12
|
+
* Control Panel shortcut.
|
|
13
|
+
*
|
|
14
|
+
* `status()` resolves `{state, alias?, url?, canManage, controlPanel,
|
|
15
|
+
* defaultAlias}`; `apply(alias)` and `disable()` resolve the new status or
|
|
16
|
+
* reject `{code}`; `openControlPanel()` opens Login Portal > Applications.
|
|
17
|
+
* `messages` is the panel text in the window's locale; `mountPanel(element)`
|
|
18
|
+
* renders a plain panel for UIs without their own.
|
|
19
|
+
*/
|
|
20
|
+
export declare const PORTAL_RUNTIME: string;
|
|
21
|
+
export {};
|
|
@@ -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
|
}
|
|
@@ -2,4 +2,7 @@ export { executorTasks as rootTasks, type ExecutorTask as RootTask } from '../ru
|
|
|
2
2
|
/** Exact readback is authoritative. PasswordConfirm tokens are reused immediately,
|
|
3
3
|
* across both Root APIs, and never persisted (DSM validity is about 300 seconds). */
|
|
4
4
|
export declare const ROOT_RUNTIME: string;
|
|
5
|
-
export declare const ROOT_PANEL = "function mountRootPanel(host, access, i18n, tasks, admin) {\n if (!admin) return;\n var status = document.createElement(\"p\"), approve = document.createElement(\"button\"), retry = document.createElement(\"button\");\n approve.textContent = \"Approve background access\"; retry.textContent = \"Check status\";\n host.appendChild(status); host.appendChild(approve); host.appendChild(retry);\n function show(result) { status.textContent = result.state + (result.reason ? \": \" + result.reason : \"\"); approve.hidden = result.state !== \"needs-admin-approval\"; }\n function run(fn) { approve.disabled = retry.disabled = true; return fn().then(show, function(e) { show({state: \"blocked\", reason: e.message || e.code}); }).then(function() { approve.disabled = retry.disabled = false; }); }\n approve.onclick = function() { return run(function() { return access.authorize(); }); };\n retry.onclick = function() { return run(function() { return access.status(); }); };\n run(function() { return access.status().then(function(result) { return result.tasks && result.tasks.boot && result.tasks.control && result.tasks.boot.state === \"ready\" && result.tasks.control.state === \"ready\" ? access.control(\"start\") : result; }); });\n}";
|
|
5
|
+
export declare const ROOT_PANEL = "function mountRootPanel(host, access, i18n, tasks, admin) {\n if (!admin) return;\n var status = document.createElement(\"p\"), approve = document.createElement(\"button\"), retry = document.createElement(\"button\");\n approve.textContent = \"Approve background access\"; retry.textContent = \"Check status\";\n host.appendChild(status); host.appendChild(approve); host.appendChild(retry);\n function show(result) { status.textContent = result.state + (result.reason ? \": \" + result.reason : \"\"); approve.hidden = result.state !== \"needs-admin-approval\" && result.retry !== true; }\n function run(fn) { approve.disabled = retry.disabled = true; return fn().then(show, function(e) { show({state: \"blocked\", reason: e.message || e.code}); }).then(function() { approve.disabled = retry.disabled = false; }); }\n access.subscribe(show);\n approve.onclick = function() { return run(function() { return access.authorize(); }); };\n retry.onclick = function() { return run(function() { return access.status(); }); };\n run(function() { return access.status().then(function(result) { return result.tasks && result.tasks.boot && result.tasks.control && result.tasks.boot.state === \"ready\" && result.tasks.control.state === \"ready\" ? access.control(\"start\") : result; }); });\n}";
|
|
6
|
+
/** Administrator password confirmation in the window's own session: a supplied
|
|
7
|
+
* password, or a masked form when none is given. */
|
|
8
|
+
export declare const PASSWORD_CONFIRM: string;
|