@synopackageland/cli 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +846 -0
- package/README.md +81 -89
- package/dist/add.d.ts +4 -1
- package/dist/add.js +45 -17
- package/dist/build-spk/delegate-scope.d.ts +6 -0
- package/dist/build-spk/delegate-scope.js +34 -0
- package/dist/build-spk/dsm-arch.d.ts +7 -1
- package/dist/build-spk/dsm-arch.js +24 -28
- package/dist/build-spk/dsm-platforms.json +42 -0
- package/dist/build-spk/dsm-version.d.ts +11 -0
- package/dist/build-spk/dsm-version.js +17 -0
- package/dist/build-spk/gateway.js +8 -4
- package/dist/build-spk/generator.js +30 -5
- package/dist/build-spk/go-toolchain.d.ts +20 -0
- package/dist/build-spk/go-toolchain.js +44 -0
- package/dist/build-spk/notices.js +4 -1
- package/dist/build-spk/resource-worker.js +3 -0
- package/dist/build-spk/wizard-messages.d.ts +66 -0
- package/dist/build-spk/wizard-messages.js +75 -9
- package/dist/cli.js +28 -14
- package/dist/contract/schema-validate.js +8 -0
- package/dist/contract/validate.js +30 -0
- package/dist/deploy/deploy.d.ts +1 -1
- package/dist/deploy/deploy.js +8 -0
- package/dist/deploy/native-install-values.d.ts +17 -0
- package/dist/deploy/native-install-values.js +32 -0
- package/dist/deploy/plan.d.ts +6 -2
- package/dist/deploy/plan.js +58 -7
- package/dist/deploy/spk-version.js +1 -1
- package/dist/error-registry.js +54 -20
- package/dist/host/dsm-client.d.ts +8 -4
- package/dist/host/dsm-client.js +63 -21
- package/dist/host/dsm-http.js +24 -2
- package/dist/host/types.d.ts +3 -1
- package/dist/info.js +45 -10
- package/dist/init.d.ts +3 -0
- package/dist/init.js +50 -19
- package/dist/package-metadata.d.ts +21 -0
- package/dist/package-metadata.js +101 -0
- package/dist/portal/alias.d.ts +25 -0
- package/dist/portal/alias.js +48 -0
- package/dist/portal/package.d.ts +33 -0
- package/dist/portal/package.js +116 -0
- package/dist/runtime/delegate-contract.d.ts +79 -0
- package/dist/runtime/delegate-contract.js +27 -0
- package/dist/runtime/dsm-version.d.ts +6 -0
- package/dist/runtime/dsm-version.js +8 -0
- package/dist/runtime/executor-build.js +10 -6
- package/dist/runtime/executor-inspect.d.ts +3 -0
- package/dist/runtime/executor-inspect.js +11 -5
- package/dist/runtime/executor-policy.d.ts +12 -0
- package/dist/runtime/executor-policy.js +43 -3
- package/dist/runtime/executor-scope-task.d.ts +4 -0
- package/dist/runtime/executor-scope-task.js +21 -0
- package/dist/runtime/executor-tasks.d.ts +2 -1
- package/dist/runtime/executor-tasks.js +4 -4
- package/dist/skill.js +1 -0
- package/dist/standalone/api-permissions.d.ts +10 -0
- package/dist/standalone/api-permissions.js +19 -2
- package/dist/standalone/background.d.ts +16 -0
- package/dist/standalone/background.js +69 -2
- package/dist/standalone/binary.d.ts +1 -1
- package/dist/standalone/binary.js +22 -8
- package/dist/standalone/build.d.ts +1 -1
- package/dist/standalone/build.js +38 -8
- package/dist/standalone/daemon.d.ts +1 -0
- package/dist/standalone/daemon.js +10 -5
- package/dist/standalone/dsm-window.d.ts +3 -1
- package/dist/standalone/dsm-window.js +78 -49
- package/dist/standalone/inspect-spk.d.ts +8 -0
- package/dist/standalone/inspect-spk.js +110 -27
- package/dist/standalone/lifecycle.js +86 -8
- package/dist/standalone/manifest.d.ts +13 -0
- package/dist/standalone/manifest.js +57 -8
- package/dist/standalone/native-authorization-window.d.ts +1 -1
- package/dist/standalone/native-authorization-window.js +9 -1
- package/dist/standalone/native-layout.d.ts +3 -0
- package/dist/standalone/native-layout.js +37 -5
- package/dist/standalone/native-root-window.d.ts +4 -2
- package/dist/standalone/native-root-window.js +33 -18
- package/dist/standalone/portal-window.d.ts +21 -0
- package/dist/standalone/portal-window.js +155 -0
- package/dist/standalone/portal.d.ts +4 -0
- package/dist/standalone/portal.js +4 -0
- package/dist/standalone/resource.d.ts +5 -3
- package/dist/standalone/resource.js +6 -3
- package/dist/standalone/root-window.d.ts +4 -1
- package/dist/standalone/root-window.js +193 -36
- package/dist/standalone/spk.d.ts +1 -1
- package/dist/standalone/spk.js +25 -7
- package/dist/templates/_daemon/go.mod +1 -1
- package/dist/templates/_daemon/main.go +6 -3
- package/dist/templates/_daemon/main_test.go +82 -9
- package/dist/templates/_daemon/testdata/child.go +3 -0
- package/dist/templates/_executor/README.md +130 -16
- package/dist/templates/_executor/anchor.go +156 -0
- package/dist/templates/_executor/anchor_test.go +161 -0
- package/dist/templates/_executor/apppriv_review_test.go +1 -1
- package/dist/templates/_executor/cancel_contract_test.go +236 -0
- package/dist/templates/_executor/copy.go +64 -0
- package/dist/templates/_executor/copy_test.go +88 -0
- package/dist/templates/_executor/digest_review_test.go +2 -2
- package/dist/templates/_executor/dsm.go +63 -13
- package/dist/templates/_executor/dsm_test.go +95 -1
- package/dist/templates/_executor/executor.go +260 -49
- package/dist/templates/_executor/executor_test.go +36 -6
- package/dist/templates/_executor/go.mod +2 -0
- package/dist/templates/_executor/identity.go +27 -1
- package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
- package/dist/templates/_executor/identity_linux.go +82 -0
- package/dist/templates/_executor/identity_security_test.go +43 -0
- package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
- package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
- package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
- package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
- package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
- package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
- package/dist/templates/_executor/lifecycle_test.go +11 -0
- package/dist/templates/_executor/link_linux.go +28 -0
- package/dist/templates/_executor/long_running_test.go +530 -0
- package/dist/templates/_executor/main.go +83 -25
- package/dist/templates/_executor/managed.go +3 -3
- package/dist/templates/_executor/managed_test.go +3 -3
- package/dist/templates/_executor/move_linux.go +490 -0
- package/dist/templates/_executor/move_linux_test.go +460 -0
- package/dist/templates/_executor/move_validation.go +46 -0
- package/dist/templates/_executor/move_validation_test.go +187 -0
- package/dist/templates/_executor/operations.go +926 -0
- package/dist/templates/_executor/path_test.go +18 -0
- package/dist/templates/_executor/pid.go +37 -0
- package/dist/templates/_executor/pid_test.go +113 -0
- package/dist/templates/_executor/platform_linux.go +24 -173
- package/dist/templates/_executor/platform_linux_test.go +9 -65
- package/dist/templates/_executor/platform_other.go +38 -4
- package/dist/templates/_executor/process.go +3 -0
- package/dist/templates/_executor/purge_log.go +18 -0
- package/dist/templates/_executor/records.go +242 -0
- package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
- package/dist/templates/_executor/scope_client.go +37 -0
- package/dist/templates/_executor/scope_contract.go +12 -0
- package/dist/templates/_executor/selected_scope.go +146 -0
- package/dist/templates/_executor/selected_scope_test.go +186 -0
- package/dist/templates/_executor/status_disabled_test.go +33 -0
- package/dist/templates/_executor/store.go +4 -3
- package/dist/templates/_executor/supervise.go +109 -0
- package/dist/templates/_executor/supervise_test.go +130 -0
- package/dist/templates/_executor/task_race_review_test.go +1 -1
- package/dist/templates/_executor/tasks.go +52 -15
- package/dist/templates/_executor/tasks_dsm71_test.go +114 -0
- package/dist/templates/_executor/tasks_review_test.go +1 -1
- package/dist/templates/_executor/tasks_test.go +62 -5
- package/dist/templates/_executor/upgrade_watch_test.go +13 -5
- package/dist/templates/_executor/watch.go +8 -0
- package/dist/templates/_executor/watch_test.go +23 -2
- package/dist/templates/_executor/write_review_linux_test.go +4 -12
- package/dist/templates/_gateway/go.mod +2 -0
- package/dist/templates/_shared/AGENTS.md +129 -0
- package/dist/templates/binary/dsm-package.yaml +24 -0
- package/dist/templates/binary/i18n/messages/de.json +4 -0
- package/dist/templates/binary/i18n/messages/en.json +4 -0
- package/dist/templates/binary/i18n/messages/es.json +4 -0
- package/dist/templates/binary/i18n/messages/fr.json +4 -0
- package/dist/templates/binary/i18n/messages/it.json +4 -0
- package/dist/templates/binary/i18n/messages/ja.json +4 -0
- package/dist/templates/binary/i18n/messages/ko.json +4 -0
- package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/dist/templates/binary/ui/app.js +19 -4
- package/dist/templates/native-authorization/AuthorizationGate.vue +5 -3
- package/dist/templates/native-authorization/i18n/de.json +1 -0
- package/dist/templates/native-authorization/i18n/en.json +1 -0
- package/dist/templates/native-authorization/i18n/es.json +2 -1
- package/dist/templates/native-authorization/i18n/fr.json +1 -0
- package/dist/templates/native-authorization/i18n/it.json +11 -10
- package/dist/templates/native-authorization/i18n/ja.json +1 -0
- package/dist/templates/native-authorization/i18n/ko.json +10 -9
- package/dist/templates/native-authorization/i18n/zh-CN.json +6 -5
- package/dist/templates/native-authorization/i18n/zh-TW.json +6 -5
- package/dist/templates/native-go/README.md +43 -10
- package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
- package/dist/templates/native-go/backend/go.mod +1 -1
- package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
- package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
- package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
- package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
- package/dist/templates/native-go/backend/internal/api/server.go +18 -5
- package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
- package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
- package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
- package/dist/templates/native-go/backend/internal/background/store.go +16 -14
- package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
- package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
- package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
- package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
- package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
- package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
- package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
- package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
- package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
- package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
- package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
- package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
- package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
- package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
- package/dist/templates/native-go/backend/internal/filestation/client.go +39 -3
- package/dist/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
- package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
- package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
- package/dist/templates/native-go/backend/internal/identity/README.md +5 -1
- package/dist/templates/native-go/backend/internal/identity/dsm.go +24 -5
- package/dist/templates/native-go/backend/internal/identity/http.go +1 -1
- package/dist/templates/native-go/backend/internal/identity/identity_test.go +48 -1
- package/dist/templates/native-go/backend/internal/identity/service.go +1 -1
- package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
- package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
- package/dist/templates/native-go/dsm-package.yaml +20 -1
- package/dist/templates/native-go/i18n/glossary.json +2 -1
- package/dist/templates/native-go/i18n/messages/de.json +1 -0
- package/dist/templates/native-go/i18n/messages/en.json +1 -0
- package/dist/templates/native-go/i18n/messages/es.json +1 -0
- package/dist/templates/native-go/i18n/messages/fr.json +1 -0
- package/dist/templates/native-go/i18n/messages/it.json +1 -0
- package/dist/templates/native-go/i18n/messages/ja.json +1 -0
- package/dist/templates/native-go/i18n/messages/ko.json +1 -0
- package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
- package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
- package/dist/templates/native-go/ui/app.css +10 -0
- package/dist/templates/native-go/ui/app.js +11 -1
- package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
- package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
- package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
- package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
- package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
- package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
- package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
- package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
- package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
- package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
- package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
- package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
- package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
- package/dist/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
- package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
- package/dist/templates/native-go-delegate/test.sh +1 -0
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
- package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
- package/dist/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
- package/dist/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
- package/dist/templates/native-go-vue/README.md +4 -0
- package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
- package/dist/templates/native-go-vue/frontend/package.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
- package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +54 -9
- package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -5
- package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
- package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
- package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
- package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
- package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
- package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
- package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
- package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
- package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
- package/package.json +5 -1
- package/schema/package-metadata.schema.json +101 -0
- package/schema/synology-app.schema.json +112 -0
- package/skills/SKILL.md +106 -4
- package/skills/reference/create.md +101 -2
- package/skills/reference/deploy.md +2 -2
- package/skills/reference/files.md +113 -2
- package/skills/reference/identity.md +70 -1
- package/skills/reference/portal.md +17 -0
- package/skills/reference/ui-vue.md +12 -0
- package/templates/_daemon/go.mod +1 -1
- package/templates/_daemon/main.go +6 -3
- package/templates/_daemon/main_test.go +82 -9
- package/templates/_daemon/testdata/child.go +3 -0
- package/templates/_executor/README.md +130 -16
- package/templates/_executor/anchor.go +156 -0
- package/templates/_executor/anchor_test.go +161 -0
- package/templates/_executor/apppriv_review_test.go +1 -1
- package/templates/_executor/cancel_contract_test.go +236 -0
- package/templates/_executor/copy.go +64 -0
- package/templates/_executor/copy_test.go +88 -0
- package/templates/_executor/digest_review_test.go +2 -2
- package/templates/_executor/dsm.go +63 -13
- package/templates/_executor/dsm_test.go +95 -1
- package/templates/_executor/executor.go +260 -49
- package/templates/_executor/executor_test.go +36 -6
- package/templates/_executor/go.mod +2 -0
- package/templates/_executor/identity.go +27 -1
- package/templates/_executor/identity_kernel_linux_test.go +60 -0
- package/templates/_executor/identity_linux.go +82 -0
- package/templates/_executor/identity_security_test.go +43 -0
- package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
- package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
- package/templates/_executor/internal/taskscript/boot.sh +9 -9
- package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
- package/templates/_executor/internal/taskscript/control.sh +15 -10
- package/templates/_executor/internal/taskscript/tasks.go +5 -3
- package/templates/_executor/lifecycle_test.go +11 -0
- package/templates/_executor/link_linux.go +28 -0
- package/templates/_executor/long_running_test.go +530 -0
- package/templates/_executor/main.go +83 -25
- package/templates/_executor/managed.go +3 -3
- package/templates/_executor/managed_test.go +3 -3
- package/templates/_executor/move_linux.go +490 -0
- package/templates/_executor/move_linux_test.go +460 -0
- package/templates/_executor/move_validation.go +46 -0
- package/templates/_executor/move_validation_test.go +187 -0
- package/templates/_executor/operations.go +926 -0
- package/templates/_executor/path_test.go +18 -0
- package/templates/_executor/pid.go +37 -0
- package/templates/_executor/pid_test.go +113 -0
- package/templates/_executor/platform_linux.go +24 -173
- package/templates/_executor/platform_linux_test.go +9 -65
- package/templates/_executor/platform_other.go +38 -4
- package/templates/_executor/process.go +3 -0
- package/templates/_executor/purge_log.go +18 -0
- package/templates/_executor/records.go +242 -0
- package/templates/_executor/scope_cancel_contract_test.go +91 -0
- package/templates/_executor/scope_client.go +37 -0
- package/templates/_executor/scope_contract.go +12 -0
- package/templates/_executor/selected_scope.go +146 -0
- package/templates/_executor/selected_scope_test.go +186 -0
- package/templates/_executor/status_disabled_test.go +33 -0
- package/templates/_executor/store.go +4 -3
- package/templates/_executor/supervise.go +109 -0
- package/templates/_executor/supervise_test.go +130 -0
- package/templates/_executor/task_race_review_test.go +1 -1
- package/templates/_executor/tasks.go +52 -15
- package/templates/_executor/tasks_dsm71_test.go +114 -0
- package/templates/_executor/tasks_review_test.go +1 -1
- package/templates/_executor/tasks_test.go +62 -5
- package/templates/_executor/upgrade_watch_test.go +13 -5
- package/templates/_executor/watch.go +8 -0
- package/templates/_executor/watch_test.go +23 -2
- package/templates/_executor/write_review_linux_test.go +4 -12
- package/templates/_gateway/go.mod +2 -0
- package/templates/_shared/AGENTS.md +129 -0
- package/templates/binary/dsm-package.yaml +24 -0
- package/templates/binary/i18n/messages/de.json +4 -0
- package/templates/binary/i18n/messages/en.json +4 -0
- package/templates/binary/i18n/messages/es.json +4 -0
- package/templates/binary/i18n/messages/fr.json +4 -0
- package/templates/binary/i18n/messages/it.json +4 -0
- package/templates/binary/i18n/messages/ja.json +4 -0
- package/templates/binary/i18n/messages/ko.json +4 -0
- package/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/templates/binary/ui/app.js +19 -4
- package/templates/native-authorization/AuthorizationGate.vue +5 -3
- package/templates/native-authorization/i18n/de.json +1 -0
- package/templates/native-authorization/i18n/en.json +1 -0
- package/templates/native-authorization/i18n/es.json +2 -1
- package/templates/native-authorization/i18n/fr.json +1 -0
- package/templates/native-authorization/i18n/it.json +11 -10
- package/templates/native-authorization/i18n/ja.json +1 -0
- package/templates/native-authorization/i18n/ko.json +10 -9
- package/templates/native-authorization/i18n/zh-CN.json +6 -5
- package/templates/native-authorization/i18n/zh-TW.json +6 -5
- package/templates/native-go/README.md +43 -10
- package/templates/native-go/backend/cmd/app/main.go +27 -7
- package/templates/native-go/backend/go.mod +1 -1
- package/templates/native-go/backend/internal/api/entry_test.go +47 -0
- package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
- package/templates/native-go/backend/internal/api/registry.go +11 -0
- package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
- package/templates/native-go/backend/internal/api/server.go +18 -5
- package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/templates/native-go/backend/internal/app/portal.go +30 -0
- package/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/templates/native-go/backend/internal/app/routes.go +8 -2
- package/templates/native-go/backend/internal/background/runner.go +1 -1
- package/templates/native-go/backend/internal/background/store.go +16 -14
- package/templates/native-go/backend/internal/dsm/admin.go +8 -2
- package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
- package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
- package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
- package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
- package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
- package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
- package/templates/native-go/backend/internal/dsm/entry.go +177 -0
- package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
- package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
- package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
- package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
- package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
- package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
- package/templates/native-go/backend/internal/filestation/client.go +39 -3
- package/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
- package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
- package/templates/native-go/backend/internal/filestation/service.go +1 -1
- package/templates/native-go/backend/internal/identity/README.md +5 -1
- package/templates/native-go/backend/internal/identity/dsm.go +24 -5
- package/templates/native-go/backend/internal/identity/http.go +1 -1
- package/templates/native-go/backend/internal/identity/identity_test.go +48 -1
- package/templates/native-go/backend/internal/identity/service.go +1 -1
- package/templates/native-go/backend/internal/portal/portal.go +138 -0
- package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
- package/templates/native-go/dsm-package.yaml +20 -1
- package/templates/native-go/i18n/glossary.json +2 -1
- package/templates/native-go/i18n/messages/de.json +1 -0
- package/templates/native-go/i18n/messages/en.json +1 -0
- package/templates/native-go/i18n/messages/es.json +1 -0
- package/templates/native-go/i18n/messages/fr.json +1 -0
- package/templates/native-go/i18n/messages/it.json +1 -0
- package/templates/native-go/i18n/messages/ja.json +1 -0
- package/templates/native-go/i18n/messages/ko.json +1 -0
- package/templates/native-go/i18n/messages/zh-CN.json +1 -0
- package/templates/native-go/i18n/messages/zh-TW.json +1 -0
- package/templates/native-go/ui/app.css +10 -0
- package/templates/native-go/ui/app.js +11 -1
- package/templates/native-go-delegate/DELEGATE.md +126 -5
- package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
- package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
- package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
- package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
- package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
- package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
- package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
- package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
- package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
- package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
- package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
- package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
- package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
- package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
- package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
- package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
- package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
- package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
- package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
- package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
- package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
- package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
- package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
- package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
- package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
- package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
- package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
- package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
- package/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
- package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
- package/templates/native-go-delegate/test.sh +1 -0
- package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
- package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
- package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
- package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
- package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
- package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
- package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
- package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
- package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
- package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
- package/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
- package/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
- package/templates/native-go-vue/README.md +4 -0
- package/templates/native-go-vue/frontend/package-lock.json +4 -4
- package/templates/native-go-vue/frontend/package.json +1 -1
- package/templates/native-go-vue/frontend/src/App.vue +18 -13
- package/templates/native-go-vue/frontend/src/context.ts +31 -0
- package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +54 -9
- package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
- package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
- package/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
- package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -2
- package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
- package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
- package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -5
- package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
- package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
- package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
- package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
- package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
- package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
- package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
- package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
- package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
- package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
- package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
- package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
- package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
- package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
- package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
- package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
- package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
- package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
- package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
package/dist/host/dsm-http.js
CHANGED
|
@@ -2,11 +2,29 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
function
|
|
6
|
-
|
|
5
|
+
function errorCode(error) {
|
|
6
|
+
return error.cause?.code
|
|
7
7
|
?? error.code;
|
|
8
|
+
}
|
|
9
|
+
function isHostUnreachable(error) {
|
|
10
|
+
const code = errorCode(error);
|
|
8
11
|
return code === "EHOSTUNREACH" || code === "ENETUNREACH";
|
|
9
12
|
}
|
|
13
|
+
const UNTRUSTED_CERTIFICATE = new Set([
|
|
14
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
15
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
16
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
17
|
+
"UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
|
18
|
+
"CERT_HAS_EXPIRED",
|
|
19
|
+
"ERR_TLS_CERT_ALTNAME_INVALID",
|
|
20
|
+
]);
|
|
21
|
+
/** Node reports an untrusted certificate only as "fetch failed"; say what to do. Verification stays on. */
|
|
22
|
+
function untrustedCertificate(url, code) {
|
|
23
|
+
const origin = new URL(url).origin;
|
|
24
|
+
return Object.assign(new Error(`DSM at ${origin} presented a TLS certificate this computer does not trust (${code}). ` +
|
|
25
|
+
`Export the NAS certificate or its CA as PEM and run with NODE_EXTRA_CA_CERTS=<that file>, ` +
|
|
26
|
+
`or give DSM a certificate whose name matches the host profile. Certificate checks stay on.`), { code: "DSM_TLS_UNTRUSTED" });
|
|
27
|
+
}
|
|
10
28
|
function headerRecord(headers) {
|
|
11
29
|
if (!headers) {
|
|
12
30
|
return {};
|
|
@@ -24,6 +42,10 @@ export async function dsmFetch(url, init = {}) {
|
|
|
24
42
|
return await fetch(url, init);
|
|
25
43
|
}
|
|
26
44
|
catch (error) {
|
|
45
|
+
const code = errorCode(error);
|
|
46
|
+
if (code && UNTRUSTED_CERTIFICATE.has(code)) {
|
|
47
|
+
throw untrustedCertificate(url, code);
|
|
48
|
+
}
|
|
27
49
|
if (!isHostUnreachable(error)) {
|
|
28
50
|
throw error;
|
|
29
51
|
}
|
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;
|
|
@@ -32,8 +33,9 @@ export interface NasHost {
|
|
|
32
33
|
ready: boolean;
|
|
33
34
|
executor_digest: string;
|
|
34
35
|
policy_digest: string;
|
|
36
|
+
error?: string;
|
|
35
37
|
} | undefined>;
|
|
36
|
-
getArchFamily?(): Promise<
|
|
38
|
+
getArchFamily?(): Promise<NativeArchFamily | undefined>;
|
|
37
39
|
/** List the current logical Shared Folder names using an administrator session. */
|
|
38
40
|
listShareNames?(): Promise<string[]>;
|
|
39
41
|
resolveSharePath?(logicalName: string): Promise<string | undefined>;
|
package/dist/info.js
CHANGED
|
@@ -5,7 +5,9 @@ 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 {
|
|
8
|
+
import { isNativeLayout, loadNativeLayout } from "./standalone/native-layout.js";
|
|
9
|
+
import { executorPolicy, executorPolicyText, sha256 } from "./runtime/executor-policy.js";
|
|
10
|
+
import { executorTasks } from "./runtime/executor-tasks.js";
|
|
9
11
|
import { uninstallCleanup } from "./runtime/uninstall-cleanup.js";
|
|
10
12
|
export async function projectInfo(options) {
|
|
11
13
|
const identity = resolveDeployIdentity(options.project, { dev: options.dev });
|
|
@@ -63,6 +65,21 @@ export function classifyRootTasks(expected, inventory) {
|
|
|
63
65
|
? result("needs-admin-approval", "Approve missing or outdated root tasks in the DSM package UI.")
|
|
64
66
|
: result("ready", "Boot and control tasks match the executor and policy digests. Executor health must be checked in the App window.");
|
|
65
67
|
}
|
|
68
|
+
async function liveRootCapability(m, host) {
|
|
69
|
+
try {
|
|
70
|
+
const policyDigest = sha256(executorPolicyText(executorPolicy(m)));
|
|
71
|
+
const classified = classifyRootTasks(executorTasks({ package: m.package, policyDigest }), await host.getRootTaskInventory?.(m.package));
|
|
72
|
+
if (classified.state !== "ready")
|
|
73
|
+
return classified;
|
|
74
|
+
const observed = await host.getExecutorStatus?.(m.package);
|
|
75
|
+
if (observed?.ready !== true || observed.policy_digest !== policyDigest)
|
|
76
|
+
return { ...classified, state: "blocked", reason: observed?.error ?? "Executor health or policy digest readback could not be verified." };
|
|
77
|
+
return { ...classified, reason: "Root tasks and the running executor match the source policy (no local SPK, so executor bytes were not compared)." };
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return { name: "rootOps", state: "blocked", reason: "DSM executor or root task readback could not be verified." };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
66
83
|
async function rootCapability(m, host, version) {
|
|
67
84
|
const blocked = (reason) => ({
|
|
68
85
|
name: "rootOps",
|
|
@@ -82,7 +99,7 @@ async function rootCapability(m, host, version) {
|
|
|
82
99
|
return blocked("NAS architecture cannot be matched to the local executor SPK artifact.");
|
|
83
100
|
const spk = join(m.root, "dist", `${m.package}-${version}-${arch}.spk`);
|
|
84
101
|
if (!existsSync(spk))
|
|
85
|
-
return
|
|
102
|
+
return liveRootCapability(m, host);
|
|
86
103
|
try {
|
|
87
104
|
const inspected = await inspectSpk(spk);
|
|
88
105
|
if (inspected.findings.length ||
|
|
@@ -100,7 +117,7 @@ async function rootCapability(m, host, version) {
|
|
|
100
117
|
if (classified.state === "ready") {
|
|
101
118
|
const observed = await host.getExecutorStatus?.(m.package);
|
|
102
119
|
if (!observed || observed.ready !== true || observed.executor_digest !== executor.executorDigest || observed.policy_digest !== executor.policyDigest)
|
|
103
|
-
return { ...classified, executor, state: "blocked", reason: "Executor health or digest readback could not be verified." };
|
|
120
|
+
return { ...classified, executor, state: "blocked", reason: observed?.error ?? "Executor health or digest readback could not be verified." };
|
|
104
121
|
}
|
|
105
122
|
return { ...classified, executor };
|
|
106
123
|
}
|
|
@@ -111,12 +128,14 @@ async function rootCapability(m, host, version) {
|
|
|
111
128
|
export async function standaloneInfo(options) {
|
|
112
129
|
if (options.dev)
|
|
113
130
|
throw Object.assign(new Error("--dev is not supported for native-go/binary; choose a distinct package name at init"), { code: "DEVELOPMENT_INSTANCE_UNSUPPORTED" });
|
|
131
|
+
if (isNativeLayout(options.root))
|
|
132
|
+
return nativeLayoutInfo(options.root, options.host);
|
|
114
133
|
const loaded = loadStandaloneManifest(options.root);
|
|
115
134
|
if (!loaded.ok)
|
|
116
135
|
throw Object.assign(new Error(loaded.errors.map((e) => e.message).join("\n")), { code: loaded.errors[0].code });
|
|
117
136
|
const m = loaded.manifest;
|
|
118
|
-
const remote = await
|
|
119
|
-
const installed =
|
|
137
|
+
const { remote, ...state } = await packageState(m.package, options.host);
|
|
138
|
+
const installed = state.installed;
|
|
120
139
|
const capabilities = [];
|
|
121
140
|
let executor;
|
|
122
141
|
for (const name of ["files", "jobs", "identity", "rootOps", "delegate"]) {
|
|
@@ -142,16 +161,32 @@ export async function standaloneInfo(options) {
|
|
|
142
161
|
});
|
|
143
162
|
}
|
|
144
163
|
return {
|
|
145
|
-
|
|
146
|
-
developmentInstance: false,
|
|
147
|
-
installed,
|
|
148
|
-
readiness: remote?.status ?? (installed ? "UNKNOWN" : "NOT_INSTALLED"),
|
|
149
|
-
openUrl: `${options.host.dsmOrigin.replace(/\/$/, "")}/?launchApp=SYNO.SDS.${m.package}.Instance`,
|
|
164
|
+
...state,
|
|
150
165
|
capabilities,
|
|
151
166
|
...(executor ? { executor } : {}),
|
|
152
167
|
uninstallCleanup: uninstallCleanup(m.package, Boolean(m.capabilities.rootOps || m.capabilities.delegate)),
|
|
153
168
|
};
|
|
154
169
|
}
|
|
170
|
+
/** A native layout has no SDK capabilities; report package state only. */
|
|
171
|
+
async function nativeLayoutInfo(root, host) {
|
|
172
|
+
const loaded = loadNativeLayout(root);
|
|
173
|
+
if (!loaded.ok)
|
|
174
|
+
throw Object.assign(new Error(loaded.errors.map((e) => e.message).join("\n")), { code: loaded.errors[0].code });
|
|
175
|
+
const { remote, ...state } = await packageState(loaded.manifest.package, host);
|
|
176
|
+
return { ...state, capabilities: [] };
|
|
177
|
+
}
|
|
178
|
+
async function packageState(pkg, host) {
|
|
179
|
+
const remote = await host.getInstalledPackageState?.(pkg);
|
|
180
|
+
const installed = await host.isPackageInstalled(pkg);
|
|
181
|
+
return {
|
|
182
|
+
remote,
|
|
183
|
+
packageIdentity: pkg,
|
|
184
|
+
developmentInstance: false,
|
|
185
|
+
installed,
|
|
186
|
+
readiness: remote?.status ?? (installed ? "UNKNOWN" : "NOT_INSTALLED"),
|
|
187
|
+
openUrl: `${host.dsmOrigin.replace(/\/$/, "")}/?launchApp=SYNO.SDS.${pkg}.Instance`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
155
190
|
export function formatProjectInfo(info) {
|
|
156
191
|
return [
|
|
157
192
|
`Package Identity:${info.packageIdentity}`,
|
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")
|
|
@@ -183,7 +195,7 @@ export function initFromTemplate(template, targetDir, options = {}) {
|
|
|
183
195
|
}
|
|
184
196
|
if (executor) {
|
|
185
197
|
const path = join(targetDir, "backend/internal/app/routes_test.go");
|
|
186
|
-
writeFileSync(path, readFileSync(path, "utf8").replace('if strings.HasPrefix(r.Method(), "jobs.") {', 'if r.Method() == "
|
|
198
|
+
writeFileSync(path, readFileSync(path, "utf8").replace('if strings.HasPrefix(r.Method(), "jobs.") {', 'if r.Method() == "root.run" { want = "session_required" }\n\t\tif strings.HasPrefix(r.Method(), "jobs.") {'));
|
|
187
199
|
}
|
|
188
200
|
if (background && ui === "vue") {
|
|
189
201
|
const app = join(targetDir, "frontend/src/App.vue");
|
|
@@ -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
|
+
}
|