@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { HostCredentials, NasHost } from "./types.js";
|
|
2
|
+
import type { NativeArchFamily } from "../build-spk/dsm-arch.js";
|
|
2
3
|
export interface CreateNasHostOptions {
|
|
3
4
|
host?: string;
|
|
4
5
|
credentials?: HostCredentials;
|
|
@@ -17,9 +18,12 @@ declare function synoagentcli(args: string[], profileName?: string): {
|
|
|
17
18
|
export declare function homesPathFromDsmUserHomeRead(result: Pick<ReturnType<typeof synoagentcli>, "status" | "stdout">): string | undefined;
|
|
18
19
|
/**
|
|
19
20
|
* DSM reports the CPU vendor, not the ISA. Every x86_64 platform Synology
|
|
20
|
-
* ships is Intel or AMD;
|
|
21
|
-
* Rockchip
|
|
22
|
-
*
|
|
21
|
+
* ships is Intel or AMD; the aarch64 ones are Realtek (rtd1296, rtd1619b) and
|
|
22
|
+
* Rockchip; Annapurna Labs is DSM 7's alpine/alpine4k, which are armv7 (DS416
|
|
23
|
+
* reports "ANNAPURNALABS"). Marvell makes both armada37xx (aarch64) and
|
|
24
|
+
* armada38x (armv7), so it, like an unrecognised vendor, returns undefined and
|
|
25
|
+
* `deploy` asks for `--arch` rather than guessing wrong and building an
|
|
26
|
+
* unusable SPK.
|
|
23
27
|
*/
|
|
24
|
-
export declare function archFamilyForCpuVendor(vendor: string | undefined):
|
|
28
|
+
export declare function archFamilyForCpuVendor(vendor: string | undefined): NativeArchFamily | undefined;
|
|
25
29
|
export {};
|
package/dist/host/dsm-client.js
CHANGED
|
@@ -275,17 +275,23 @@ function createDsmNasHost(credentials, profileName) {
|
|
|
275
275
|
}
|
|
276
276
|
/**
|
|
277
277
|
* DSM reports the CPU vendor, not the ISA. Every x86_64 platform Synology
|
|
278
|
-
* ships is Intel or AMD;
|
|
279
|
-
* Rockchip
|
|
280
|
-
*
|
|
278
|
+
* ships is Intel or AMD; the aarch64 ones are Realtek (rtd1296, rtd1619b) and
|
|
279
|
+
* Rockchip; Annapurna Labs is DSM 7's alpine/alpine4k, which are armv7 (DS416
|
|
280
|
+
* reports "ANNAPURNALABS"). Marvell makes both armada37xx (aarch64) and
|
|
281
|
+
* armada38x (armv7), so it, like an unrecognised vendor, returns undefined and
|
|
282
|
+
* `deploy` asks for `--arch` rather than guessing wrong and building an
|
|
283
|
+
* unusable SPK.
|
|
281
284
|
*/
|
|
282
285
|
export function archFamilyForCpuVendor(vendor) {
|
|
283
286
|
const normalized = (vendor ?? "").trim().toLowerCase();
|
|
284
287
|
if (normalized === "intel" || normalized === "amd") {
|
|
285
288
|
return "x86_64";
|
|
286
289
|
}
|
|
287
|
-
if (["realtek", "
|
|
290
|
+
if (["realtek", "rockchip"].includes(normalized)) {
|
|
288
291
|
return "aarch64";
|
|
289
292
|
}
|
|
293
|
+
if (["annapurnalabs", "annapurna labs", "annapurna"].includes(normalized)) {
|
|
294
|
+
return "armv7";
|
|
295
|
+
}
|
|
290
296
|
return undefined;
|
|
291
297
|
}
|
package/dist/host/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { SharePermissionListing } from "../deploy/share-permission-prefligh
|
|
|
2
2
|
import type { InstalledPackageState } from "./catalog-install.js";
|
|
3
3
|
import type { PortInfoEntry } from "./port-info.js";
|
|
4
4
|
import type { DsmPortProfileInventory } from "./dsm-port-profile.js";
|
|
5
|
+
import type { NativeArchFamily } from "../build-spk/dsm-arch.js";
|
|
5
6
|
export interface DeployIdentity {
|
|
6
7
|
packageId: string;
|
|
7
8
|
displayname: string;
|
|
@@ -33,7 +34,7 @@ export interface NasHost {
|
|
|
33
34
|
executor_digest: string;
|
|
34
35
|
policy_digest: string;
|
|
35
36
|
} | undefined>;
|
|
36
|
-
getArchFamily?(): Promise<
|
|
37
|
+
getArchFamily?(): Promise<NativeArchFamily | undefined>;
|
|
37
38
|
/** List the current logical Shared Folder names using an administrator session. */
|
|
38
39
|
listShareNames?(): Promise<string[]>;
|
|
39
40
|
resolveSharePath?(logicalName: string): Promise<string | undefined>;
|
package/dist/info.js
CHANGED
|
@@ -5,7 +5,8 @@ import { appOriginFromContract } from "./host/open-url.js";
|
|
|
5
5
|
import { resolveDeployIdentity } from "./deploy/identity.js";
|
|
6
6
|
import { loadStandaloneManifest, } from "./standalone/manifest.js";
|
|
7
7
|
import { inspectSpk } from "./standalone/inspect-spk.js";
|
|
8
|
-
import { executorPolicy } from "./runtime/executor-policy.js";
|
|
8
|
+
import { executorPolicy, executorPolicyText, sha256 } from "./runtime/executor-policy.js";
|
|
9
|
+
import { executorTasks } from "./runtime/executor-tasks.js";
|
|
9
10
|
import { uninstallCleanup } from "./runtime/uninstall-cleanup.js";
|
|
10
11
|
export async function projectInfo(options) {
|
|
11
12
|
const identity = resolveDeployIdentity(options.project, { dev: options.dev });
|
|
@@ -63,6 +64,21 @@ export function classifyRootTasks(expected, inventory) {
|
|
|
63
64
|
? result("needs-admin-approval", "Approve missing or outdated root tasks in the DSM package UI.")
|
|
64
65
|
: result("ready", "Boot and control tasks match the executor and policy digests. Executor health must be checked in the App window.");
|
|
65
66
|
}
|
|
67
|
+
async function liveRootCapability(m, host) {
|
|
68
|
+
try {
|
|
69
|
+
const policyDigest = sha256(executorPolicyText(executorPolicy(m)));
|
|
70
|
+
const classified = classifyRootTasks(executorTasks({ package: m.package, policyDigest }), await host.getRootTaskInventory?.(m.package));
|
|
71
|
+
if (classified.state !== "ready")
|
|
72
|
+
return classified;
|
|
73
|
+
const observed = await host.getExecutorStatus?.(m.package);
|
|
74
|
+
if (observed?.ready !== true || observed.policy_digest !== policyDigest)
|
|
75
|
+
return { ...classified, state: "blocked", reason: "Executor health or policy digest readback could not be verified." };
|
|
76
|
+
return { ...classified, reason: "Root tasks and the running executor match the source policy (no local SPK, so executor bytes were not compared)." };
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return { name: "rootOps", state: "blocked", reason: "DSM executor or root task readback could not be verified." };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
66
82
|
async function rootCapability(m, host, version) {
|
|
67
83
|
const blocked = (reason) => ({
|
|
68
84
|
name: "rootOps",
|
|
@@ -82,7 +98,7 @@ async function rootCapability(m, host, version) {
|
|
|
82
98
|
return blocked("NAS architecture cannot be matched to the local executor SPK artifact.");
|
|
83
99
|
const spk = join(m.root, "dist", `${m.package}-${version}-${arch}.spk`);
|
|
84
100
|
if (!existsSync(spk))
|
|
85
|
-
return
|
|
101
|
+
return liveRootCapability(m, host);
|
|
86
102
|
try {
|
|
87
103
|
const inspected = await inspectSpk(spk);
|
|
88
104
|
if (inspected.findings.length ||
|
package/dist/init.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { type CapabilityName } from "./capabilities.js";
|
|
1
2
|
import type { TemplateName } from "./types.js";
|
|
2
3
|
/** The container templates need DSM 7.2.1 or later; native-go and binary need 7.1. */
|
|
3
4
|
export declare function isContainerTemplate(template: TemplateName): boolean;
|
|
4
5
|
export declare function isTemplateName(value: string): value is TemplateName;
|
|
5
6
|
export declare function listTemplates(): TemplateName[];
|
|
7
|
+
/** New native scaffolds opt in explicitly; existing manifests are never migrated. */
|
|
8
|
+
export declare function nativeCapabilitySettings(names: readonly CapabilityName[]): Record<string, unknown>;
|
|
6
9
|
export interface InitOptions {
|
|
7
10
|
/** os_min_ver of the new project: a release (7.2) or a full 7.x-build; default is the template's (DSM 7.1 for native-go/binary, DSM 7.2.1 for container templates). */
|
|
8
11
|
minDsm?: string;
|
package/dist/init.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { parse, stringify } from "yaml";
|
|
2
|
+
import { isMap, isScalar, parse, parseDocument, stringify } from "yaml";
|
|
3
3
|
import { capabilityNames, capabilitySettings } from "./capabilities.js";
|
|
4
|
+
import { MOVE_FROM_STAGING } from './runtime/delegate-contract.js';
|
|
4
5
|
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
5
6
|
import { basename, join, relative } from "node:path";
|
|
6
7
|
import { templatesRoot } from "./template-paths.js";
|
|
@@ -25,6 +26,15 @@ export function isTemplateName(value) {
|
|
|
25
26
|
export function listTemplates() {
|
|
26
27
|
return [...TEMPLATE_NAMES];
|
|
27
28
|
}
|
|
29
|
+
/** New native scaffolds opt in explicitly; existing manifests are never migrated. */
|
|
30
|
+
export function nativeCapabilitySettings(names) {
|
|
31
|
+
const settings = capabilitySettings(names);
|
|
32
|
+
if (names.includes('delegate'))
|
|
33
|
+
settings.delegate = {
|
|
34
|
+
scope: 'install-selected', operations: [MOVE_FROM_STAGING], destinations: ['save'], lifetime: 'until-revoked',
|
|
35
|
+
};
|
|
36
|
+
return settings;
|
|
37
|
+
}
|
|
28
38
|
/**
|
|
29
39
|
* native-go --with root-ops: files laid over the native-go template, and the
|
|
30
40
|
* files they replace.
|
|
@@ -85,10 +95,12 @@ function isTemplateBuildArtifact(path) {
|
|
|
85
95
|
}
|
|
86
96
|
export function initFromTemplate(template, targetDir, options = {}) {
|
|
87
97
|
if (!isTemplateName(template))
|
|
88
|
-
throw new Error(`[
|
|
98
|
+
throw new Error(`[INIT_TEMPLATE_UNKNOWN] 未知模板:${template}`);
|
|
89
99
|
const caps = capabilityNames(options.with ?? []);
|
|
90
100
|
if (caps.includes("login") && resolvedUi(template, options) === "plain")
|
|
91
101
|
throw new Error("[CAPABILITY_COMBINATION_INVALID] login 需要獨立登入頁;plain UI 不支援,請改用 --ui vue。");
|
|
102
|
+
if (caps.includes("delegate") && resolvedUi(template, options) === "plain")
|
|
103
|
+
throw new Error("[CAPABILITY_COMBINATION_INVALID] delegate 的 install-selected scope 只能在 Vue 面板確認;plain UI 不支援,請改用 --ui vue。");
|
|
92
104
|
if (options.from && template !== "compose")
|
|
93
105
|
throw new Error("[INIT_OPTIONS_UNSUPPORTED] --from 只適用於 compose。");
|
|
94
106
|
if (caps.length && template !== "native-go")
|
|
@@ -194,20 +206,11 @@ export function initFromTemplate(template, targetDir, options = {}) {
|
|
|
194
206
|
if (template !== "compose") {
|
|
195
207
|
const path = join(targetDir, "dsm-package.yaml");
|
|
196
208
|
const raw = parse(readFileSync(path, "utf8"));
|
|
197
|
-
raw.capabilities =
|
|
198
|
-
writeFileSync(path, stringify(raw));
|
|
199
|
-
}
|
|
200
|
-
if (template === "compose" && options.from) {
|
|
201
|
-
const imported = readFileSync(options.from, "utf8");
|
|
202
|
-
const compose = parse(imported);
|
|
203
|
-
if (!compose || typeof compose !== "object" || !compose.services)
|
|
204
|
-
throw new Error("[INIT_COMPOSE_INVALID] --from 需要包含 services 的 Compose YAML。");
|
|
205
|
-
writeFileSync(join(targetDir, "compose.yaml"), imported);
|
|
206
|
-
const path = join(targetDir, "synology-app.yaml");
|
|
207
|
-
const raw = parse(readFileSync(path, "utf8"));
|
|
208
|
-
delete raw.install;
|
|
209
|
+
raw.capabilities = nativeCapabilitySettings(caps);
|
|
209
210
|
writeFileSync(path, stringify(raw));
|
|
210
211
|
}
|
|
212
|
+
if (template === "compose" && options.from)
|
|
213
|
+
importCompose(options.from, targetDir, options);
|
|
211
214
|
if (template === "binary") {
|
|
212
215
|
mkdirSync(join(targetDir, "prebuilt"), { recursive: true });
|
|
213
216
|
for (const [arch, goarch] of [["x86_64", "amd64"], ["aarch64", "arm64"]]) {
|
|
@@ -221,6 +224,35 @@ export function initFromTemplate(template, targetDir, options = {}) {
|
|
|
221
224
|
writeFileSync(manifest, readFileSync(manifest, "utf8") + sharedFolderYaml(options.sharedFolder));
|
|
222
225
|
}
|
|
223
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* --from replaces the example Compose. The manifest takes the requested (or
|
|
229
|
+
* directory-derived) identity and keeps only the example install entries the
|
|
230
|
+
* imported Compose references as `${KEY}` (or `${KEY_UID}`/`${KEY_GID}`).
|
|
231
|
+
*/
|
|
232
|
+
function importCompose(from, targetDir, options) {
|
|
233
|
+
const imported = readFileSync(from, "utf8");
|
|
234
|
+
const compose = parse(imported);
|
|
235
|
+
if (!compose || typeof compose !== "object" || !compose.services)
|
|
236
|
+
throw new Error("[INIT_COMPOSE_INVALID] --from 需要包含 services 的 Compose YAML。");
|
|
237
|
+
writeFileSync(join(targetDir, "compose.yaml"), imported);
|
|
238
|
+
const path = join(targetDir, "synology-app.yaml");
|
|
239
|
+
const doc = parseDocument(readFileSync(path, "utf8"));
|
|
240
|
+
doc.set("package", options.packageId ?? defaultPackageId(targetDir));
|
|
241
|
+
doc.set("displayname", validDisplayName(options.displayName ?? defaultDisplayName(targetDir)));
|
|
242
|
+
const install = doc.get("install");
|
|
243
|
+
const referenced = new Set([...imported.matchAll(/\$\{([A-Z][A-Z0-9_]*?)(?:_UID|_GID)?\}/g)].map(match => match[1]));
|
|
244
|
+
if (isMap(install))
|
|
245
|
+
install.items = install.items.filter(item => referenced.has(String(isScalar(item.key) ? item.key.value : item.key)));
|
|
246
|
+
if (!isMap(install) || install.items.length === 0)
|
|
247
|
+
doc.delete("install");
|
|
248
|
+
writeFileSync(path, String(doc));
|
|
249
|
+
}
|
|
250
|
+
function validDisplayName(displayName) {
|
|
251
|
+
if (displayName.trim() === "" || /[\r\n"\\]/.test(displayName)) {
|
|
252
|
+
throw new Error("[INIT_DISPLAY_NAME_INVALID] 顯示名稱必須是單行,且不含 \" 或 \\。");
|
|
253
|
+
}
|
|
254
|
+
return displayName;
|
|
255
|
+
}
|
|
224
256
|
/** The `install.sharedFolder` block, validated by the same reader build-spk uses. */
|
|
225
257
|
function sharedFolderYaml(options) {
|
|
226
258
|
const folder = { mode: options.mode, key: options.key ?? "shared", ...(options.name === undefined ? {} : { name: options.name }), permission: options.permission ?? "rw" };
|
|
@@ -243,15 +275,14 @@ function substitutionsFor(template, targetDir, options) {
|
|
|
243
275
|
if (options.ui !== undefined && !["plain", "vue"].includes(options.ui))
|
|
244
276
|
throw new Error("[INIT_UI_INVALID] --ui 只接受 plain 或 vue。");
|
|
245
277
|
if (!SUBSTITUTED[template]) {
|
|
278
|
+
if (options.from && options.displayName !== undefined)
|
|
279
|
+
validDisplayName(options.displayName);
|
|
246
280
|
return {};
|
|
247
281
|
}
|
|
248
282
|
const packageId = options.packageId ?? defaultPackageId(targetDir);
|
|
249
283
|
if (!PACKAGE_ID.test(packageId)) {
|
|
250
284
|
throw new Error(`[INIT_PACKAGE_INVALID] package「${packageId}」必須以英文字母開頭,只含英數字(2–64 字),例如 PhotoTagger。`);
|
|
251
285
|
}
|
|
252
|
-
const displayName = options.displayName ?? defaultDisplayName(targetDir);
|
|
253
|
-
if (displayName.trim() === "" || /[\r\n"\\]/.test(displayName)) {
|
|
254
|
-
throw new Error("[INIT_DISPLAY_NAME_INVALID] 顯示名稱必須是單行,且不含 \" 或 \\。");
|
|
255
|
-
}
|
|
286
|
+
const displayName = validDisplayName(options.displayName ?? defaultDisplayName(targetDir));
|
|
256
287
|
return { __PACKAGE__: packageId, __DISPLAY_NAME__: displayName, __BACKGROUND_ENABLED__: caps.includes("jobs") || caps.includes("delegate") ? "true" : "false" };
|
|
257
288
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Plain text, or a map from a BCP-47 tag (en, zh-TW, ...) to plain text. */
|
|
2
|
+
export type LocalizedText = string | Record<string, string>;
|
|
3
|
+
export interface PackageMetadata {
|
|
4
|
+
long_description?: LocalizedText;
|
|
5
|
+
changelog?: LocalizedText;
|
|
6
|
+
contact_email?: string;
|
|
7
|
+
support_email?: string;
|
|
8
|
+
homepage?: string;
|
|
9
|
+
source_url?: string;
|
|
10
|
+
issues_url?: string;
|
|
11
|
+
license?: string;
|
|
12
|
+
maintainer_url?: string;
|
|
13
|
+
distributor?: string;
|
|
14
|
+
distributor_url?: string;
|
|
15
|
+
support_url?: string;
|
|
16
|
+
helpurl?: string;
|
|
17
|
+
screenshots?: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function safeMetadataUrl(value: unknown, mail?: boolean): value is string;
|
|
20
|
+
export declare function validateMetadata(raw: unknown): PackageMetadata;
|
|
21
|
+
export declare function metadataInfoFields(metadata?: PackageMetadata): [string, string][];
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export function safeMetadataUrl(value, mail = false) {
|
|
2
|
+
if (typeof value !== "string" || value.length > 2048)
|
|
3
|
+
return false;
|
|
4
|
+
try {
|
|
5
|
+
const u = new URL(value);
|
|
6
|
+
return (!u.username &&
|
|
7
|
+
!u.password &&
|
|
8
|
+
(["https:", "http:"].includes(u.protocol) ||
|
|
9
|
+
(mail &&
|
|
10
|
+
u.protocol === "mailto:" &&
|
|
11
|
+
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(u.pathname))));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function validateMetadata(raw) {
|
|
18
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
19
|
+
throw new Error("invalid metadata");
|
|
20
|
+
const allowed = [
|
|
21
|
+
"long_description",
|
|
22
|
+
"changelog",
|
|
23
|
+
"contact_email",
|
|
24
|
+
"support_email",
|
|
25
|
+
"homepage",
|
|
26
|
+
"source_url",
|
|
27
|
+
"issues_url",
|
|
28
|
+
"license",
|
|
29
|
+
"maintainer_url",
|
|
30
|
+
"distributor",
|
|
31
|
+
"distributor_url",
|
|
32
|
+
"support_url",
|
|
33
|
+
"helpurl",
|
|
34
|
+
"screenshots",
|
|
35
|
+
];
|
|
36
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
37
|
+
if (!allowed.includes(k))
|
|
38
|
+
throw new Error("unknown metadata");
|
|
39
|
+
if (k === "screenshots") {
|
|
40
|
+
if (!Array.isArray(v) ||
|
|
41
|
+
v.length > 12 ||
|
|
42
|
+
!v.every((u) => safeMetadataUrl(u)))
|
|
43
|
+
throw new Error("invalid screenshots");
|
|
44
|
+
}
|
|
45
|
+
else if ((k === "long_description" || k === "changelog") &&
|
|
46
|
+
typeof v === "object" &&
|
|
47
|
+
v &&
|
|
48
|
+
!Array.isArray(v)) {
|
|
49
|
+
if (Object.entries(v).length > 32 ||
|
|
50
|
+
!Object.entries(v).every(([lang, t]) => /^[a-z]{2}(?:-[A-Za-z]{2})?$/.test(lang) &&
|
|
51
|
+
typeof t === "string" &&
|
|
52
|
+
t.length <= 16000 &&
|
|
53
|
+
!/[\x00-\x08\x0b\x0c\x0e-\x1f]/.test(t)))
|
|
54
|
+
throw new Error("invalid localized description");
|
|
55
|
+
}
|
|
56
|
+
else if (typeof v !== "string" ||
|
|
57
|
+
v.length > 16000 ||
|
|
58
|
+
/[\x00-\x08\x0b\x0c\x0e-\x1f]/.test(v))
|
|
59
|
+
throw new Error("invalid text");
|
|
60
|
+
if (k.endsWith("_email") &&
|
|
61
|
+
(typeof v !== "string" || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)))
|
|
62
|
+
throw new Error("invalid email");
|
|
63
|
+
if ([
|
|
64
|
+
"homepage",
|
|
65
|
+
"source_url",
|
|
66
|
+
"issues_url",
|
|
67
|
+
"maintainer_url",
|
|
68
|
+
"distributor_url",
|
|
69
|
+
"support_url",
|
|
70
|
+
"helpurl",
|
|
71
|
+
].includes(k) &&
|
|
72
|
+
!safeMetadataUrl(v, k === "support_url"))
|
|
73
|
+
throw new Error("invalid metadata URL");
|
|
74
|
+
}
|
|
75
|
+
if (JSON.stringify(raw).length > 32000)
|
|
76
|
+
throw new Error("metadata too large");
|
|
77
|
+
return raw;
|
|
78
|
+
}
|
|
79
|
+
export function metadataInfoFields(metadata) {
|
|
80
|
+
if (!metadata)
|
|
81
|
+
return [];
|
|
82
|
+
const m = validateMetadata(metadata), fields = [];
|
|
83
|
+
// INFO has one changelog; a per-language map contributes its English text.
|
|
84
|
+
const changelog = typeof m.changelog === "object"
|
|
85
|
+
? (m.changelog.en ?? Object.values(m.changelog)[0])
|
|
86
|
+
: m.changelog;
|
|
87
|
+
for (const [k, v] of [
|
|
88
|
+
["maintainer_url", m.maintainer_url],
|
|
89
|
+
["distributor", m.distributor],
|
|
90
|
+
["distributor_url", m.distributor_url],
|
|
91
|
+
["support_url", m.support_url],
|
|
92
|
+
["helpurl", m.helpurl],
|
|
93
|
+
["changelog", changelog],
|
|
94
|
+
])
|
|
95
|
+
if (v)
|
|
96
|
+
fields.push([k, v.replace(/\r?\n/g, " · ")]);
|
|
97
|
+
if (!m.support_url && m.support_email)
|
|
98
|
+
fields.push(["support_url", "mailto:" + m.support_email]);
|
|
99
|
+
fields.push(["spk_land_metadata", JSON.stringify(m)]);
|
|
100
|
+
return fields;
|
|
101
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AppContract } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* DSM Application Portal alias: `https://<nas>/<alias>/` opens the App after
|
|
4
|
+
* DSM sign-in. DSM itself only refuses empty aliases (4100), synoman
|
|
5
|
+
* directory names (4102) and aliases another App uses (4103); the SDK keeps a
|
|
6
|
+
* stricter, URL-safe rule so the same value works in links and shell scripts.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PORTAL_ALIAS_PATTERN: RegExp;
|
|
9
|
+
export declare const PORTAL_ALIAS_MAX = 64;
|
|
10
|
+
/**
|
|
11
|
+
* Names DSM already serves: /usr/syno/synoman entries and the default aliases
|
|
12
|
+
* of Synology Apps, as observed on DSM 7.4-90069. DSM stays the authority.
|
|
13
|
+
*/
|
|
14
|
+
export declare const RESERVED_PORTAL_ALIASES: readonly string[];
|
|
15
|
+
export interface PortalDeclaration {
|
|
16
|
+
alias: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function isPortalAlias(value: unknown): value is string;
|
|
19
|
+
/** The package name as a slug; a reserved or too long name falls back to a stable hash. */
|
|
20
|
+
export declare function defaultPortalAlias(packageId: string): string;
|
|
21
|
+
/** `{}` or `{alias}`; undefined for any other shape. */
|
|
22
|
+
export declare function readPortalDeclaration(value: unknown, packageId: string): PortalDeclaration | undefined;
|
|
23
|
+
/** A Compose App reaches the portal only as a DSM window behind the DSM-authenticated gateway. */
|
|
24
|
+
export declare function contractPortalSupported(contract: AppContract): boolean;
|
|
25
|
+
export declare function resolvedContractPortal(contract: AppContract): PortalDeclaration | undefined;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readWebIntegration, resolvedWebLaunch, usesAuthGateway } from "../contract/web-launch.js";
|
|
3
|
+
/**
|
|
4
|
+
* DSM Application Portal alias: `https://<nas>/<alias>/` opens the App after
|
|
5
|
+
* DSM sign-in. DSM itself only refuses empty aliases (4100), synoman
|
|
6
|
+
* directory names (4102) and aliases another App uses (4103); the SDK keeps a
|
|
7
|
+
* stricter, URL-safe rule so the same value works in links and shell scripts.
|
|
8
|
+
*/
|
|
9
|
+
export const PORTAL_ALIAS_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
10
|
+
export const PORTAL_ALIAS_MAX = 64;
|
|
11
|
+
/**
|
|
12
|
+
* Names DSM already serves: /usr/syno/synoman entries and the default aliases
|
|
13
|
+
* of Synology Apps, as observed on DSM 7.4-90069. DSM stays the authority.
|
|
14
|
+
*/
|
|
15
|
+
export const RESERVED_PORTAL_ALIASES = [
|
|
16
|
+
"dsfile", "indexdb", "mobile", "oauth", "scripts", "sharing", "ssdp", "synosdsjslib", "synohdpack", "webapi", "webman",
|
|
17
|
+
"calendar", "chatplus", "contacts", "drive", "file", "photo", "sso", "synologymeet",
|
|
18
|
+
];
|
|
19
|
+
export function isPortalAlias(value) {
|
|
20
|
+
return typeof value === "string" && PORTAL_ALIAS_PATTERN.test(value) && !RESERVED_PORTAL_ALIASES.includes(value);
|
|
21
|
+
}
|
|
22
|
+
/** The package name as a slug; a reserved or too long name falls back to a stable hash. */
|
|
23
|
+
export function defaultPortalAlias(packageId) {
|
|
24
|
+
const slug = packageId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
25
|
+
return isPortalAlias(slug) ? slug : `app-${createHash("sha256").update(packageId).digest("hex").slice(0, 12)}`;
|
|
26
|
+
}
|
|
27
|
+
/** `{}` or `{alias}`; undefined for any other shape. */
|
|
28
|
+
export function readPortalDeclaration(value, packageId) {
|
|
29
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
30
|
+
return undefined;
|
|
31
|
+
const keys = Object.keys(value);
|
|
32
|
+
if (keys.some((key) => key !== "alias"))
|
|
33
|
+
return undefined;
|
|
34
|
+
const alias = value.alias;
|
|
35
|
+
if (alias === undefined)
|
|
36
|
+
return { alias: defaultPortalAlias(packageId) };
|
|
37
|
+
return isPortalAlias(alias) ? { alias } : undefined;
|
|
38
|
+
}
|
|
39
|
+
/** A Compose App reaches the portal only as a DSM window behind the DSM-authenticated gateway. */
|
|
40
|
+
export function contractPortalSupported(contract) {
|
|
41
|
+
return resolvedWebLaunch(contract) === "dsm-window" && usesAuthGateway(contract);
|
|
42
|
+
}
|
|
43
|
+
export function resolvedContractPortal(contract) {
|
|
44
|
+
const portal = readWebIntegration(contract)?.portal;
|
|
45
|
+
if (portal === undefined || !contractPortalSupported(contract))
|
|
46
|
+
return undefined;
|
|
47
|
+
return readPortalDeclaration(portal, String(contract.package ?? ""));
|
|
48
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Translate } from "../build-spk/wizard-i18n.js";
|
|
2
|
+
import type { InstallWizardStep } from "../build-spk/install-wizard.js";
|
|
3
|
+
import type { AppContract } from "../types.js";
|
|
4
|
+
/** Package payload paths DSM's app-portal worker copies to /usr/syno/etc/www/app.d at start. */
|
|
5
|
+
export declare const PORTAL_JSON_RELPATH = "etc/portal.json";
|
|
6
|
+
export declare const PORTAL_MUSTACHE_RELPATH = "etc/portal.mustache";
|
|
7
|
+
/** Install wizard key; DSM exports it to preinst/postinst. */
|
|
8
|
+
export declare const PORTAL_INSTALL_KEY = "portal_alias";
|
|
9
|
+
/** Package-owned install draft, never DSM's saved portal configuration. */
|
|
10
|
+
export declare const PORTAL_DRAFT = "portal-install.json";
|
|
11
|
+
export interface PortalPackage {
|
|
12
|
+
/** The DSM app id the alias opens: an AppInstance or a `.url` entry of ui/config. */
|
|
13
|
+
appId: string;
|
|
14
|
+
/** Control Panel display name. */
|
|
15
|
+
application: string;
|
|
16
|
+
/** Default alias; the wizard answer replaces it. */
|
|
17
|
+
alias: string;
|
|
18
|
+
}
|
|
19
|
+
/** A Compose portal opens the App's `.url` entry of ui/config, keyed by the package id. */
|
|
20
|
+
export declare function contractPortal(contract: AppContract): PortalPackage | undefined;
|
|
21
|
+
export declare function portalResource(): Record<string, unknown>;
|
|
22
|
+
/** Every field of DSM's own app.d files; the worker refuses a partial file (synopkg start 272). */
|
|
23
|
+
export declare function renderPortalJson(portal: PortalPackage): string;
|
|
24
|
+
/** DSM's CGI location: index.cgi launches the app id nginx passes as REWRITE_APP. */
|
|
25
|
+
export declare function renderPortalMustache(): string;
|
|
26
|
+
export declare function renderPortalWizardItems(t: Translate, alias: string): Array<Record<string, unknown>>;
|
|
27
|
+
export declare function renderPortalWizardStep(t: Translate, alias: string): InstallWizardStep;
|
|
28
|
+
/**
|
|
29
|
+
* preinst validates the wizard answer, postinst stores it and writes it as the
|
|
30
|
+
* default alias of the package's own portal.json, postupgrade restores it into
|
|
31
|
+
* the new payload. Activation stays an administrator's AppPortal set call.
|
|
32
|
+
*/
|
|
33
|
+
export declare function renderPortalLifecycle(name: string, portal: PortalPackage): string;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { PORTAL_ALIAS_MAX, PORTAL_ALIAS_PATTERN, RESERVED_PORTAL_ALIASES, resolvedContractPortal } from "./alias.js";
|
|
2
|
+
/** Package payload paths DSM's app-portal worker copies to /usr/syno/etc/www/app.d at start. */
|
|
3
|
+
export const PORTAL_JSON_RELPATH = "etc/portal.json";
|
|
4
|
+
export const PORTAL_MUSTACHE_RELPATH = "etc/portal.mustache";
|
|
5
|
+
/** Install wizard key; DSM exports it to preinst/postinst. */
|
|
6
|
+
export const PORTAL_INSTALL_KEY = "portal_alias";
|
|
7
|
+
/** Package-owned install draft, never DSM's saved portal configuration. */
|
|
8
|
+
export const PORTAL_DRAFT = "portal-install.json";
|
|
9
|
+
/** A Compose portal opens the App's `.url` entry of ui/config, keyed by the package id. */
|
|
10
|
+
export function contractPortal(contract) {
|
|
11
|
+
const portal = resolvedContractPortal(contract);
|
|
12
|
+
const packageId = String(contract.package);
|
|
13
|
+
return portal && { appId: packageId, application: String(contract.displayname ?? packageId), alias: portal.alias };
|
|
14
|
+
}
|
|
15
|
+
export function portalResource() {
|
|
16
|
+
return { "web-config": { "app-portal": { "json-relpath": PORTAL_JSON_RELPATH, "mustache-relpath": PORTAL_MUSTACHE_RELPATH } } };
|
|
17
|
+
}
|
|
18
|
+
/** Every field of DSM's own app.d files; the worker refuses a partial file (synopkg start 272). */
|
|
19
|
+
export function renderPortalJson(portal) {
|
|
20
|
+
return `${JSON.stringify({
|
|
21
|
+
application: portal.application,
|
|
22
|
+
id: portal.appId,
|
|
23
|
+
alias: portal.alias,
|
|
24
|
+
fqdn: null,
|
|
25
|
+
alternatePort: {},
|
|
26
|
+
"x-accel": false,
|
|
27
|
+
include: [],
|
|
28
|
+
injectable: false,
|
|
29
|
+
ssl: { spdy: false, hsts: false },
|
|
30
|
+
index: "index.cgi",
|
|
31
|
+
root: "/usr/syno/synoman",
|
|
32
|
+
version: 2,
|
|
33
|
+
})}\n`;
|
|
34
|
+
}
|
|
35
|
+
/** DSM's CGI location: index.cgi launches the app id nginx passes as REWRITE_APP. */
|
|
36
|
+
export function renderPortalMustache() {
|
|
37
|
+
return "{{> /usr/syno/share/nginx/cgi}}\n";
|
|
38
|
+
}
|
|
39
|
+
/** DSM renders wizard descriptions as HTML; "<alias>" would vanish as a tag. */
|
|
40
|
+
function htmlText(text) {
|
|
41
|
+
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
42
|
+
}
|
|
43
|
+
export function renderPortalWizardItems(t, alias) {
|
|
44
|
+
return [
|
|
45
|
+
{ desc: htmlText(t("portal.notice")) },
|
|
46
|
+
{
|
|
47
|
+
type: "textfield",
|
|
48
|
+
desc: t("portal.alias"),
|
|
49
|
+
subitems: [{
|
|
50
|
+
key: PORTAL_INSTALL_KEY,
|
|
51
|
+
desc: t("portal.alias"),
|
|
52
|
+
defaultValue: alias,
|
|
53
|
+
validator: { allowBlank: false, regex: { expr: `/${PORTAL_ALIAS_PATTERN.source}/`, errorText: t("portal.aliasInvalid") } },
|
|
54
|
+
}],
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
export function renderPortalWizardStep(t, alias) {
|
|
59
|
+
return { step_title: t("portal.step"), items: renderPortalWizardItems(t, alias) };
|
|
60
|
+
}
|
|
61
|
+
function shellQuote(value) {
|
|
62
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
63
|
+
}
|
|
64
|
+
const MARKER = "SYNOPKGLAND_PORTAL_ALIAS";
|
|
65
|
+
/**
|
|
66
|
+
* preinst validates the wizard answer, postinst stores it and writes it as the
|
|
67
|
+
* default alias of the package's own portal.json, postupgrade restores it into
|
|
68
|
+
* the new payload. Activation stays an administrator's AppPortal set call.
|
|
69
|
+
*/
|
|
70
|
+
export function renderPortalLifecycle(name, portal) {
|
|
71
|
+
if (!["preinst", "postinst", "postupgrade"].includes(name))
|
|
72
|
+
return "";
|
|
73
|
+
const [prefix, suffix] = renderPortalJson({ ...portal, alias: MARKER }).trimEnd().split(MARKER);
|
|
74
|
+
const helpers = `synopkgland_portal_valid() {
|
|
75
|
+
case "$1" in ''|-*|*-|*[!a-z0-9-]*) return 1 ;; esac
|
|
76
|
+
[ "\${#1}" -le ${PORTAL_ALIAS_MAX} ] || return 1
|
|
77
|
+
case ' ${RESERVED_PORTAL_ALIASES.join(" ")} ' in *" $1 "*) return 1 ;; esac
|
|
78
|
+
return 0
|
|
79
|
+
}
|
|
80
|
+
synopkgland_portal_var="\${SYNOPKG_PKGVAR:-/var/packages/\${SYNOPKG_PKGNAME:-}/var}"
|
|
81
|
+
synopkgland_portal_json="\${SYNOPKG_PKGDEST:-/var/packages/\${SYNOPKG_PKGNAME:-}/target}/${PORTAL_JSON_RELPATH}"
|
|
82
|
+
synopkgland_portal_write() {
|
|
83
|
+
synopkgland_portal_tmp="$synopkgland_portal_json.$$"
|
|
84
|
+
printf '%s%s%s\\n' ${shellQuote(prefix)} "$1" ${shellQuote(suffix)} > "$synopkgland_portal_tmp" &&
|
|
85
|
+
chmod 644 "$synopkgland_portal_tmp" && mv -f "$synopkgland_portal_tmp" "$synopkgland_portal_json"
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
const answer = `synopkgland_portal_alias="\${${PORTAL_INSTALL_KEY}:-${portal.alias}}"
|
|
89
|
+
if ! synopkgland_portal_valid "$synopkgland_portal_alias"; then
|
|
90
|
+
echo "Application Portal alias: use 1-64 lowercase letters, digits or -, not a DSM path." >&2
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
93
|
+
`;
|
|
94
|
+
if (name === "preinst") {
|
|
95
|
+
return `${helpers}if [ "\${SYNOPKG_PKG_STATUS:-}" != UPGRADE ]; then
|
|
96
|
+
${answer}fi
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
if (name === "postinst") {
|
|
100
|
+
return `${helpers}if [ "\${SYNOPKG_PKG_STATUS:-}" != UPGRADE ]; then
|
|
101
|
+
${answer} (umask 077 && mkdir -p "$synopkgland_portal_var" &&
|
|
102
|
+
printf '{"schema":1,"alias":"%s"}\\n' "$synopkgland_portal_alias" > "$synopkgland_portal_var/.${PORTAL_DRAFT}.$$" &&
|
|
103
|
+
mv -f "$synopkgland_portal_var/.${PORTAL_DRAFT}.$$" "$synopkgland_portal_var/${PORTAL_DRAFT}") || exit 1
|
|
104
|
+
synopkgland_portal_write "$synopkgland_portal_alias" || exit 1
|
|
105
|
+
fi
|
|
106
|
+
`;
|
|
107
|
+
}
|
|
108
|
+
return `${helpers}synopkgland_portal_draft="$synopkgland_portal_var/${PORTAL_DRAFT}"
|
|
109
|
+
if [ -f "$synopkgland_portal_draft" ] && [ ! -L "$synopkgland_portal_draft" ]; then
|
|
110
|
+
synopkgland_portal_alias="$(head -c 128 "$synopkgland_portal_draft" | sed -n 's/^{"schema":1,"alias":"\\([a-z0-9-]*\\)"}$/\\1/p')"
|
|
111
|
+
if synopkgland_portal_valid "$synopkgland_portal_alias"; then
|
|
112
|
+
synopkgland_portal_write "$synopkgland_portal_alias" || exit 1
|
|
113
|
+
fi
|
|
114
|
+
fi
|
|
115
|
+
`;
|
|
116
|
+
}
|