@synopackageland/cli 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +613 -0
- package/README.md +81 -89
- package/dist/add.js +39 -16
- package/dist/build-spk/delegate-scope.d.ts +6 -0
- package/dist/build-spk/delegate-scope.js +34 -0
- package/dist/build-spk/dsm-arch.d.ts +7 -1
- package/dist/build-spk/dsm-arch.js +24 -28
- package/dist/build-spk/dsm-platforms.json +39 -0
- package/dist/build-spk/dsm-version.d.ts +11 -0
- package/dist/build-spk/dsm-version.js +17 -0
- package/dist/build-spk/gateway.d.ts +1 -1
- package/dist/build-spk/gateway.js +2 -2
- package/dist/build-spk/generator.js +30 -5
- package/dist/build-spk/notices.js +4 -1
- package/dist/build-spk/resource-worker.js +3 -0
- package/dist/build-spk/wizard-messages.d.ts +66 -0
- package/dist/build-spk/wizard-messages.js +75 -9
- package/dist/cli.js +15 -7
- package/dist/contract/schema-validate.js +8 -0
- package/dist/contract/validate.js +30 -0
- package/dist/deploy/deploy.d.ts +1 -1
- package/dist/deploy/deploy.js +8 -0
- package/dist/deploy/plan.js +1 -1
- package/dist/deploy/spk-version.js +1 -1
- package/dist/error-registry.js +43 -15
- package/dist/host/dsm-client.d.ts +8 -4
- package/dist/host/dsm-client.js +10 -4
- package/dist/host/types.d.ts +2 -1
- package/dist/info.js +18 -2
- package/dist/init.d.ts +3 -0
- package/dist/init.js +49 -18
- package/dist/package-metadata.d.ts +21 -0
- package/dist/package-metadata.js +101 -0
- package/dist/portal/alias.d.ts +25 -0
- package/dist/portal/alias.js +48 -0
- package/dist/portal/package.d.ts +33 -0
- package/dist/portal/package.js +116 -0
- package/dist/runtime/delegate-contract.d.ts +79 -0
- package/dist/runtime/delegate-contract.js +27 -0
- package/dist/runtime/executor-build.d.ts +1 -1
- package/dist/runtime/executor-build.js +5 -4
- package/dist/runtime/executor-inspect.d.ts +3 -0
- package/dist/runtime/executor-inspect.js +11 -5
- package/dist/runtime/executor-policy.d.ts +12 -0
- package/dist/runtime/executor-policy.js +43 -3
- package/dist/runtime/executor-scope-task.d.ts +4 -0
- package/dist/runtime/executor-scope-task.js +21 -0
- package/dist/runtime/executor-tasks.d.ts +2 -1
- package/dist/runtime/executor-tasks.js +4 -4
- package/dist/skill.js +1 -0
- package/dist/standalone/api-permissions.d.ts +10 -0
- package/dist/standalone/api-permissions.js +19 -2
- package/dist/standalone/background.d.ts +16 -0
- package/dist/standalone/background.js +69 -2
- package/dist/standalone/binary.d.ts +1 -1
- package/dist/standalone/binary.js +22 -8
- package/dist/standalone/build.d.ts +1 -1
- package/dist/standalone/build.js +38 -8
- package/dist/standalone/daemon.d.ts +1 -1
- package/dist/standalone/daemon.js +2 -1
- package/dist/standalone/dsm-window.d.ts +3 -1
- package/dist/standalone/dsm-window.js +72 -15
- package/dist/standalone/inspect-spk.d.ts +8 -0
- package/dist/standalone/inspect-spk.js +105 -26
- package/dist/standalone/lifecycle.js +86 -8
- package/dist/standalone/manifest.d.ts +13 -0
- package/dist/standalone/manifest.js +57 -8
- package/dist/standalone/native-authorization-window.d.ts +1 -1
- package/dist/standalone/native-authorization-window.js +2 -0
- package/dist/standalone/native-layout.d.ts +3 -0
- package/dist/standalone/native-layout.js +37 -5
- package/dist/standalone/portal-window.d.ts +21 -0
- package/dist/standalone/portal-window.js +155 -0
- package/dist/standalone/portal.d.ts +4 -0
- package/dist/standalone/portal.js +4 -0
- package/dist/standalone/resource.d.ts +5 -3
- package/dist/standalone/resource.js +6 -3
- package/dist/standalone/root-window.js +62 -15
- package/dist/standalone/spk.d.ts +1 -1
- package/dist/standalone/spk.js +25 -7
- package/dist/templates/_daemon/main_test.go +61 -8
- package/dist/templates/_executor/README.md +127 -16
- package/dist/templates/_executor/anchor.go +146 -0
- package/dist/templates/_executor/anchor_test.go +126 -0
- package/dist/templates/_executor/apppriv_review_test.go +1 -1
- package/dist/templates/_executor/cancel_contract_test.go +236 -0
- package/dist/templates/_executor/copy.go +64 -0
- package/dist/templates/_executor/copy_test.go +88 -0
- package/dist/templates/_executor/dsm.go +23 -10
- package/dist/templates/_executor/dsm_test.go +95 -1
- package/dist/templates/_executor/executor.go +260 -49
- package/dist/templates/_executor/executor_test.go +36 -6
- package/dist/templates/_executor/identity.go +27 -1
- package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
- package/dist/templates/_executor/identity_linux.go +82 -0
- package/dist/templates/_executor/identity_security_test.go +43 -0
- package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
- package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
- package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
- package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
- package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
- package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
- package/dist/templates/_executor/lifecycle_test.go +11 -0
- package/dist/templates/_executor/link_linux.go +28 -0
- package/dist/templates/_executor/long_running_test.go +530 -0
- package/dist/templates/_executor/main.go +72 -20
- package/dist/templates/_executor/move_linux.go +490 -0
- package/dist/templates/_executor/move_linux_test.go +460 -0
- package/dist/templates/_executor/move_validation.go +46 -0
- package/dist/templates/_executor/move_validation_test.go +187 -0
- package/dist/templates/_executor/operations.go +926 -0
- package/dist/templates/_executor/platform_linux.go +24 -173
- package/dist/templates/_executor/platform_linux_test.go +9 -65
- package/dist/templates/_executor/platform_other.go +30 -4
- package/dist/templates/_executor/process.go +3 -0
- package/dist/templates/_executor/records.go +242 -0
- package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
- package/dist/templates/_executor/scope_client.go +37 -0
- package/dist/templates/_executor/scope_contract.go +12 -0
- package/dist/templates/_executor/selected_scope.go +146 -0
- package/dist/templates/_executor/selected_scope_test.go +186 -0
- package/dist/templates/_executor/status_disabled_test.go +33 -0
- package/dist/templates/_executor/store.go +4 -3
- package/dist/templates/_executor/supervise.go +109 -0
- package/dist/templates/_executor/supervise_test.go +130 -0
- package/dist/templates/_executor/task_race_review_test.go +1 -1
- package/dist/templates/_executor/tasks.go +7 -8
- package/dist/templates/_executor/tasks_review_test.go +1 -1
- package/dist/templates/_executor/tasks_test.go +4 -4
- package/dist/templates/_executor/watch.go +8 -0
- package/dist/templates/_executor/watch_test.go +23 -2
- package/dist/templates/_executor/write_review_linux_test.go +4 -12
- package/dist/templates/_shared/AGENTS.md +129 -0
- package/dist/templates/binary/dsm-package.yaml +24 -0
- package/dist/templates/binary/i18n/messages/de.json +4 -0
- package/dist/templates/binary/i18n/messages/en.json +4 -0
- package/dist/templates/binary/i18n/messages/es.json +4 -0
- package/dist/templates/binary/i18n/messages/fr.json +4 -0
- package/dist/templates/binary/i18n/messages/it.json +4 -0
- package/dist/templates/binary/i18n/messages/ja.json +4 -0
- package/dist/templates/binary/i18n/messages/ko.json +4 -0
- package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/dist/templates/binary/ui/app.js +19 -4
- package/dist/templates/native-authorization/AuthorizationGate.vue +5 -3
- package/dist/templates/native-authorization/i18n/de.json +1 -0
- package/dist/templates/native-authorization/i18n/en.json +1 -0
- package/dist/templates/native-authorization/i18n/es.json +2 -1
- package/dist/templates/native-authorization/i18n/fr.json +1 -0
- package/dist/templates/native-authorization/i18n/it.json +11 -10
- package/dist/templates/native-authorization/i18n/ja.json +1 -0
- package/dist/templates/native-authorization/i18n/ko.json +10 -9
- package/dist/templates/native-authorization/i18n/zh-CN.json +6 -5
- package/dist/templates/native-authorization/i18n/zh-TW.json +6 -5
- package/dist/templates/native-go/README.md +43 -10
- package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
- package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
- package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
- package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
- package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
- package/dist/templates/native-go/backend/internal/api/server.go +18 -5
- package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
- package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
- package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
- package/dist/templates/native-go/backend/internal/background/store.go +16 -14
- package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
- package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
- package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
- package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
- package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
- package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
- package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
- package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
- package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
- package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
- package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
- package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
- package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
- package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
- package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
- package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
- package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
- package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
- package/dist/templates/native-go/dsm-package.yaml +20 -1
- package/dist/templates/native-go/i18n/glossary.json +2 -1
- package/dist/templates/native-go/i18n/messages/de.json +1 -0
- package/dist/templates/native-go/i18n/messages/en.json +1 -0
- package/dist/templates/native-go/i18n/messages/es.json +1 -0
- package/dist/templates/native-go/i18n/messages/fr.json +1 -0
- package/dist/templates/native-go/i18n/messages/it.json +1 -0
- package/dist/templates/native-go/i18n/messages/ja.json +1 -0
- package/dist/templates/native-go/i18n/messages/ko.json +1 -0
- package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
- package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
- package/dist/templates/native-go/ui/app.css +10 -0
- package/dist/templates/native-go/ui/app.js +11 -1
- package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
- package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
- package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
- package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
- package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
- package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
- package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
- package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
- package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
- package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
- package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
- package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
- package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
- package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
- package/dist/templates/native-go-delegate/test.sh +1 -0
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
- package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
- package/dist/templates/native-go-vue/README.md +4 -0
- package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
- package/dist/templates/native-go-vue/frontend/package.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
- package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
- package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
- package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
- package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
- package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
- package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
- package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
- package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
- package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
- package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
- package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
- package/package.json +5 -1
- package/schema/package-metadata.schema.json +101 -0
- package/schema/synology-app.schema.json +112 -0
- package/skills/SKILL.md +106 -4
- package/skills/reference/create.md +101 -2
- package/skills/reference/deploy.md +2 -2
- package/skills/reference/files.md +113 -2
- package/skills/reference/identity.md +70 -1
- package/skills/reference/portal.md +17 -0
- package/skills/reference/ui-vue.md +12 -0
- package/templates/_daemon/main_test.go +61 -8
- package/templates/_executor/README.md +127 -16
- package/templates/_executor/anchor.go +146 -0
- package/templates/_executor/anchor_test.go +126 -0
- package/templates/_executor/apppriv_review_test.go +1 -1
- package/templates/_executor/cancel_contract_test.go +236 -0
- package/templates/_executor/copy.go +64 -0
- package/templates/_executor/copy_test.go +88 -0
- package/templates/_executor/dsm.go +23 -10
- package/templates/_executor/dsm_test.go +95 -1
- package/templates/_executor/executor.go +260 -49
- package/templates/_executor/executor_test.go +36 -6
- package/templates/_executor/identity.go +27 -1
- package/templates/_executor/identity_kernel_linux_test.go +60 -0
- package/templates/_executor/identity_linux.go +82 -0
- package/templates/_executor/identity_security_test.go +43 -0
- package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
- package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
- package/templates/_executor/internal/taskscript/boot.sh +9 -9
- package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
- package/templates/_executor/internal/taskscript/control.sh +15 -10
- package/templates/_executor/internal/taskscript/tasks.go +5 -3
- package/templates/_executor/lifecycle_test.go +11 -0
- package/templates/_executor/link_linux.go +28 -0
- package/templates/_executor/long_running_test.go +530 -0
- package/templates/_executor/main.go +72 -20
- package/templates/_executor/move_linux.go +490 -0
- package/templates/_executor/move_linux_test.go +460 -0
- package/templates/_executor/move_validation.go +46 -0
- package/templates/_executor/move_validation_test.go +187 -0
- package/templates/_executor/operations.go +926 -0
- package/templates/_executor/platform_linux.go +24 -173
- package/templates/_executor/platform_linux_test.go +9 -65
- package/templates/_executor/platform_other.go +30 -4
- package/templates/_executor/process.go +3 -0
- package/templates/_executor/records.go +242 -0
- package/templates/_executor/scope_cancel_contract_test.go +91 -0
- package/templates/_executor/scope_client.go +37 -0
- package/templates/_executor/scope_contract.go +12 -0
- package/templates/_executor/selected_scope.go +146 -0
- package/templates/_executor/selected_scope_test.go +186 -0
- package/templates/_executor/status_disabled_test.go +33 -0
- package/templates/_executor/store.go +4 -3
- package/templates/_executor/supervise.go +109 -0
- package/templates/_executor/supervise_test.go +130 -0
- package/templates/_executor/task_race_review_test.go +1 -1
- package/templates/_executor/tasks.go +7 -8
- package/templates/_executor/tasks_review_test.go +1 -1
- package/templates/_executor/tasks_test.go +4 -4
- package/templates/_executor/watch.go +8 -0
- package/templates/_executor/watch_test.go +23 -2
- package/templates/_executor/write_review_linux_test.go +4 -12
- package/templates/_shared/AGENTS.md +129 -0
- package/templates/binary/dsm-package.yaml +24 -0
- package/templates/binary/i18n/messages/de.json +4 -0
- package/templates/binary/i18n/messages/en.json +4 -0
- package/templates/binary/i18n/messages/es.json +4 -0
- package/templates/binary/i18n/messages/fr.json +4 -0
- package/templates/binary/i18n/messages/it.json +4 -0
- package/templates/binary/i18n/messages/ja.json +4 -0
- package/templates/binary/i18n/messages/ko.json +4 -0
- package/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/templates/binary/ui/app.js +19 -4
- package/templates/native-authorization/AuthorizationGate.vue +5 -3
- package/templates/native-authorization/i18n/de.json +1 -0
- package/templates/native-authorization/i18n/en.json +1 -0
- package/templates/native-authorization/i18n/es.json +2 -1
- package/templates/native-authorization/i18n/fr.json +1 -0
- package/templates/native-authorization/i18n/it.json +11 -10
- package/templates/native-authorization/i18n/ja.json +1 -0
- package/templates/native-authorization/i18n/ko.json +10 -9
- package/templates/native-authorization/i18n/zh-CN.json +6 -5
- package/templates/native-authorization/i18n/zh-TW.json +6 -5
- package/templates/native-go/README.md +43 -10
- package/templates/native-go/backend/cmd/app/main.go +27 -7
- package/templates/native-go/backend/internal/api/entry_test.go +47 -0
- package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
- package/templates/native-go/backend/internal/api/registry.go +11 -0
- package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
- package/templates/native-go/backend/internal/api/server.go +18 -5
- package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/templates/native-go/backend/internal/app/portal.go +30 -0
- package/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/templates/native-go/backend/internal/app/routes.go +8 -2
- package/templates/native-go/backend/internal/background/runner.go +1 -1
- package/templates/native-go/backend/internal/background/store.go +16 -14
- package/templates/native-go/backend/internal/dsm/admin.go +8 -2
- package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
- package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
- package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
- package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
- package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
- package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
- package/templates/native-go/backend/internal/dsm/entry.go +177 -0
- package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
- package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
- package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
- package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
- package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
- package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
- package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
- package/templates/native-go/backend/internal/filestation/service.go +1 -1
- package/templates/native-go/backend/internal/portal/portal.go +138 -0
- package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
- package/templates/native-go/dsm-package.yaml +20 -1
- package/templates/native-go/i18n/glossary.json +2 -1
- package/templates/native-go/i18n/messages/de.json +1 -0
- package/templates/native-go/i18n/messages/en.json +1 -0
- package/templates/native-go/i18n/messages/es.json +1 -0
- package/templates/native-go/i18n/messages/fr.json +1 -0
- package/templates/native-go/i18n/messages/it.json +1 -0
- package/templates/native-go/i18n/messages/ja.json +1 -0
- package/templates/native-go/i18n/messages/ko.json +1 -0
- package/templates/native-go/i18n/messages/zh-CN.json +1 -0
- package/templates/native-go/i18n/messages/zh-TW.json +1 -0
- package/templates/native-go/ui/app.css +10 -0
- package/templates/native-go/ui/app.js +11 -1
- package/templates/native-go-delegate/DELEGATE.md +126 -5
- package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
- package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
- package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
- package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
- package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
- package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
- package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
- package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
- package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
- package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
- package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
- package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
- package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
- package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
- package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
- package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
- package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
- package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
- package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
- package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
- package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
- package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
- package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
- package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
- package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
- package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
- package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
- package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
- package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
- package/templates/native-go-delegate/test.sh +1 -0
- package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
- package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
- package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
- package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
- package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
- package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
- package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
- package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
- package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
- package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
- package/templates/native-go-vue/README.md +4 -0
- package/templates/native-go-vue/frontend/package-lock.json +4 -4
- package/templates/native-go-vue/frontend/package.json +1 -1
- package/templates/native-go-vue/frontend/src/App.vue +18 -13
- package/templates/native-go-vue/frontend/src/context.ts +31 -0
- package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
- package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
- package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
- package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
- package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
- package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
- package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
- package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
- package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
- package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
- package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
- package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
- package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
- package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
- package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
- package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
- package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
- package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
- package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
- package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
- package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
- package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
- package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
- package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
- package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
- package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
|
@@ -41,3 +41,17 @@ test('failed status loading offers a retry and releases the mounting class',asyn
|
|
|
41
41
|
f.app.unmount();expect(f.root.classList.contains('dsmapp-vue-root')).toBe(false)
|
|
42
42
|
}finally{f.close()}
|
|
43
43
|
})
|
|
44
|
+
test('a portal app shows the Application Portal section on the status page',async()=>{
|
|
45
|
+
const without=fixture('Plain')
|
|
46
|
+
const f=fixture('Portal')
|
|
47
|
+
try{
|
|
48
|
+
await settle();expect(without.root.textContent).not.toContain('Application Portal')
|
|
49
|
+
f.app.unmount()
|
|
50
|
+
const status={state:'active',alias:'portal',url:'https://nas.example/portal/',canManage:false,controlPanel:false,defaultAlias:'portal'} as const
|
|
51
|
+
f.ctx.portal={messages:{title:'Application Portal',link:'Direct link:'},status:vi.fn(async()=>status),apply:vi.fn(),disable:vi.fn(),openControlPanel:vi.fn(),mountPanel:vi.fn()}
|
|
52
|
+
const app=mount(f.root,f.ctx);await settle()
|
|
53
|
+
expect(f.root.textContent).toContain('Application Portal')
|
|
54
|
+
expect(f.root.querySelector('a[href="https://nas.example/portal/"]')).not.toBeNull()
|
|
55
|
+
app.unmount()
|
|
56
|
+
}finally{without.close();f.root.remove()}
|
|
57
|
+
})
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import {expect,test,vi} from 'vitest'
|
|
3
|
+
import {createApp,h,nextTick} from 'vue'
|
|
4
|
+
import {AppRoot} from '@synopackageland/ui'
|
|
5
|
+
import PortalSettings from '../src/portal/PortalSettings.vue'
|
|
6
|
+
import type {PortalAccess,PortalStatus} from '../src/context'
|
|
7
|
+
|
|
8
|
+
const messages={title:'Application Portal',link:'Direct link:',inactive:'Not active.',askAdmin:'Ask an administrator',alias:'Alias',apply:'Apply',disable:'Turn off',advanced:'Advanced',controlPanel:'Open Control Panel',portal_alias_in_use:'Alias in use',portal_unavailable:'DSM refused'}
|
|
9
|
+
const base:PortalStatus={state:'inactive',canManage:false,controlPanel:false,defaultAlias:'my-app'}
|
|
10
|
+
function access(status:PortalStatus,overrides:Partial<PortalAccess>={}):PortalAccess{
|
|
11
|
+
return {messages,status:vi.fn(async()=>status),apply:vi.fn(async()=>status),disable:vi.fn(async()=>status),openControlPanel:vi.fn(),mountPanel:vi.fn(),...overrides}
|
|
12
|
+
}
|
|
13
|
+
async function mount(portal:PortalAccess){
|
|
14
|
+
const root=document.createElement('div');document.body.append(root)
|
|
15
|
+
const app=createApp({render:()=>h(AppRoot,{},()=>h(PortalSettings,{portal}))})
|
|
16
|
+
app.mount(root);await nextTick();await nextTick();await new Promise(r=>setTimeout(r));await nextTick()
|
|
17
|
+
return {root,unmount(){app.unmount();root.remove()}}
|
|
18
|
+
}
|
|
19
|
+
const buttons=(root:HTMLElement)=>[...root.querySelectorAll('button')].map(b=>b.textContent?.trim())
|
|
20
|
+
|
|
21
|
+
test('an ordinary user sees the active link and nothing to change',async()=>{
|
|
22
|
+
const {root,unmount}=await mount(access({...base,state:'active',alias:'my-app',url:'https://nas.example/my-app/'}))
|
|
23
|
+
try{
|
|
24
|
+
expect(root.querySelector('a')?.getAttribute('href')).toBe('https://nas.example/my-app/')
|
|
25
|
+
expect(root.querySelector('input')).toBeNull();expect(root.querySelector('button')).toBeNull()
|
|
26
|
+
}finally{unmount()}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('an ordinary user without an active alias is asked to contact an administrator',async()=>{
|
|
30
|
+
const {root,unmount}=await mount(access({...base,state:'unavailable'}))
|
|
31
|
+
try{
|
|
32
|
+
expect(root.textContent).toContain('Ask an administrator')
|
|
33
|
+
expect(root.querySelector('a,input,button')).toBeNull()
|
|
34
|
+
}finally{unmount()}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('an administrator applies the prefilled alias and sees DSM refusals as portal text',async()=>{
|
|
38
|
+
const apply=vi.fn(async()=>Promise.reject({code:'portal_alias_in_use'}))
|
|
39
|
+
const portal=access({...base,canManage:true},{apply})
|
|
40
|
+
const {root,unmount}=await mount(portal)
|
|
41
|
+
try{
|
|
42
|
+
const input=root.querySelector('input')!
|
|
43
|
+
expect(input.value).toBe('my-app')
|
|
44
|
+
root.querySelector('form')!.dispatchEvent(new Event('submit',{cancelable:true}))
|
|
45
|
+
await new Promise(r=>setTimeout(r));await nextTick()
|
|
46
|
+
expect(apply).toHaveBeenCalledWith('my-app')
|
|
47
|
+
expect(root.querySelector('[role="alert"]')?.textContent).toContain('Alias in use')
|
|
48
|
+
;[...root.querySelectorAll('button')].find(b=>b.textContent?.includes('Advanced'))!.click()
|
|
49
|
+
expect(portal.openControlPanel).toHaveBeenCalled()
|
|
50
|
+
}finally{unmount()}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('an administrator turns an active alias off',async()=>{
|
|
54
|
+
const portal=access({...base,state:'active',alias:'my-app',url:'https://nas.example/my-app/',canManage:true})
|
|
55
|
+
const {root,unmount}=await mount(portal)
|
|
56
|
+
try{
|
|
57
|
+
expect(root.querySelector('a')?.getAttribute('href')).toBe('https://nas.example/my-app/')
|
|
58
|
+
;[...root.querySelectorAll('button')].find(b=>b.textContent?.includes('Turn off'))!.click()
|
|
59
|
+
await nextTick()
|
|
60
|
+
expect(portal.disable).toHaveBeenCalled()
|
|
61
|
+
}finally{unmount()}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('an administrator without DSM portal support gets only the Control Panel shortcut',async()=>{
|
|
65
|
+
const portal=access({...base,state:'unavailable',controlPanel:true})
|
|
66
|
+
const {root,unmount}=await mount(portal)
|
|
67
|
+
try{
|
|
68
|
+
expect(root.querySelector('input')).toBeNull()
|
|
69
|
+
expect(buttons(root)).toEqual(['Open Control Panel'])
|
|
70
|
+
}finally{unmount()}
|
|
71
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
// @vitest-environment-options {"url":"https://nas.test"}
|
|
3
|
+
import {expect,test,vi} from 'vitest'
|
|
4
|
+
import {nextTick} from 'vue'
|
|
5
|
+
import {mount} from '../src/main'
|
|
6
|
+
import type {Context} from '../src/context'
|
|
7
|
+
import {appCopy} from '../src/i18n'
|
|
8
|
+
import {identityCopy} from '../src/identity/i18n'
|
|
9
|
+
async function settle(){for(let i=0;i<20;i++){await Promise.resolve();await nextTick()}}
|
|
10
|
+
const buttons=(root:HTMLElement)=>[...root.querySelectorAll('button')].map(b=>b.textContent?.trim())
|
|
11
|
+
function start(locale:string,call:(method:string)=>Promise<unknown>){
|
|
12
|
+
const ctx={locale,call:vi.fn(call),reopen(){return ()=>{}}} as unknown as Context
|
|
13
|
+
const root=document.createElement('div');document.body.append(root)
|
|
14
|
+
const app=mount(root,ctx)
|
|
15
|
+
return {root,close(){app.unmount();root.remove()}}
|
|
16
|
+
}
|
|
17
|
+
test('the status page and its errors follow the DSM language',async()=>{
|
|
18
|
+
const copy=appCopy('ger')
|
|
19
|
+
const {root,close}=start('de',async method=>{
|
|
20
|
+
if(method==='app.status')return {package:'Pkg',version:'1',user:'admin',admin:true}
|
|
21
|
+
if(method==='greeting.get')throw {code:'admin_required'}
|
|
22
|
+
throw {code:'unknown_method'}
|
|
23
|
+
})
|
|
24
|
+
try{
|
|
25
|
+
await settle()
|
|
26
|
+
expect(buttons(root)).toContain(copy.refresh)
|
|
27
|
+
expect(root.textContent).toContain(copy.statusTitle)
|
|
28
|
+
expect(root.textContent).toContain(copy.greeting)
|
|
29
|
+
expect(root.textContent).toContain(copy.errors.admin_required)
|
|
30
|
+
expect(root.querySelector('[aria-label]')?.getAttribute('aria-label')).not.toBe('Package settings')
|
|
31
|
+
}finally{close()}
|
|
32
|
+
})
|
|
33
|
+
test('unknown failures name the code in the DSM language',()=>{
|
|
34
|
+
expect(appCopy('ja').errors.request_failed).toContain('{code}')
|
|
35
|
+
})
|
|
36
|
+
test('the sign-in page and its session notices follow the DSM language',async()=>{
|
|
37
|
+
const copy=identityCopy('jpn')
|
|
38
|
+
const {root,close}=start('ja',async method=>{
|
|
39
|
+
if(method==='identity.status')return {enabled:true}
|
|
40
|
+
if(method==='identity.session')return {user:'alice',uid:'1',expiresAt:new Date(Date.now()-1000).toISOString()}
|
|
41
|
+
throw {code:'session_required'}
|
|
42
|
+
})
|
|
43
|
+
try{
|
|
44
|
+
await settle()
|
|
45
|
+
expect(root.textContent).toContain(copy.title)
|
|
46
|
+
expect(buttons(root)).toEqual(expect.arrayContaining([copy.signIn,copy.continueDSM]))
|
|
47
|
+
expect(root.querySelector('[role="status"]')?.textContent).toBe(copy.notices.expired)
|
|
48
|
+
expect(root.textContent).not.toMatch(/Sign in|Account|Password|session/)
|
|
49
|
+
}finally{close()}
|
|
50
|
+
})
|
package/package.json
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Syno Package Land Developer Kit CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"synopkgland": "./dist/bin.js"
|
|
8
8
|
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=22.12"
|
|
11
|
+
},
|
|
9
12
|
"files": [
|
|
10
13
|
"dist",
|
|
14
|
+
"CHANGELOG.md",
|
|
11
15
|
"templates",
|
|
12
16
|
"schema",
|
|
13
17
|
"skills"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"additionalProperties": false,
|
|
5
|
+
"properties": {
|
|
6
|
+
"changelog": {
|
|
7
|
+
"oneOf": [
|
|
8
|
+
{
|
|
9
|
+
"type": "string",
|
|
10
|
+
"maxLength": 16000
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"type": "object",
|
|
14
|
+
"maxProperties": 32,
|
|
15
|
+
"additionalProperties": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"maxLength": 16000
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"contact_email": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"maxLength": 16000,
|
|
25
|
+
"pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
|
|
26
|
+
},
|
|
27
|
+
"support_email": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"maxLength": 16000,
|
|
30
|
+
"pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
|
|
31
|
+
},
|
|
32
|
+
"homepage": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"maxLength": 16000,
|
|
35
|
+
"pattern": "^https?://"
|
|
36
|
+
},
|
|
37
|
+
"source_url": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"maxLength": 16000,
|
|
40
|
+
"pattern": "^https?://"
|
|
41
|
+
},
|
|
42
|
+
"issues_url": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"maxLength": 16000,
|
|
45
|
+
"pattern": "^https?://"
|
|
46
|
+
},
|
|
47
|
+
"license": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"maxLength": 16000
|
|
50
|
+
},
|
|
51
|
+
"maintainer_url": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"maxLength": 16000,
|
|
54
|
+
"pattern": "^https?://"
|
|
55
|
+
},
|
|
56
|
+
"distributor": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"maxLength": 16000
|
|
59
|
+
},
|
|
60
|
+
"distributor_url": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"maxLength": 16000,
|
|
63
|
+
"pattern": "^https?://"
|
|
64
|
+
},
|
|
65
|
+
"support_url": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"maxLength": 16000,
|
|
68
|
+
"pattern": "^(https?://|mailto:)"
|
|
69
|
+
},
|
|
70
|
+
"helpurl": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"maxLength": 16000,
|
|
73
|
+
"pattern": "^https?://"
|
|
74
|
+
},
|
|
75
|
+
"long_description": {
|
|
76
|
+
"oneOf": [
|
|
77
|
+
{
|
|
78
|
+
"type": "string",
|
|
79
|
+
"maxLength": 16000
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"type": "object",
|
|
83
|
+
"maxProperties": 32,
|
|
84
|
+
"additionalProperties": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"maxLength": 16000
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
"screenshots": {
|
|
92
|
+
"type": "array",
|
|
93
|
+
"maxItems": 12,
|
|
94
|
+
"items": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"pattern": "^https?://",
|
|
97
|
+
"maxLength": 2048
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -118,6 +118,18 @@
|
|
|
118
118
|
"pattern": "^(?:[A-Za-z0-9._-]{1,64}|[A-Za-z0-9._-]{1,64}\\\\[A-Za-z0-9._-](?:[A-Za-z0-9._ -]{0,126}[A-Za-z0-9._-])?|[A-Za-z0-9._-](?:[A-Za-z0-9._ -]{0,126}[A-Za-z0-9._-])?@[A-Za-z0-9._-]{1,64})$(?![\\s\\S])"
|
|
119
119
|
},
|
|
120
120
|
"description": "DSM group names allowed in; only with access: dsm-groups."
|
|
121
|
+
},
|
|
122
|
+
"portal": {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"properties": {
|
|
125
|
+
"alias": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"pattern": "^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$",
|
|
128
|
+
"description": "Default DSM Application Portal alias (https://<nas>/<alias>/). Omit to use the package name. An administrator still applies it."
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"additionalProperties": false,
|
|
132
|
+
"description": "Register the App in DSM Control Panel > Login Portal > Applications. Needs launch: dsm-window behind the DSM gateway (access other than public) and os_min_ver 7.3.2-86009 or later. Registration alone exposes nothing."
|
|
121
133
|
}
|
|
122
134
|
},
|
|
123
135
|
"additionalProperties": true
|
|
@@ -149,6 +161,106 @@
|
|
|
149
161
|
"type": "boolean"
|
|
150
162
|
}
|
|
151
163
|
}
|
|
164
|
+
},
|
|
165
|
+
"metadata": {
|
|
166
|
+
"type": "object",
|
|
167
|
+
"additionalProperties": false,
|
|
168
|
+
"properties": {
|
|
169
|
+
"changelog": {
|
|
170
|
+
"oneOf": [
|
|
171
|
+
{
|
|
172
|
+
"type": "string",
|
|
173
|
+
"maxLength": 16000
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"type": "object",
|
|
177
|
+
"maxProperties": 32,
|
|
178
|
+
"additionalProperties": {
|
|
179
|
+
"type": "string",
|
|
180
|
+
"maxLength": 16000
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
"contact_email": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"maxLength": 16000,
|
|
188
|
+
"pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
|
|
189
|
+
},
|
|
190
|
+
"support_email": {
|
|
191
|
+
"type": "string",
|
|
192
|
+
"maxLength": 16000,
|
|
193
|
+
"pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
|
|
194
|
+
},
|
|
195
|
+
"homepage": {
|
|
196
|
+
"type": "string",
|
|
197
|
+
"maxLength": 16000,
|
|
198
|
+
"pattern": "^https?://"
|
|
199
|
+
},
|
|
200
|
+
"source_url": {
|
|
201
|
+
"type": "string",
|
|
202
|
+
"maxLength": 16000,
|
|
203
|
+
"pattern": "^https?://"
|
|
204
|
+
},
|
|
205
|
+
"issues_url": {
|
|
206
|
+
"type": "string",
|
|
207
|
+
"maxLength": 16000,
|
|
208
|
+
"pattern": "^https?://"
|
|
209
|
+
},
|
|
210
|
+
"license": {
|
|
211
|
+
"type": "string",
|
|
212
|
+
"maxLength": 16000
|
|
213
|
+
},
|
|
214
|
+
"maintainer_url": {
|
|
215
|
+
"type": "string",
|
|
216
|
+
"maxLength": 16000,
|
|
217
|
+
"pattern": "^https?://"
|
|
218
|
+
},
|
|
219
|
+
"distributor": {
|
|
220
|
+
"type": "string",
|
|
221
|
+
"maxLength": 16000
|
|
222
|
+
},
|
|
223
|
+
"distributor_url": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"maxLength": 16000,
|
|
226
|
+
"pattern": "^https?://"
|
|
227
|
+
},
|
|
228
|
+
"support_url": {
|
|
229
|
+
"type": "string",
|
|
230
|
+
"maxLength": 16000,
|
|
231
|
+
"pattern": "^(https?://|mailto:)"
|
|
232
|
+
},
|
|
233
|
+
"helpurl": {
|
|
234
|
+
"type": "string",
|
|
235
|
+
"maxLength": 16000,
|
|
236
|
+
"pattern": "^https?://"
|
|
237
|
+
},
|
|
238
|
+
"long_description": {
|
|
239
|
+
"oneOf": [
|
|
240
|
+
{
|
|
241
|
+
"type": "string",
|
|
242
|
+
"maxLength": 16000
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"type": "object",
|
|
246
|
+
"maxProperties": 32,
|
|
247
|
+
"additionalProperties": {
|
|
248
|
+
"type": "string",
|
|
249
|
+
"maxLength": 16000
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
"screenshots": {
|
|
255
|
+
"type": "array",
|
|
256
|
+
"maxItems": 12,
|
|
257
|
+
"items": {
|
|
258
|
+
"type": "string",
|
|
259
|
+
"pattern": "^https?://",
|
|
260
|
+
"maxLength": 2048
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
152
264
|
}
|
|
153
265
|
},
|
|
154
266
|
"additionalProperties": true
|
package/skills/SKILL.md
CHANGED
|
@@ -5,15 +5,15 @@ description: Initialize, extend, check, build, inspect, and deploy Synology appl
|
|
|
5
5
|
|
|
6
6
|
# Independent Synology SPKs
|
|
7
7
|
|
|
8
|
-
Use this guide to initialize, build and inspect own applications or upstream OSS as independent packages. 依已實作能力區分 DSM session 檔案、私有 jobs 與 App 登入;delegate 已實作並隨 CLI
|
|
8
|
+
Use this guide to initialize, build and inspect own applications or upstream OSS as independent packages. 依已實作能力區分 DSM session 檔案、私有 jobs 與 App 登入;delegate 已實作並隨 CLI 提供固定操作的離線委託(預設 `files.moveFromStaging`);共用 delegate/rootOps executor 的完整裝置生命週期驗收仍待完成,不得宣稱已通過;支援邊界依 delegate guide/support matrix,禁止發明新的身分平台。
|
|
9
9
|
|
|
10
10
|
Start with `synopkgland init -t native-go`, `synopkgland init -t binary`, or `synopkgland init -t compose`. Read reference/create.md or reference/wrap.md, then reference/deploy.md. Native CGI session checks belong to the package. Container authentication belongs to upstream; fixed service credentials govern mounted data access.
|
|
11
11
|
|
|
12
12
|
Never install, uninstall, publish or modify NAS data without task authorization. Prefer check, inspect and deploy --dry-run for reviewable artifacts.
|
|
13
13
|
|
|
14
|
-
Native projects use schema 2 capabilities and `--with files,jobs,login,root-ops`; use `add` for existing projects. Prefer `check --json`, `build --json`, `inspect <spk> --json`, `deploy --dry-run --json`, and `status --host <profile> --json` for structured results. Read the conflict policy in reference/create.md before adding overlays.
|
|
14
|
+
Native projects use schema 2 capabilities and `--with files,jobs,login,root-ops,delegate`; use `add` for existing projects. Prefer `check --json`, `build --json`, `inspect <spk> --json`, `deploy --dry-run --json`, and `status --host <profile> --json` for structured results. Read the conflict policy in reference/create.md before adding overlays.
|
|
15
15
|
|
|
16
|
-
Read reference/files.md and reference/identity.md for capability boundaries. RootOps and delegate share one-time protected executor boot/control setup with digest approval. Existing native products can explicitly use the separate authorization-sdk build-time adapter; do not mix its tasks with generated executor capabilities. App sessions alone do not grant NAS file authority.
|
|
16
|
+
Read reference/portal.md before declaring or changing a DSM Application Portal alias (`add portal`); DSM owns the saved setting. Read reference/files.md and reference/identity.md for capability boundaries. RootOps and delegate share one-time protected executor boot/control setup with digest approval. Existing native products can explicitly use the separate authorization-sdk build-time adapter; do not mix its tasks with generated executor capabilities. App sessions alone do not grant NAS file authority.
|
|
17
17
|
|
|
18
18
|
Read [reference/ui-vue.md](reference/ui-vue.md) when editing Vue components in the native-go Vue template; use the installed SDK contracts, keep DSM embedding boundaries, and verify the actual app.
|
|
19
19
|
|
|
@@ -26,4 +26,106 @@ Use `syno-pkg-land-ui` directly in npm scripts; keep AI guidance version-indepen
|
|
|
26
26
|
|
|
27
27
|
For existing native products, schema 2 `backend: {kind: native}` preserves project-owned payload/metadata, prepare/compile argv hooks and pinned toolkits. See the native-layout guide; run `check`, `build`, then `inspect <spk>` locally. Keep lifecycle/systemd as the package account and preserve product-owned digest approval/revocation. Native layouts do not opt into generated Go capabilities.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
## Permanent destination integration
|
|
31
|
+
|
|
32
|
+
`init --with delegate` / `add delegate` default to `operations: [files.moveFromStaging]`,
|
|
33
|
+
`destinations: [save]`, `lifetime: until-revoked`, `scope: install-selected`. Existing legacy
|
|
34
|
+
TTL declarations retain their 1–3600 second service / 30-day wire ceiling and
|
|
35
|
+
64 MiB / 60-second URL example. Do not apply those limits to the new move API.
|
|
36
|
+
Delegate can coexist with daemon; ordinary standalone jobs cannot. Preserve
|
|
37
|
+
App business route floors. Binary/compose remain unsupported.
|
|
38
|
+
|
|
39
|
+
Use File Station `/home[/...]`, never `/homes/<user>`. The SDK destination picker
|
|
40
|
+
selection itself grants access after fresh DSM session/UID/write verification,
|
|
41
|
+
without a second consent dialog. Ordinary and administrator subjects use their
|
|
42
|
+
own nonzero UID/current groups, never root. An online App can create an in-scope
|
|
43
|
+
grant using a valid session; there is no trusted external consent or notification.
|
|
44
|
+
|
|
45
|
+
Use the default `createBackgroundSaveFacade(ctx)` / CapabilityPanels management
|
|
46
|
+
page. `delegate.status` exposes verified `disabled` and manifest mode; missing
|
|
47
|
+
protected evidence must not imply enabled. `delegate.operations.list` accepts
|
|
48
|
+
only `{}`, uses the backend move mirrors, and returns the caller's username+UID
|
|
49
|
+
operations only, including for admins. Mirrors are not completion receipts:
|
|
50
|
+
query original `delegate.operations.get` and show Saved only for committed with
|
|
51
|
+
a receipt. Cancel by the same reference; revoke by grant ID. Never resubmit
|
|
52
|
+
uncertain/interrupted work. Admin disable is protected and revokes grants;
|
|
53
|
+
enable/mailbox start does not resurrect them. Keep IDs, never session credentials.
|
|
54
|
+
|
|
55
|
+
App-owned daemon completion and scheduled CSV export call configured Go
|
|
56
|
+
`Service.MoveFromStaging` with `delegation_id`, stable `job_id`, private relative
|
|
57
|
+
`staging`, `name`, `size`. No owner/UID selector. Bounds: 16 GiB/file, queued16,
|
|
58
|
+
active1/package, 24-hour attempt, 5-second revalidation ticks (one check at a time, 30-second complete-check deadline; proven timeouts retain private copying, publication still revalidates), 10 MiB operation records,
|
|
59
|
+
50 MiB audit. Scope is a usage restriction, not hard subtree confinement.
|
|
60
|
+
Local production-executor fixtures use fake DSM/peer/bulk writer; do not claim
|
|
61
|
+
NAS ACL, actual writer UID, logout/reboot or full lifecycle acceptance from them.
|
|
62
|
+
Gopeed product wiring remains a separate task.
|
|
63
|
+
|
|
64
|
+
Admission recovery (per job): on `EXECUTOR_UNAVAILABLE`, `EXECUTOR_TIMEOUT`,
|
|
65
|
+
`EXECUTOR_PROTOCOL`, `canceled`, `EXECUTOR_PAUSED`, `queue-full`,
|
|
66
|
+
`STORAGE_ERROR`, `ADMISSION_PENDING`, `jobs_busy` or `jobs_unavailable` (the
|
|
67
|
+
package journal was busy or failed transiently; a caller deadline or cancel
|
|
68
|
+
spent waiting for it is `canceled`), call `MoveFromStaging` again later with
|
|
69
|
+
the same exact params. It queries the original reference first and re-sends
|
|
70
|
+
admission only when the executor does not know it and the pinned source is
|
|
71
|
+
unchanged; executor tuple deduplication keeps one operation, so a lost reply or a
|
|
72
|
+
racing caller never copies twice. At most 10 possibly-delivered sends, 2 s
|
|
73
|
+
backoff doubling to 5 min; the worker sweep does the same. Terminal, do not
|
|
74
|
+
retry: `APP_DENIED`, `DELEGATION_DENIED`, `operation-conflict`, `disabled`,
|
|
75
|
+
`SCOPE_DENIED` and other executor refusals, `STAGING_CHANGED`,
|
|
76
|
+
`ADMISSION_EXHAUSTED`, `spool_unsafe` and `journal_corrupt` (repair the package
|
|
77
|
+
spool first), and `operation-not-found` for an accepted operation.
|
|
78
|
+
Never change job/grant IDs, delete mirrors or call the socket directly to retry.
|
|
79
|
+
|
|
80
|
+
Cancellation (per job): `CancelOperation` / `delegate.operations.cancel` with the
|
|
81
|
+
original ref is idempotent; repeat it with the same ref after any retryable
|
|
82
|
+
error or a lost reply. A reply `queued`→`canceled` is final at once. A copy in
|
|
83
|
+
flight answers `copying` with code `CANCEL_REQUESTED`: the cancel is accepted and
|
|
84
|
+
durable, not finished; poll `OperationStatus` on the same ref until terminal
|
|
85
|
+
(repeating the cancel is harmless). `canceled` (`OPERATION_CANCELED`) guarantees the writer
|
|
86
|
+
stopped, its part file is removed, nothing was published and staging is kept; it
|
|
87
|
+
stays canceled across executor crash, package stop/start and logout. Revoke, scope change and disable store their reason (`grant-revoked`,
|
|
88
|
+
`scope-changed`, `integration-disabled`) the same way: a copy in flight answers
|
|
89
|
+
`CANCEL_REQUESTED` with it and settles `canceled` with it across a restart. A
|
|
90
|
+
copy the executor stops without a cancel ends `interrupted`/`EXECUTOR_PAUSED`
|
|
91
|
+
(`interrupted`/`interrupted` after a crash), never `WRITE_FAILED`. `committed`
|
|
92
|
+
means publication won the race: the file stays (cancel never removes it) and only
|
|
93
|
+
the app record may be dropped. `uncertain` means a publish attempt failed before
|
|
94
|
+
the cancel; keep querying. A cancel of a ref the executor has not admitted yet
|
|
95
|
+
(reserved/sent mirror) returns `canceled` and leaves a tombstone, so a late or
|
|
96
|
+
recovered admission of that ref returns `canceled` and never copies; a producer
|
|
97
|
+
cancel is also written to the mirror first, so `MoveFromStaging` and the worker
|
|
98
|
+
sweep forward the cancel instead of admitting it.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
### Install-selected scope and the destination API
|
|
102
|
+
|
|
103
|
+
- The DSM install wizard dynamically lists local shares (`SYNO.Core.Share list`
|
|
104
|
+
via `api_store`) and offers home. It saves only a package-owned pre-selection
|
|
105
|
+
in `var/delegate-install.json`; never trust that file for authority.
|
|
106
|
+
- The existing administrator PasswordConfirm form displays this pre-selection
|
|
107
|
+
at first enable. `ctx.executor.authorize(password, selectedScope)` confirms it
|
|
108
|
+
through a pinned, exact-readback one-time root task. Settings changes use the
|
|
109
|
+
same form/password path; no App CGI route may set protected scope directly.
|
|
110
|
+
- The executor trusts `/usr/local/etc/synopkgland/<pkg>/delegations/selected-scope.record`
|
|
111
|
+
only. Its scope/generation are runtime protected state; shipped policy pins
|
|
112
|
+
lock the selection mode and operations. Changes revoke old grants and cancel
|
|
113
|
+
pending writes. Change-away-and-back never revives an old grant.
|
|
114
|
+
- Follow `selection` from verified `delegate.status` / `sdk.destination(key)`.
|
|
115
|
+
If the draft differs, display the difference and follow the protected value.
|
|
116
|
+
Home and fixed `shared:<name>` manifests stay compatible.
|
|
117
|
+
- Frontend: `const sdk = createBackgroundSaveFacade(ctx); const current = await
|
|
118
|
+
sdk.destination('save')` returns typed `{key, selection, destination, status}`.
|
|
119
|
+
`selection` contains `{scope, root, generation}`; `destination` is this caller's
|
|
120
|
+
grant or null. Handle active/missing/reselection-required/needs-scope-confirmation/disabled.
|
|
121
|
+
- Go: `Service.Destination(ctx, caller, request, key)` verifies the fresh DSM
|
|
122
|
+
session and username+UID. Capture its active grant ID into the App job. The
|
|
123
|
+
offline producer uses existing `Service.MoveFromStaging`; no user/UID selector,
|
|
124
|
+
cookie, token, or browser path cache. Executor revalidates at use/publication.
|
|
125
|
+
- The generated Background saves page includes a working **Save example file**
|
|
126
|
+
(`sdk.exportExample({key, job_id})`, `delegate.example.export`). Go
|
|
127
|
+
`ExportExample` creates a private JSON file, calls `MoveFromStaging` once, and
|
|
128
|
+
repeats the original request on repeated IDs. Review `example.go` to
|
|
129
|
+
adapt a real producer; show Saved only from a protected committed receipt.
|
|
130
|
+
- Wizard support is measured on vt-nas DSM 7.4 via a session-only SSH local
|
|
131
|
+
forward. This is not proof of other DSM releases or full writer/reboot behavior.
|
|
@@ -27,8 +27,107 @@ synopkgland init -t compose --from ./compose.yaml upstream-app
|
|
|
27
27
|
## Schema 2 能力
|
|
28
28
|
|
|
29
29
|
native-go 與 binary 使用 `dsm-package.yaml` 的 `schema: 2`,backend 寫 `kind: go, dir: backend` 或 `kind: binary, files: {x86_64: prebuilt/api-x86_64}`。
|
|
30
|
-
`--with files,jobs,login,root-ops` 分別宣告 `capabilities.files: session`、`jobs: true`、`identity: standalone`、`rootOps: true`。jobs 可寫 `{worker: sha256-v1}`,與 daemon 互斥;delegate
|
|
30
|
+
`--with files,jobs,login,root-ops,delegate` 分別宣告 `capabilities.files: session`、`jobs: true`、`identity: standalone`、`rootOps: true`、`delegate: {operations: [files.moveFromStaging], destinations: [save], lifetime: until-revoked, scope: install-selected}`。jobs 可寫 `{worker: sha256-v1}`,與 daemon 互斥;delegate 隱含 worker 並可與 daemon 共存;admin/normal 都以本人 UID 執行。binary/compose 不支援 files/jobs/login/delegate。
|
|
31
31
|
既有 native-go 專案用 `synopkgland add files jobs login`;已存在能力回報 no-op。overlay 檔案已有不同內容或 stub 被改動時,add 拒絕並列出衝突;不修改業務 routes 或 App.vue。
|
|
32
32
|
check、inspect、build、deploy、status 支援 `--json`,stdout 只有單一 JSON 物件,錯誤包含 code、message、hint;進度在 stderr。
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
rootOps 與 delegate 已共用管理員 PasswordConfirm 核准的 protected executor、boot/control tasks;精確 task readback 與 digest health 一致才 ready,pins 變更須重核准。native 產品另可明確 opt-in authorization-sdk adapter,不與 generated executor tasks 混用。SDK off stub 與 routes_test.go 的預設 policy scaffold 只有內容仍等於 bundled base 時才會替換;App 自訂版本拒絕。
|
|
35
|
+
|
|
36
|
+
## Permanent destination integration
|
|
37
|
+
|
|
38
|
+
`init --with delegate` / `add delegate` default to `operations: [files.moveFromStaging]`,
|
|
39
|
+
`destinations: [save]`, `lifetime: until-revoked`, `scope: install-selected`. Existing legacy
|
|
40
|
+
TTL declarations retain their 1–3600 second service / 30-day wire ceiling and
|
|
41
|
+
64 MiB / 60-second URL example. Do not apply those limits to the new move API.
|
|
42
|
+
Delegate can coexist with daemon; ordinary standalone jobs cannot. Preserve
|
|
43
|
+
App business route floors. Binary/compose remain unsupported.
|
|
44
|
+
|
|
45
|
+
Use File Station `/home[/...]`, never `/homes/<user>`. The SDK destination picker
|
|
46
|
+
selection itself grants access after fresh DSM session/UID/write verification,
|
|
47
|
+
without a second consent dialog. Ordinary and administrator subjects use their
|
|
48
|
+
own nonzero UID/current groups, never root. An online App can create an in-scope
|
|
49
|
+
grant using a valid session; there is no trusted external consent or notification.
|
|
50
|
+
|
|
51
|
+
Use the default `createBackgroundSaveFacade(ctx)` / CapabilityPanels management
|
|
52
|
+
page. `delegate.status` exposes verified `disabled` and manifest mode; missing
|
|
53
|
+
protected evidence must not imply enabled. `delegate.operations.list` accepts
|
|
54
|
+
only `{}`, uses the backend move mirrors, and returns the caller's username+UID
|
|
55
|
+
operations only, including for admins. Mirrors are not completion receipts:
|
|
56
|
+
query original `delegate.operations.get` and show Saved only for committed with
|
|
57
|
+
a receipt. Cancel by the same reference; revoke by grant ID. Never resubmit
|
|
58
|
+
uncertain/interrupted work. Admin disable is protected and revokes grants;
|
|
59
|
+
enable/mailbox start does not resurrect them. Keep IDs, never session credentials.
|
|
60
|
+
|
|
61
|
+
App-owned daemon completion and scheduled CSV export call configured Go
|
|
62
|
+
`Service.MoveFromStaging` with `delegation_id`, stable `job_id`, private relative
|
|
63
|
+
`staging`, `name`, `size`. No owner/UID selector. Bounds: 16 GiB/file, queued16,
|
|
64
|
+
active1/package, 24-hour attempt, 5-second revalidation ticks (one check at a time, 30-second complete-check deadline; proven timeouts retain private copying, publication still revalidates), 10 MiB operation records,
|
|
65
|
+
50 MiB audit. Scope is a usage restriction, not hard subtree confinement.
|
|
66
|
+
Local production-executor fixtures use fake DSM/peer/bulk writer; do not claim
|
|
67
|
+
NAS ACL, actual writer UID, logout/reboot or full lifecycle acceptance from them.
|
|
68
|
+
Gopeed product wiring remains a separate task.
|
|
69
|
+
|
|
70
|
+
Admission recovery (per job): on `EXECUTOR_UNAVAILABLE`, `EXECUTOR_TIMEOUT`,
|
|
71
|
+
`EXECUTOR_PROTOCOL`, `canceled`, `EXECUTOR_PAUSED`, `queue-full`,
|
|
72
|
+
`STORAGE_ERROR`, `ADMISSION_PENDING`, `jobs_busy` or `jobs_unavailable` (the
|
|
73
|
+
package journal was busy or failed transiently; a caller deadline or cancel
|
|
74
|
+
spent waiting for it is `canceled`), call `MoveFromStaging` again later with
|
|
75
|
+
the same exact params. It queries the original reference first and re-sends
|
|
76
|
+
admission only when the executor does not know it and the pinned source is
|
|
77
|
+
unchanged; executor tuple deduplication keeps one operation, so a lost reply or a
|
|
78
|
+
racing caller never copies twice. At most 10 possibly-delivered sends, 2 s
|
|
79
|
+
backoff doubling to 5 min; the worker sweep does the same. Terminal, do not
|
|
80
|
+
retry: `APP_DENIED`, `DELEGATION_DENIED`, `operation-conflict`, `disabled`,
|
|
81
|
+
`SCOPE_DENIED` and other executor refusals, `STAGING_CHANGED`,
|
|
82
|
+
`ADMISSION_EXHAUSTED`, `spool_unsafe` and `journal_corrupt` (repair the package
|
|
83
|
+
spool first), and `operation-not-found` for an accepted operation.
|
|
84
|
+
Never change job/grant IDs, delete mirrors or call the socket directly to retry.
|
|
85
|
+
|
|
86
|
+
Cancellation (per job): `CancelOperation` / `delegate.operations.cancel` with the
|
|
87
|
+
original ref is idempotent; repeat it with the same ref after any retryable
|
|
88
|
+
error or a lost reply. A reply `queued`→`canceled` is final at once. A copy in
|
|
89
|
+
flight answers `copying` with code `CANCEL_REQUESTED`: the cancel is accepted and
|
|
90
|
+
durable, not finished; poll `OperationStatus` on the same ref until terminal
|
|
91
|
+
(repeating the cancel is harmless). `canceled` (`OPERATION_CANCELED`) guarantees the writer
|
|
92
|
+
stopped, its part file is removed, nothing was published and staging is kept; it
|
|
93
|
+
stays canceled across executor crash, package stop/start and logout. `committed`
|
|
94
|
+
means publication won the race: the file stays (cancel never removes it) and only
|
|
95
|
+
the app record may be dropped. `uncertain` means a publish attempt failed before
|
|
96
|
+
the cancel; keep querying. A cancel of a ref the executor has not admitted yet
|
|
97
|
+
(reserved/sent mirror) returns `canceled` and leaves a tombstone, so a late or
|
|
98
|
+
recovered admission of that ref returns `canceled` and never copies; a producer
|
|
99
|
+
cancel is also written to the mirror first, so `MoveFromStaging` and the worker
|
|
100
|
+
sweep forward the cancel instead of admitting it.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
### Install-selected scope and the destination API
|
|
104
|
+
|
|
105
|
+
- The DSM install wizard dynamically lists local shares (`SYNO.Core.Share list`
|
|
106
|
+
via `api_store`) and offers home. It saves only a package-owned pre-selection
|
|
107
|
+
in `var/delegate-install.json`; never trust that file for authority.
|
|
108
|
+
- The existing administrator PasswordConfirm form displays this pre-selection
|
|
109
|
+
at first enable. `ctx.executor.authorize(password, selectedScope)` confirms it
|
|
110
|
+
through a pinned, exact-readback one-time root task. Settings changes use the
|
|
111
|
+
same form/password path; no App CGI route may set protected scope directly.
|
|
112
|
+
- The executor trusts `/usr/local/etc/synopkgland/<pkg>/delegations/selected-scope.record`
|
|
113
|
+
only. Its scope/generation are runtime protected state; shipped policy pins
|
|
114
|
+
lock the selection mode and operations. Changes revoke old grants and cancel
|
|
115
|
+
pending writes. Change-away-and-back never revives an old grant.
|
|
116
|
+
- Follow `selection` from verified `delegate.status` / `sdk.destination(key)`.
|
|
117
|
+
If the draft differs, display the difference and follow the protected value.
|
|
118
|
+
Home and fixed `shared:<name>` manifests stay compatible.
|
|
119
|
+
- Frontend: `const sdk = createBackgroundSaveFacade(ctx); const current = await
|
|
120
|
+
sdk.destination('save')` returns typed `{key, selection, destination, status}`.
|
|
121
|
+
`selection` contains `{scope, root, generation}`; `destination` is this caller's
|
|
122
|
+
grant or null. Handle active/missing/reselection-required/needs-scope-confirmation/disabled.
|
|
123
|
+
- Go: `Service.Destination(ctx, caller, request, key)` verifies the fresh DSM
|
|
124
|
+
session and username+UID. Capture its active grant ID into the App job. The
|
|
125
|
+
offline producer uses existing `Service.MoveFromStaging`; no user/UID selector,
|
|
126
|
+
cookie, token, or browser path cache. Executor revalidates at use/publication.
|
|
127
|
+
- The generated Background saves page includes a working **Save example file**
|
|
128
|
+
(`sdk.exportExample({key, job_id})`, `delegate.example.export`). Go
|
|
129
|
+
`ExportExample` creates a private JSON file, calls `MoveFromStaging` once, and
|
|
130
|
+
repeats the original request on repeated IDs. Review `example.go` to
|
|
131
|
+
adapt a real producer; show Saved only from a protected committed receipt.
|
|
132
|
+
- Wizard support is measured on vt-nas DSM 7.4 via a session-only SSH local
|
|
133
|
+
forward. This is not proof of other DSM releases or full writer/reboot behavior.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Build and deploy
|
|
2
2
|
|
|
3
|
-
1. Run `synopkgland check` and `synopkgland build --arch x86_64` (use aarch64 for
|
|
3
|
+
1. Run `synopkgland check` and `synopkgland build --arch x86_64` (use aarch64 or armv7 for those targets; armv7 must be listed in `arches`; its jobs, daemon and executor are built but not NAS-verified). deploy detects the NAS arch, except on Marvell CPUs, where it asks for `--arch`.
|
|
4
4
|
2. Inspect the resulting file with `synopkgland inspect <file>`.
|
|
5
5
|
3. Review `synopkgland deploy --dry-run --arch x86_64`, which does not connect to a NAS.
|
|
6
6
|
4. Only when installation is authorized, run `synopkgland deploy --host <profile>`.
|
|
@@ -9,4 +9,4 @@ Deployment uploads directly to DSM. It does not publish artifacts. Container ins
|
|
|
9
9
|
|
|
10
10
|
For native-go root-ops, approve fixed operations in DSM after installation. Updates that change the task text require fresh approval. Remove tasks before uninstall. Never delete installed packages or data as part of a code cleanup.
|
|
11
11
|
|
|
12
|
-
5. After installation run `synopkgland status --host <profile> --json`; inspect every capability state and Open URL. Installation is not readiness.
|
|
12
|
+
5. After installation run `synopkgland status --host <profile> --json`; inspect every capability state and Open URL. Installation is not readiness. Delegate is implemented and shipped (default `files.moveFromStaging`); full device lifecycle acceptance is still pending for the shared delegate/rootOps executor: install → setup → reboot → upgrade → revoke → uninstall. Delete App Data is not evidence of complete cleanup; verify retained directories/account artifacts.
|