@synopackageland/templates 0.10.1 → 0.10.3
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/README.md +8 -3
- package/package.json +1 -1
- package/templates/_shared/AGENTS.md +42 -0
- package/templates/_shared/dsm-scripts/postinst +53 -0
- package/templates/_shared/dsm-scripts/postuninst +51 -0
- package/templates/_shared/dsm-scripts/postupgrade +54 -0
- package/templates/_shared/dsm-scripts/preinst +49 -0
- package/templates/_shared/dsm-scripts/preuninst +50 -0
- package/templates/_shared/dsm-scripts/preupgrade +52 -0
- package/templates/_shared/dsm-scripts/start-stop-status +59 -0
- package/templates/native-go/README.md +18 -2
- package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +1 -1
- package/templates/native-go/backend/cmd/app/main.go +4 -4
- package/templates/native-go/backend/cmd/app/main_test.go +4 -4
- package/templates/native-go/backend/go.mod +1 -1
- package/templates/native-go/backend/go.sum +2 -2
- package/templates/native-go/i18n/glossary.json +0 -1
- package/templates/native-go/i18n/messages/de.json +1 -1
- package/templates/native-go/i18n/messages/en.json +1 -1
- package/templates/native-go/i18n/messages/es.json +1 -1
- package/templates/native-go/i18n/messages/fr.json +1 -1
- package/templates/native-go/i18n/messages/it.json +1 -1
- package/templates/native-go/i18n/messages/ja.json +1 -1
- package/templates/native-go/i18n/messages/ko.json +1 -1
- package/templates/native-go/i18n/messages/zh-CN.json +2 -2
- package/templates/native-go/i18n/messages/zh-TW.json +1 -1
- package/templates/native-go-delegate/frontend/test/capability-panels.test.ts +3 -3
- package/templates/native-go-root-ops/backend/internal/app/executor.go +3 -3
- package/templates/native-go-root-ops/backend/internal/app/executor_test.go +8 -0
- package/templates/native-go-vue/README.md +3 -0
- package/templates/native-go-vue/frontend/package-lock.json +9 -9
- package/templates/native-go-vue/frontend/package.json +2 -2
- package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +1 -1
- package/templates/native-node/README.md +7 -0
- package/templates/native-node/dsm-package.yaml +1 -1
- package/templates/native-python/README.md +7 -0
- package/templates/native-python/dsm-package.yaml +1 -1
- package/templates/native-rust/README.md +7 -0
- package/templates/native-rust/backend/Cargo.lock +2 -2
- package/templates/native-rust/backend/Cargo.toml +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ the files an App owns; the SDK (`github.com/synopackageland/syno-pkg-land-sdk`,
|
|
|
18
18
|
| `native-{python,node,rust}-vue` | The README and `.gitignore` of the Vue shell |
|
|
19
19
|
| `binary` | A prebuilt static CGI (`example/main.go`) with a plain UI |
|
|
20
20
|
| `compose` | Container Manager project (`compose.yaml`, `synology-app.yaml`) |
|
|
21
|
-
| `_shared` | Agent guides, template license, Go license texts, third-party notice writer |
|
|
21
|
+
| `_shared` | Agent guides, template license, Go license texts, third-party notice writer, `dsm-scripts/` (DSM lifecycle scripts) |
|
|
22
22
|
|
|
23
23
|
Overlays are copied over `native-go` in the order root-ops, vue, jobs, delegate.
|
|
24
24
|
An overlay may replace `internal/app/*_none.go` (the CLI deletes the matching
|
|
@@ -31,14 +31,19 @@ also makes `app.status` and `report.save` `authenticated`, and the Rust
|
|
|
31
31
|
manifest gets the overlays' methods. `init` copies the App SDK into
|
|
32
32
|
`backend/vendor` (Python `synopkgland_app`; Node `@synopackageland/app`, its
|
|
33
33
|
package.json without devDependencies and scripts, and `dist/`).
|
|
34
|
+
`_shared/dsm-scripts/` holds DSM's lifecycle scripts (`preinst`, `postinst`, `preupgrade`,
|
|
35
|
+
`postupgrade`, `preuninst`, `postuninst`, `start-stop-status`), each commented and doing
|
|
36
|
+
nothing; `init` (CLI 0.10.3 and later) copies them into every project's `dsm-scripts/`, and `build`
|
|
37
|
+
calls each one from the generated script of the same name (`synopkgland skill show lifecycle`).
|
|
34
38
|
The placeholders `__PACKAGE__` (also the Go module path), `__DISPLAY_NAME__` and
|
|
35
39
|
`__BACKGROUND_ENABLED__` are substituted by `init`.
|
|
36
40
|
|
|
37
|
-
`backend/go.mod` requires `github.com/synopackageland/syno-pkg-land-sdk v0.10.
|
|
41
|
+
`backend/go.mod` requires `github.com/synopackageland/syno-pkg-land-sdk v0.10.3`; that line is
|
|
38
42
|
the single source of the SDK version and `frontend/package.json` pins
|
|
39
43
|
`@synopackageland/sdk` to the same version. Python and Node.js name it in
|
|
40
44
|
`backend.sdk`, Rust in the `syno-pkg-land-app` tag of `backend/Cargo.toml`
|
|
41
|
-
(and `Cargo.lock`); all of them pin 0.10.
|
|
45
|
+
(and `Cargo.lock`); all of them pin 0.10.3. The Vue frontend pins
|
|
46
|
+
`@synopackageland/ui` 0.9.5.
|
|
42
47
|
|
|
43
48
|
## Notice writer
|
|
44
49
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/templates",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Project templates for synopkgland init: native-go, native-python, native-node and native-rust (plain or Vue, with jobs, delegate and root-ops overlays), binary and compose.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {"type": "git", "url": "git+https://github.com/synopackageland/syno-pkg-land-templates.git"},
|
|
@@ -25,6 +25,27 @@ From the project root, run `synopkgland check --json`,
|
|
|
25
25
|
For Vue, first run `npm ci`, `npm test` and `npm run build` in frontend.
|
|
26
26
|
Do not connect to or change a NAS without explicit task authorization.
|
|
27
27
|
|
|
28
|
+
## Lifecycle scripts (`dsm-scripts/`)
|
|
29
|
+
|
|
30
|
+
`dsm-scripts/` holds DSM's own lifecycle scripts (preinst, postinst, preupgrade,
|
|
31
|
+
postupgrade, preuninst, postuninst, start-stop-status); each does nothing until
|
|
32
|
+
edited. The build calls each from the generated script of the same name, as the
|
|
33
|
+
package account, around the SDK's own steps. Read
|
|
34
|
+
`synopkgland skill show lifecycle` before editing them; never add root work,
|
|
35
|
+
never repeat SDK steps, and keep only DSM script names in that folder
|
|
36
|
+
(build tools belong in `scripts/`).
|
|
37
|
+
|
|
38
|
+
Root cleanup or migration after an install or upgrade (for example removing
|
|
39
|
+
what an older version left in a root-owned place) is not a lifecycle script:
|
|
40
|
+
name a `root/` program as `root.start` in `dsm-package.yaml`. The executor runs
|
|
41
|
+
it as root once after each install or upgrade, at the first start of the new
|
|
42
|
+
version and only while the administrator's approval is live; it must not
|
|
43
|
+
declare `run` or `job`, should be safe to run twice, and declaring it means the
|
|
44
|
+
administrator approves the App again. Package start only requests the
|
|
45
|
+
executor, so `postinst`, `postupgrade` and `start` cannot wait for the step:
|
|
46
|
+
keep the unprivileged follow-up in `dsm-scripts/`, and read the step's result
|
|
47
|
+
from the executor `status` (`start_step`).
|
|
48
|
+
|
|
28
49
|
## Who may use the app (`entry`)
|
|
29
50
|
|
|
30
51
|
Omit `entry` to keep legacy access. `entry: admin-only` admits DSM administrators
|
|
@@ -62,6 +83,27 @@ from the portal panel (`ctx.portal.register()`), which the executor's approved
|
|
|
62
83
|
DSM resource. Beyond that, support is detected (SYNO.API.Info), not
|
|
63
84
|
version-gated.
|
|
64
85
|
|
|
86
|
+
### Login page look (`login_style`)
|
|
87
|
+
|
|
88
|
+
A portal build gives the Login Portal entry a default look: a neutral
|
|
89
|
+
wallpaper, its thumbnail in Control Panel > Login Portal > Applications, the
|
|
90
|
+
login button colour `#2F6BD8`, and the App icon beside the NAS name on the
|
|
91
|
+
alias login page. To use your own images, add to dsm-package.yaml (each key is
|
|
92
|
+
optional; `wallpaper` and `wallpaper_thumbnail` go together):
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
login_style:
|
|
96
|
+
color: "#0F766E" # login button, #RGB or #RRGGBB
|
|
97
|
+
wallpaper: branding/login-wallpaper.jpg # JPEG, at least 1920x1080, at most 2 MiB
|
|
98
|
+
wallpaper_thumbnail: branding/login-thumbnail.jpg # JPEG 320x200, the same picture
|
|
99
|
+
title: branding/login-title.png # PNG 680x124, replaces icon and NAS name
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`synopkgland check` refuses a missing image or one of the wrong format or size
|
|
103
|
+
(`STANDALONE_LOGIN_STYLE_IMAGE_INVALID`) and prints the style in effect;
|
|
104
|
+
`synopkgland inspect <spk>` shows what the SPK carries. Use only images you
|
|
105
|
+
may redistribute; never copy Synology's.
|
|
106
|
+
|
|
65
107
|
## Background jobs (`jobs`)
|
|
66
108
|
|
|
67
109
|
The worker runs the App's Work for one claimed job at a time, as the package
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# postinst: runs after DSM copied the package files, at install and at the
|
|
3
|
+
# install half of an upgrade (SYNOPKG_PKG_STATUS=INSTALL or UPGRADE). During an
|
|
4
|
+
# upgrade, postupgrade follows it.
|
|
5
|
+
#
|
|
6
|
+
# Order: the SDK's postinst steps first (executor, Shared Folder, portal), then
|
|
7
|
+
# this script. If the SDK steps fail, this script does not run.
|
|
8
|
+
#
|
|
9
|
+
# Runs as the package account, never as root. Root work belongs in root/*.sh
|
|
10
|
+
# through the SDK executor (synopkgland add root-ops). Root cleanup or
|
|
11
|
+
# migration after an install or upgrade is the executor's start step
|
|
12
|
+
# (root.start): it runs once per new version, at the executor's first start
|
|
13
|
+
# after an administrator's approval. Package start only requests the executor
|
|
14
|
+
# and does not wait for it, so this script cannot see that step; keep only the
|
|
15
|
+
# unprivileged follow-up here. The App reads the step's result from the
|
|
16
|
+
# executor status (start_step).
|
|
17
|
+
#
|
|
18
|
+
# Environment (DSM sets these; the SDK passes them through unchanged):
|
|
19
|
+
# SYNOPKG_PKGNAME, SYNOPKG_PKGVER package id and the version being installed
|
|
20
|
+
# SYNOPKG_OLD_PKGVER the previous version (upgrade only)
|
|
21
|
+
# SYNOPKG_PKG_STATUS INSTALL, UPGRADE, UNINSTALL, START, STOP,
|
|
22
|
+
# or empty at boot and shutdown
|
|
23
|
+
# SYNOPKG_PKGDEST installed files (/var/packages/<id>/target)
|
|
24
|
+
# SYNOPKG_PKGVAR, SYNOPKG_PKGHOME package data and home; kept across upgrades
|
|
25
|
+
# SYNOPKG_TEMP_LOGFILE write a message for the user here
|
|
26
|
+
# SYNOPKG_DSM_LANGUAGE DSM language code (enu, cht, chs, jpn, ...)
|
|
27
|
+
# SYNOPKG_DSM_VERSION_MAJOR, _MINOR, _BUILD, SYNOPKG_DSM_ARCH
|
|
28
|
+
# SYNOPKG_USERNAME who started the action; empty when DSM did
|
|
29
|
+
#
|
|
30
|
+
# Install wizard answers arrive as environment variables named by each item's
|
|
31
|
+
# key ("true", "false" or text). The SDK's own wizard keys are not for you.
|
|
32
|
+
#
|
|
33
|
+
# Exit code: 0 is success; non-zero leaves the package in a failed state
|
|
34
|
+
# (DSM's own rule).
|
|
35
|
+
#
|
|
36
|
+
# To tell the user why something failed, write plain text to the message file
|
|
37
|
+
# and exit non-zero; DSM shows it after the action:
|
|
38
|
+
# echo "Port 8080 is already in use." > "$SYNOPKG_TEMP_LOGFILE"
|
|
39
|
+
# exit 1
|
|
40
|
+
#
|
|
41
|
+
# Do not:
|
|
42
|
+
# - start, stop or clean up what the SDK owns (daemon, background worker,
|
|
43
|
+
# executor, portal, Shared Folder, app data deletion, uninstall.purge);
|
|
44
|
+
# - need root or try to gain it;
|
|
45
|
+
# - block for long: neither DSM nor the SDK documents a timeout, so a script
|
|
46
|
+
# that hangs blocks Package Center.
|
|
47
|
+
#
|
|
48
|
+
# More: synopkgland skill show lifecycle
|
|
49
|
+
|
|
50
|
+
# Example: create the App's own folder in its data directory.
|
|
51
|
+
# mkdir -p "$SYNOPKG_PKGVAR/cache" || exit 1
|
|
52
|
+
|
|
53
|
+
exit 0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# postuninst: runs after DSM deleted the package files. It runs at uninstall
|
|
3
|
+
# (SYNOPKG_PKG_STATUS=UNINSTALL) AND during an upgrade (UPGRADE), where it is
|
|
4
|
+
# the OLD version's script. SYNOPKG_PKGDEST no longer exists here.
|
|
5
|
+
#
|
|
6
|
+
# Order: the SDK's postuninst steps first (deleting app data when the user
|
|
7
|
+
# chose it in the uninstall wizard), then this script. If the SDK steps fail,
|
|
8
|
+
# this script does not run.
|
|
9
|
+
#
|
|
10
|
+
# Runs as the package account, never as root. Root work belongs in root/*.sh
|
|
11
|
+
# through the SDK executor (synopkgland add root-ops).
|
|
12
|
+
#
|
|
13
|
+
# Environment (DSM sets these; the SDK passes them through unchanged):
|
|
14
|
+
# SYNOPKG_PKGNAME, SYNOPKG_PKGVER package id and the version being installed
|
|
15
|
+
# SYNOPKG_OLD_PKGVER the previous version (upgrade only)
|
|
16
|
+
# SYNOPKG_PKG_STATUS INSTALL, UPGRADE, UNINSTALL, START, STOP,
|
|
17
|
+
# or empty at boot and shutdown
|
|
18
|
+
# SYNOPKG_PKGDEST installed files (/var/packages/<id>/target)
|
|
19
|
+
# SYNOPKG_PKGVAR, SYNOPKG_PKGHOME package data and home; kept across upgrades
|
|
20
|
+
# SYNOPKG_TEMP_LOGFILE write a message for the user here
|
|
21
|
+
# SYNOPKG_DSM_LANGUAGE DSM language code (enu, cht, chs, jpn, ...)
|
|
22
|
+
# SYNOPKG_DSM_VERSION_MAJOR, _MINOR, _BUILD, SYNOPKG_DSM_ARCH
|
|
23
|
+
# SYNOPKG_USERNAME who started the action; empty when DSM did
|
|
24
|
+
#
|
|
25
|
+
# Uninstall wizard answers arrive as environment variables named by each
|
|
26
|
+
# item's key. The SDK's uninstall wizard already asks about deleting app data.
|
|
27
|
+
#
|
|
28
|
+
# Exit code: DSM documents no meaning for postuninst; exit 0 unless something
|
|
29
|
+
# the user must know failed.
|
|
30
|
+
#
|
|
31
|
+
# To tell the user why something failed, write plain text to the message file
|
|
32
|
+
# and exit non-zero; DSM shows it after the action:
|
|
33
|
+
# echo "Port 8080 is already in use." > "$SYNOPKG_TEMP_LOGFILE"
|
|
34
|
+
# exit 1
|
|
35
|
+
#
|
|
36
|
+
# Do not:
|
|
37
|
+
# - start, stop or clean up what the SDK owns (daemon, background worker,
|
|
38
|
+
# executor, portal, Shared Folder, app data deletion, uninstall.purge);
|
|
39
|
+
# - need root or try to gain it;
|
|
40
|
+
# - block for long: neither DSM nor the SDK documents a timeout, so a script
|
|
41
|
+
# that hangs blocks Package Center.
|
|
42
|
+
#
|
|
43
|
+
# More: synopkgland skill show lifecycle
|
|
44
|
+
|
|
45
|
+
# Example: on a real uninstall only, remove a file the App wrote outside its
|
|
46
|
+
# data directories.
|
|
47
|
+
# if [ "${SYNOPKG_PKG_STATUS:-}" = UNINSTALL ]; then
|
|
48
|
+
# rm -f "$SYNOPKG_PKGHOME/settings-backup.json"
|
|
49
|
+
# fi
|
|
50
|
+
|
|
51
|
+
exit 0
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# postupgrade: runs at the end of an upgrade, after the new postinst
|
|
3
|
+
# (SYNOPKG_PKG_STATUS=UPGRADE). It is the NEW version's script.
|
|
4
|
+
#
|
|
5
|
+
# Order: the SDK's postupgrade steps first, then this script. If the SDK steps
|
|
6
|
+
# fail, this script does not run.
|
|
7
|
+
#
|
|
8
|
+
# Runs as the package account, never as root. Root work belongs in root/*.sh
|
|
9
|
+
# through the SDK executor (synopkgland add root-ops). Root cleanup or
|
|
10
|
+
# migration after an install or upgrade is the executor's start step
|
|
11
|
+
# (root.start): it runs once per new version, at the executor's first start
|
|
12
|
+
# after an administrator's approval. Package start only requests the executor
|
|
13
|
+
# and does not wait for it, so this script cannot see that step; keep only the
|
|
14
|
+
# unprivileged follow-up here. The App reads the step's result from the
|
|
15
|
+
# executor status (start_step).
|
|
16
|
+
#
|
|
17
|
+
# Environment (DSM sets these; the SDK passes them through unchanged):
|
|
18
|
+
# SYNOPKG_PKGNAME, SYNOPKG_PKGVER package id and the version being installed
|
|
19
|
+
# SYNOPKG_OLD_PKGVER the previous version (upgrade only)
|
|
20
|
+
# SYNOPKG_PKG_STATUS INSTALL, UPGRADE, UNINSTALL, START, STOP,
|
|
21
|
+
# or empty at boot and shutdown
|
|
22
|
+
# SYNOPKG_PKGDEST installed files (/var/packages/<id>/target)
|
|
23
|
+
# SYNOPKG_PKGVAR, SYNOPKG_PKGHOME package data and home; kept across upgrades
|
|
24
|
+
# SYNOPKG_TEMP_LOGFILE write a message for the user here
|
|
25
|
+
# SYNOPKG_DSM_LANGUAGE DSM language code (enu, cht, chs, jpn, ...)
|
|
26
|
+
# SYNOPKG_DSM_VERSION_MAJOR, _MINOR, _BUILD, SYNOPKG_DSM_ARCH
|
|
27
|
+
# SYNOPKG_USERNAME who started the action; empty when DSM did
|
|
28
|
+
#
|
|
29
|
+
# Upgrade wizard answers arrive as environment variables named by each item's
|
|
30
|
+
# key. A silent upgrade shows no wizard, so always have a default.
|
|
31
|
+
#
|
|
32
|
+
# Exit code: 0 is success; non-zero leaves the package in a failed state
|
|
33
|
+
# (DSM's own rule).
|
|
34
|
+
#
|
|
35
|
+
# To tell the user why something failed, write plain text to the message file
|
|
36
|
+
# and exit non-zero; DSM shows it after the action:
|
|
37
|
+
# echo "Port 8080 is already in use." > "$SYNOPKG_TEMP_LOGFILE"
|
|
38
|
+
# exit 1
|
|
39
|
+
#
|
|
40
|
+
# Do not:
|
|
41
|
+
# - start, stop or clean up what the SDK owns (daemon, background worker,
|
|
42
|
+
# executor, portal, Shared Folder, app data deletion, uninstall.purge);
|
|
43
|
+
# - need root or try to gain it;
|
|
44
|
+
# - block for long: neither DSM nor the SDK documents a timeout, so a script
|
|
45
|
+
# that hangs blocks Package Center.
|
|
46
|
+
#
|
|
47
|
+
# More: synopkgland skill show lifecycle
|
|
48
|
+
|
|
49
|
+
# Example: migrate the App's data once, from versions before 1.2.
|
|
50
|
+
# case "${SYNOPKG_OLD_PKGVER:-}" in
|
|
51
|
+
# 0.*|1.0*|1.1*) "$SYNOPKG_PKGDEST/app/migrate" || exit 1 ;;
|
|
52
|
+
# esac
|
|
53
|
+
|
|
54
|
+
exit 0
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# preinst: runs before DSM copies the package files, at install and at the
|
|
3
|
+
# install half of an upgrade (SYNOPKG_PKG_STATUS=INSTALL or UPGRADE).
|
|
4
|
+
#
|
|
5
|
+
# Order: the SDK's preinst steps first, then this script. If the SDK steps
|
|
6
|
+
# fail, this script does not run.
|
|
7
|
+
#
|
|
8
|
+
# Runs as the package account, never as root. Root work belongs in root/*.sh
|
|
9
|
+
# through the SDK executor (synopkgland add root-ops).
|
|
10
|
+
#
|
|
11
|
+
# Environment (DSM sets these; the SDK passes them through unchanged):
|
|
12
|
+
# SYNOPKG_PKGNAME, SYNOPKG_PKGVER package id and the version being installed
|
|
13
|
+
# SYNOPKG_OLD_PKGVER the previous version (upgrade only)
|
|
14
|
+
# SYNOPKG_PKG_STATUS INSTALL, UPGRADE, UNINSTALL, START, STOP,
|
|
15
|
+
# or empty at boot and shutdown
|
|
16
|
+
# SYNOPKG_PKGDEST installed files (/var/packages/<id>/target)
|
|
17
|
+
# SYNOPKG_PKGVAR, SYNOPKG_PKGHOME package data and home; kept across upgrades
|
|
18
|
+
# SYNOPKG_TEMP_LOGFILE write a message for the user here
|
|
19
|
+
# SYNOPKG_DSM_LANGUAGE DSM language code (enu, cht, chs, jpn, ...)
|
|
20
|
+
# SYNOPKG_DSM_VERSION_MAJOR, _MINOR, _BUILD, SYNOPKG_DSM_ARCH
|
|
21
|
+
# SYNOPKG_USERNAME who started the action; empty when DSM did
|
|
22
|
+
#
|
|
23
|
+
# Install wizard answers arrive as environment variables named by each item's
|
|
24
|
+
# key ("true", "false" or text). The SDK's own wizard keys are not for you.
|
|
25
|
+
#
|
|
26
|
+
# Exit code: 0 continues; non-zero aborts the install or upgrade (DSM's own
|
|
27
|
+
# rule). Keep this to checks: nothing undoes a change made here.
|
|
28
|
+
#
|
|
29
|
+
# To tell the user why something failed, write plain text to the message file
|
|
30
|
+
# and exit non-zero; DSM shows it after the action:
|
|
31
|
+
# echo "Port 8080 is already in use." > "$SYNOPKG_TEMP_LOGFILE"
|
|
32
|
+
# exit 1
|
|
33
|
+
#
|
|
34
|
+
# Do not:
|
|
35
|
+
# - start, stop or clean up what the SDK owns (daemon, background worker,
|
|
36
|
+
# executor, portal, Shared Folder, app data deletion, uninstall.purge);
|
|
37
|
+
# - need root or try to gain it;
|
|
38
|
+
# - block for long: neither DSM nor the SDK documents a timeout, so a script
|
|
39
|
+
# that hangs blocks Package Center.
|
|
40
|
+
#
|
|
41
|
+
# More: synopkgland skill show lifecycle
|
|
42
|
+
|
|
43
|
+
# Example: refuse DSM older than 7.2.
|
|
44
|
+
# if [ "${SYNOPKG_DSM_VERSION_MAJOR:-7}" -eq 7 ] && [ "${SYNOPKG_DSM_VERSION_MINOR:-0}" -lt 2 ]; then
|
|
45
|
+
# echo "This App needs DSM 7.2 or later." > "$SYNOPKG_TEMP_LOGFILE"
|
|
46
|
+
# exit 1
|
|
47
|
+
# fi
|
|
48
|
+
|
|
49
|
+
exit 0
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# preuninst: runs before DSM deletes the package files, after DSM stopped the
|
|
3
|
+
# package. It runs at uninstall (SYNOPKG_PKG_STATUS=UNINSTALL) AND during an
|
|
4
|
+
# upgrade (UPGRADE), where it is the OLD version's script.
|
|
5
|
+
#
|
|
6
|
+
# Order: this script first, then the SDK's preuninst steps (stop, the App's
|
|
7
|
+
# uninstall.purge, executor cleanup).
|
|
8
|
+
#
|
|
9
|
+
# Runs as the package account, never as root. Root work belongs in root/*.sh
|
|
10
|
+
# through the SDK executor (synopkgland add root-ops).
|
|
11
|
+
#
|
|
12
|
+
# Environment (DSM sets these; the SDK passes them through unchanged):
|
|
13
|
+
# SYNOPKG_PKGNAME, SYNOPKG_PKGVER package id and the version being installed
|
|
14
|
+
# SYNOPKG_OLD_PKGVER the previous version (upgrade only)
|
|
15
|
+
# SYNOPKG_PKG_STATUS INSTALL, UPGRADE, UNINSTALL, START, STOP,
|
|
16
|
+
# or empty at boot and shutdown
|
|
17
|
+
# SYNOPKG_PKGDEST installed files (/var/packages/<id>/target)
|
|
18
|
+
# SYNOPKG_PKGVAR, SYNOPKG_PKGHOME package data and home; kept across upgrades
|
|
19
|
+
# SYNOPKG_TEMP_LOGFILE write a message for the user here
|
|
20
|
+
# SYNOPKG_DSM_LANGUAGE DSM language code (enu, cht, chs, jpn, ...)
|
|
21
|
+
# SYNOPKG_DSM_VERSION_MAJOR, _MINOR, _BUILD, SYNOPKG_DSM_ARCH
|
|
22
|
+
# SYNOPKG_USERNAME who started the action; empty when DSM did
|
|
23
|
+
#
|
|
24
|
+
# Uninstall wizard answers arrive as environment variables named by each
|
|
25
|
+
# item's key. The SDK's uninstall wizard already asks about deleting app data.
|
|
26
|
+
#
|
|
27
|
+
# Exit code: 0 continues; non-zero aborts the uninstall or upgrade before the
|
|
28
|
+
# SDK steps run (DSM's own rule).
|
|
29
|
+
#
|
|
30
|
+
# To tell the user why something failed, write plain text to the message file
|
|
31
|
+
# and exit non-zero; DSM shows it after the action:
|
|
32
|
+
# echo "Port 8080 is already in use." > "$SYNOPKG_TEMP_LOGFILE"
|
|
33
|
+
# exit 1
|
|
34
|
+
#
|
|
35
|
+
# Do not:
|
|
36
|
+
# - start, stop or clean up what the SDK owns (daemon, background worker,
|
|
37
|
+
# executor, portal, Shared Folder, app data deletion, uninstall.purge);
|
|
38
|
+
# - need root or try to gain it;
|
|
39
|
+
# - block for long: neither DSM nor the SDK documents a timeout, so a script
|
|
40
|
+
# that hangs blocks Package Center.
|
|
41
|
+
#
|
|
42
|
+
# More: synopkgland skill show lifecycle
|
|
43
|
+
|
|
44
|
+
# Example: on a real uninstall only, export the App's settings to a file the
|
|
45
|
+
# user keeps.
|
|
46
|
+
# if [ "${SYNOPKG_PKG_STATUS:-}" = UNINSTALL ]; then
|
|
47
|
+
# cp "$SYNOPKG_PKGVAR/settings.json" "$SYNOPKG_PKGHOME/settings-backup.json" 2>/dev/null || true
|
|
48
|
+
# fi
|
|
49
|
+
|
|
50
|
+
exit 0
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# preupgrade: runs at the start of an upgrade, after DSM stopped the old
|
|
3
|
+
# version (SYNOPKG_PKG_STATUS=UPGRADE). It is the NEW version's script, but
|
|
4
|
+
# SYNOPKG_PKGDEST still holds the OLD version's files.
|
|
5
|
+
#
|
|
6
|
+
# Upgrade order: old start-stop-status stop, new preupgrade, old preuninst,
|
|
7
|
+
# old files deleted, old postuninst, new preinst, new files, new postinst,
|
|
8
|
+
# new postupgrade, new start-stop-status start.
|
|
9
|
+
#
|
|
10
|
+
# Order in this script: this script first, then the SDK's preupgrade steps.
|
|
11
|
+
#
|
|
12
|
+
# Runs as the package account, never as root. Root work belongs in root/*.sh
|
|
13
|
+
# through the SDK executor (synopkgland add root-ops).
|
|
14
|
+
#
|
|
15
|
+
# Environment (DSM sets these; the SDK passes them through unchanged):
|
|
16
|
+
# SYNOPKG_PKGNAME, SYNOPKG_PKGVER package id and the version being installed
|
|
17
|
+
# SYNOPKG_OLD_PKGVER the previous version (upgrade only)
|
|
18
|
+
# SYNOPKG_PKG_STATUS INSTALL, UPGRADE, UNINSTALL, START, STOP,
|
|
19
|
+
# or empty at boot and shutdown
|
|
20
|
+
# SYNOPKG_PKGDEST installed files (/var/packages/<id>/target)
|
|
21
|
+
# SYNOPKG_PKGVAR, SYNOPKG_PKGHOME package data and home; kept across upgrades
|
|
22
|
+
# SYNOPKG_TEMP_LOGFILE write a message for the user here
|
|
23
|
+
# SYNOPKG_DSM_LANGUAGE DSM language code (enu, cht, chs, jpn, ...)
|
|
24
|
+
# SYNOPKG_DSM_VERSION_MAJOR, _MINOR, _BUILD, SYNOPKG_DSM_ARCH
|
|
25
|
+
# SYNOPKG_USERNAME who started the action; empty when DSM did
|
|
26
|
+
#
|
|
27
|
+
# Upgrade wizard answers arrive as environment variables named by each item's
|
|
28
|
+
# key. A silent upgrade shows no wizard, so always have a default.
|
|
29
|
+
#
|
|
30
|
+
# Exit code: 0 continues; non-zero aborts the upgrade before the SDK steps run
|
|
31
|
+
# (DSM's own rule). Keep this to checks and to saving what postupgrade needs.
|
|
32
|
+
#
|
|
33
|
+
# To tell the user why something failed, write plain text to the message file
|
|
34
|
+
# and exit non-zero; DSM shows it after the action:
|
|
35
|
+
# echo "Port 8080 is already in use." > "$SYNOPKG_TEMP_LOGFILE"
|
|
36
|
+
# exit 1
|
|
37
|
+
#
|
|
38
|
+
# Do not:
|
|
39
|
+
# - start, stop or clean up what the SDK owns (daemon, background worker,
|
|
40
|
+
# executor, portal, Shared Folder, app data deletion, uninstall.purge);
|
|
41
|
+
# - need root or try to gain it;
|
|
42
|
+
# - block for long: neither DSM nor the SDK documents a timeout, so a script
|
|
43
|
+
# that hangs blocks Package Center.
|
|
44
|
+
#
|
|
45
|
+
# More: synopkgland skill show lifecycle
|
|
46
|
+
|
|
47
|
+
# Example: refuse a downgrade the App's data format cannot take.
|
|
48
|
+
# case "${SYNOPKG_OLD_PKGVER:-}" in
|
|
49
|
+
# 2.*) echo "Downgrading from 2.x is not supported." > "$SYNOPKG_TEMP_LOGFILE"; exit 1 ;;
|
|
50
|
+
# esac
|
|
51
|
+
|
|
52
|
+
exit 0
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# start-stop-status: DSM calls it with one argument:
|
|
3
|
+
# start the user started the package, at boot, or after install/upgrade
|
|
4
|
+
# stop the user stopped it, at shutdown, before upgrade and uninstall
|
|
5
|
+
# status DSM asks whether the package runs
|
|
6
|
+
# prestart, prestop only when INFO has precheckstartstop (the SDK sets it
|
|
7
|
+
# for daemon and background-job Apps); non-zero refuses the action
|
|
8
|
+
#
|
|
9
|
+
# Order: start, prestart and status run the SDK steps first, then this script.
|
|
10
|
+
# stop and prestop run this script first, then the SDK steps; the SDK stop
|
|
11
|
+
# always runs. If this script fails at start, the SDK stops again.
|
|
12
|
+
# SYNOPKG_PKG_STATUS tells why (START, STOP, INSTALL, UPGRADE, UNINSTALL, or
|
|
13
|
+
# empty at boot and shutdown).
|
|
14
|
+
#
|
|
15
|
+
# Runs as the package account, never as root. Root work belongs in root/*.sh
|
|
16
|
+
# through the SDK executor (synopkgland add root-ops).
|
|
17
|
+
#
|
|
18
|
+
# Environment (DSM sets these; the SDK passes them through unchanged):
|
|
19
|
+
# SYNOPKG_PKGNAME, SYNOPKG_PKGVER package id and the version being installed
|
|
20
|
+
# SYNOPKG_OLD_PKGVER the previous version (upgrade only)
|
|
21
|
+
# SYNOPKG_PKG_STATUS INSTALL, UPGRADE, UNINSTALL, START, STOP,
|
|
22
|
+
# or empty at boot and shutdown
|
|
23
|
+
# SYNOPKG_PKGDEST installed files (/var/packages/<id>/target)
|
|
24
|
+
# SYNOPKG_PKGVAR, SYNOPKG_PKGHOME package data and home; kept across upgrades
|
|
25
|
+
# SYNOPKG_TEMP_LOGFILE write a message for the user here
|
|
26
|
+
# SYNOPKG_DSM_LANGUAGE DSM language code (enu, cht, chs, jpn, ...)
|
|
27
|
+
# SYNOPKG_DSM_VERSION_MAJOR, _MINOR, _BUILD, SYNOPKG_DSM_ARCH
|
|
28
|
+
# SYNOPKG_USERNAME who started the action; empty when DSM did
|
|
29
|
+
#
|
|
30
|
+
# Exit code: for start and stop, 0 is success and non-zero a failure. For
|
|
31
|
+
# status, the SDK asks this script only while the SDK runs: 0 running,
|
|
32
|
+
# 3 not running, 4 unknown, 150 broken (DSM's own codes).
|
|
33
|
+
#
|
|
34
|
+
# To tell the user why something failed, write plain text to the message file
|
|
35
|
+
# and exit non-zero; DSM shows it after the action:
|
|
36
|
+
# echo "Port 8080 is already in use." > "$SYNOPKG_TEMP_LOGFILE"
|
|
37
|
+
# exit 1
|
|
38
|
+
#
|
|
39
|
+
# Do not:
|
|
40
|
+
# - start, stop or clean up what the SDK owns (daemon, background worker,
|
|
41
|
+
# executor, portal, Shared Folder, app data deletion, uninstall.purge);
|
|
42
|
+
# - need root or try to gain it;
|
|
43
|
+
# - block for long: neither DSM nor the SDK documents a timeout, so a script
|
|
44
|
+
# that hangs blocks Package Center.
|
|
45
|
+
#
|
|
46
|
+
# More: synopkgland skill show lifecycle
|
|
47
|
+
|
|
48
|
+
case "$1" in
|
|
49
|
+
start)
|
|
50
|
+
# Example: refuse to start without a setting the App needs.
|
|
51
|
+
# if [ ! -s "$SYNOPKG_PKGVAR/settings.json" ]; then
|
|
52
|
+
# echo "Open the App once to finish its setup." > "$SYNOPKG_TEMP_LOGFILE"
|
|
53
|
+
# exit 1
|
|
54
|
+
# fi
|
|
55
|
+
exit 0 ;;
|
|
56
|
+
stop) exit 0 ;;
|
|
57
|
+
status) exit 0 ;;
|
|
58
|
+
*) exit 0 ;;
|
|
59
|
+
esac
|
|
@@ -315,12 +315,28 @@ A portal needs DSM 7.3.2-86009 or later, so `add portal` raises a lower
|
|
|
315
315
|
package that registers a portal (Package Center error 320); 7.3.2 and 7.4
|
|
316
316
|
install it; 7.2 is untested. To keep supporting older DSM, remove `portal:`.
|
|
317
317
|
|
|
318
|
+
The build also gives the portal a login page look: a neutral default
|
|
319
|
+
wallpaper (its thumbnail is what Control Panel > Login Portal > Applications
|
|
320
|
+
shows), a button colour and the App icon. Replace them with your own in
|
|
321
|
+
dsm-package.yaml:
|
|
322
|
+
|
|
323
|
+
```yaml
|
|
324
|
+
login_style:
|
|
325
|
+
color: "#0F766E" # login button
|
|
326
|
+
wallpaper: branding/login-wallpaper.jpg # JPEG, at least 1920x1080, at most 2 MiB
|
|
327
|
+
wallpaper_thumbnail: branding/login-thumbnail.jpg # JPEG 320x200; required with wallpaper
|
|
328
|
+
title: branding/login-title.png # PNG 680x124, in place of icon and NAS name
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
`synopkgland check` validates the files and prints the style in effect.
|
|
332
|
+
|
|
318
333
|
## Data, upgrades, uninstall
|
|
319
334
|
|
|
320
335
|
The backend stores data in `/var/packages/__PACKAGE__/var` (the package's
|
|
321
336
|
own folder, kept across upgrades). Bump `build` for every SPK you hand out;
|
|
322
|
-
bump `version` for feature releases.
|
|
323
|
-
|
|
337
|
+
bump `version` for feature releases. You need no lifecycle scripts: the CGI
|
|
338
|
+
starts per request, so start/stop do nothing. For extra install, upgrade or
|
|
339
|
+
uninstall work, edit `dsm-scripts/` (`synopkgland skill show lifecycle`).
|
|
324
340
|
|
|
325
341
|
### What an upgrade keeps
|
|
326
342
|
|
|
@@ -42,16 +42,16 @@ var (
|
|
|
42
42
|
// "on" when dsm-package.yaml declares portal: serves portal.status;
|
|
43
43
|
// "executor" below DSM 7.2, where the executor registers the entry.
|
|
44
44
|
portal = ""
|
|
45
|
-
// backend.timeout_seconds,
|
|
45
|
+
// backend.timeout_seconds, api.DefaultRequestTimeout unless set.
|
|
46
46
|
requestTimeout = ""
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
-
// deadline is the CGI request deadline: requestTimeout seconds, or
|
|
50
|
-
// is unset or not a positive number.
|
|
49
|
+
// deadline is the CGI request deadline: requestTimeout seconds, or
|
|
50
|
+
// api.DefaultRequestTimeout when it is unset or not a positive number.
|
|
51
51
|
func deadline() api.DeadlineOption {
|
|
52
52
|
seconds, err := strconv.Atoi(requestTimeout)
|
|
53
53
|
if err != nil || seconds <= 0 {
|
|
54
|
-
|
|
54
|
+
return api.Timeout(api.DefaultRequestTimeout)
|
|
55
55
|
}
|
|
56
56
|
return api.Timeout(time.Duration(seconds) * time.Second)
|
|
57
57
|
}
|
|
@@ -13,12 +13,12 @@ func TestRequestDeadlineFollowsTheBuildSetting(t *testing.T) {
|
|
|
13
13
|
saved := requestTimeout
|
|
14
14
|
t.Cleanup(func() { requestTimeout = saved })
|
|
15
15
|
for setting, want := range map[string]time.Duration{
|
|
16
|
-
"":
|
|
16
|
+
"": api.DefaultRequestTimeout,
|
|
17
17
|
"120": 120 * time.Second,
|
|
18
18
|
"1": time.Second,
|
|
19
|
-
"0":
|
|
20
|
-
"-5":
|
|
21
|
-
"x":
|
|
19
|
+
"0": api.DefaultRequestTimeout,
|
|
20
|
+
"-5": api.DefaultRequestTimeout,
|
|
21
|
+
"x": api.DefaultRequestTimeout,
|
|
22
22
|
} {
|
|
23
23
|
requestTimeout = setting
|
|
24
24
|
var left time.Duration
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
github.com/synopackageland/syno-pkg-land-sdk v0.10.
|
|
2
|
-
github.com/synopackageland/syno-pkg-land-sdk v0.10.
|
|
1
|
+
github.com/synopackageland/syno-pkg-land-sdk v0.10.3 h1:YMwtSPqR7sS6pGKF0x7vMoMxNSY7GIMcxTa++VCTlz8=
|
|
2
|
+
github.com/synopackageland/syno-pkg-land-sdk v0.10.3/go.mod h1:hlsvaVuH2wsAoR8jzI1Rg/NeejQSFpAaN6zpIWsVbjI=
|
|
3
3
|
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
|
4
4
|
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"error.method_not_allowed": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
|
|
15
15
|
"error.network": "Verbindung fehlgeschlagen. Bitte überprüfen Sie Ihre Netzwerkeinstellungen.",
|
|
16
16
|
"error.request_too_large": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "Die Anfrage hat zu lange gedauert und wurde abgebrochen. Versuchen Sie es erneut oder mit einer kleineren Aufgabe.",
|
|
18
18
|
"error.request_canceled": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
|
|
19
19
|
"error.session_required": "Verbindung abgelaufen. Melden Sie sich erneut an.",
|
|
20
20
|
"error.unknown_method": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"error.method_not_allowed": "Unable to perform this operation. Please try again later.",
|
|
15
15
|
"error.network": "Connection failed. Please check your network settings.",
|
|
16
16
|
"error.request_too_large": "Unable to perform this operation. Please try again later.",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "The request took too long and was stopped. Try again, or try a smaller task.",
|
|
18
18
|
"error.request_canceled": "Unable to perform this operation. Please try again later.",
|
|
19
19
|
"error.session_required": "Connection expired. Please sign in again.",
|
|
20
20
|
"error.unknown_method": "Unable to perform this operation. Please try again later.",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"error.method_not_allowed": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
|
|
15
15
|
"error.network": "Error de la conexión. Compruebe su conexión de red.",
|
|
16
16
|
"error.request_too_large": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "La solicitud tardó demasiado y se detuvo. Vuelva a intentarlo o pruebe con una tarea más pequeña.",
|
|
18
18
|
"error.request_canceled": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
|
|
19
19
|
"error.session_required": "Conexión caducada. Vuelva a conectarse.",
|
|
20
20
|
"error.unknown_method": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"error.method_not_allowed": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
|
|
15
15
|
"error.network": "La connexion a échoué. Vérifiez vos paramètres réseau.",
|
|
16
16
|
"error.request_too_large": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "La requête a pris trop de temps et a été arrêtée. Réessayez ou essayez une tâche plus petite.",
|
|
18
18
|
"error.request_canceled": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
|
|
19
19
|
"error.session_required": "La connexion a expiré. Reconnectez-vous.",
|
|
20
20
|
"error.unknown_method": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"error.method_not_allowed": "Impossibile eseguire questa operazione. Riprovare più tardi.",
|
|
15
15
|
"error.network": "Connessione non riuscita. Controllare le impostazioni di rete.",
|
|
16
16
|
"error.request_too_large": "Impossibile eseguire questa operazione. Riprovare più tardi.",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "La richiesta ha impiegato troppo tempo ed è stata interrotta. Riprovare o provare con un’attività più piccola.",
|
|
18
18
|
"error.request_canceled": "Impossibile eseguire questa operazione. Riprovare più tardi.",
|
|
19
19
|
"error.session_required": "Connessione scaduta. Accedere nuovamente.",
|
|
20
20
|
"error.unknown_method": "Impossibile eseguire questa operazione. Riprovare più tardi.",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"error.method_not_allowed": "この操作は実行できません。後でもう一度お試しください。",
|
|
15
15
|
"error.network": "接続に失敗しました。ネットワーク設定を確認してください。",
|
|
16
16
|
"error.request_too_large": "この操作は実行できません。後でもう一度お試しください。",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "リクエストの処理に時間がかかりすぎたため、停止しました。もう一度お試しいただくか、範囲を小さくしてください。",
|
|
18
18
|
"error.request_canceled": "この操作は実行できません。後でもう一度お試しください。",
|
|
19
19
|
"error.session_required": "接続の期限が切れています。もう 1 度サイン インしてください。",
|
|
20
20
|
"error.unknown_method": "この操作は実行できません。後でもう一度お試しください。",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"error.method_not_allowed": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
|
|
15
15
|
"error.network": "연결 실패. 네트워크 설정을 확인해 주십시오.",
|
|
16
16
|
"error.request_too_large": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "요청 처리 시간이 너무 오래 걸려 중지되었습니다. 다시 시도하거나 작업 범위를 줄이십시오.",
|
|
18
18
|
"error.request_canceled": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
|
|
19
19
|
"error.session_required": "연결 만료됨. 다시 로그인 해 주십시오.",
|
|
20
20
|
"error.unknown_method": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
"error.method_not_allowed": "无法执行此操作。请稍后再试。",
|
|
15
15
|
"error.network": "无法联机,请检查你的网络设置。",
|
|
16
16
|
"error.request_too_large": "无法执行此操作。请稍后再试。",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "请求处理时间过长,已停止。请重试,或缩小范围后再试。",
|
|
18
18
|
"error.request_canceled": "无法执行此操作。请稍后再试。",
|
|
19
19
|
"error.session_required": "联机超时,请重新登录。",
|
|
20
20
|
"error.unknown_method": "无法执行此操作。请稍后再试。",
|
|
21
21
|
"error.app_unavailable": "App 当前不可用,请稍后重试。",
|
|
22
22
|
"error.limit_exceeded": "文件超过允许的大小。",
|
|
23
23
|
"error.read_failed": "无法读取文件。请稍后再试。",
|
|
24
|
-
"error.identity_unavailable": "
|
|
24
|
+
"error.identity_unavailable": "无法识别此用户账号。请稍后再试。",
|
|
25
25
|
"greeting.adminOnly": "只有 administrators 群组的成员可以更改问候语。",
|
|
26
26
|
"greeting.label": "新的问候语",
|
|
27
27
|
"greeting.save": "保存",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"error.method_not_allowed": "無法執行此操作。請稍後再試。",
|
|
15
15
|
"error.network": "無法連線,請檢查你的網路設定。",
|
|
16
16
|
"error.request_too_large": "無法執行此操作。請稍後再試。",
|
|
17
|
-
"error.request_timeout": "
|
|
17
|
+
"error.request_timeout": "請求處理太久已停止,請再試一次或縮小範圍。",
|
|
18
18
|
"error.request_canceled": "無法執行此操作。請稍後再試。",
|
|
19
19
|
"error.session_required": "連線逾時。請重新登入。",
|
|
20
20
|
"error.unknown_method": "無法執行此操作。請稍後再試。",
|
|
@@ -29,7 +29,7 @@ test('the capability surface uses an explicit long-running facade without legacy
|
|
|
29
29
|
} satisfies BackgroundSaveFacade
|
|
30
30
|
const call=vi.fn(async()=>{throw {code:'unexpected-legacy-call'}})
|
|
31
31
|
const root=render({delegate:sdk,call,locale:'en'});await settle()
|
|
32
|
-
expect(root.textContent).toContain('My
|
|
32
|
+
expect(root.textContent).toContain('My saves');expect(sdk.operations).toHaveBeenCalled()
|
|
33
33
|
expect(call).not.toHaveBeenCalled()
|
|
34
34
|
})
|
|
35
35
|
test('the default surface binds the real routes and the session-only picker',async()=>{
|
|
@@ -46,12 +46,12 @@ test('the default surface binds the real routes and the session-only picker',asy
|
|
|
46
46
|
throw {code:'unexpected'}
|
|
47
47
|
})
|
|
48
48
|
const root=render({call,locale:'en'});await settle()
|
|
49
|
-
button(root,'Choose
|
|
49
|
+
button(root,'Choose folder').click();await settle()
|
|
50
50
|
// The SDK picker selects a folder with a row click.
|
|
51
51
|
const row=root.querySelector<HTMLElement>('tr[data-row-key="/home"]')!;expect(row).toBeTruthy();row.dispatchEvent(new MouseEvent('click',{bubbles:true}));await settle()
|
|
52
52
|
button(root,'Confirm selection').click();await settle()
|
|
53
53
|
expect(call).toHaveBeenCalledWith('delegate.select_destination',{key:'save',path:'/home'})
|
|
54
|
-
// The
|
|
54
|
+
// The SDK hides the sample save unless an App opts in; the template opts in with sample-save.
|
|
55
55
|
button(root,'Save example file').click();await settle()
|
|
56
56
|
expect(call).toHaveBeenCalledWith('delegate.example.export',expect.objectContaining({key:'save'}))
|
|
57
57
|
})
|
|
@@ -6,7 +6,6 @@ import (
|
|
|
6
6
|
"errors"
|
|
7
7
|
"net/http"
|
|
8
8
|
"path/filepath"
|
|
9
|
-
"time"
|
|
10
9
|
|
|
11
10
|
"github.com/synopackageland/syno-pkg-land-sdk/api"
|
|
12
11
|
"github.com/synopackageland/syno-pkg-land-sdk/delegate"
|
|
@@ -59,7 +58,8 @@ func (cfg Config) executorHoldsThisBuild(ctx context.Context) error {
|
|
|
59
58
|
var executorSocketBase = "/run/synopkgland"
|
|
60
59
|
|
|
61
60
|
// executor keeps the executor's protocol v1 refusal codes (POLICY_DENIED,
|
|
62
|
-
// EXECUTOR_UNAVAILABLE, ...) as the API error code.
|
|
61
|
+
// EXECUTOR_UNAVAILABLE, ...) as the API error code. Without its own Timeout
|
|
62
|
+
// the client waits as the SDK says: delegate.ExecutorTimeout, root.run longer.
|
|
63
63
|
func (cfg Config) executor() *delegate.Client {
|
|
64
|
-
return &delegate.Client{Socket: filepath.Join(executorSocketBase, cfg.PackageID, "executor.sock")
|
|
64
|
+
return &delegate.Client{Socket: filepath.Join(executorSocketBase, cfg.PackageID, "executor.sock")}
|
|
65
65
|
}
|
|
@@ -163,3 +163,11 @@ func TestExecutorRootRunReportsTheExecutorsRefusalCode(t *testing.T) {
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
+
|
|
167
|
+
// The executor client waits as long as the SDK says (spec/protocol/v1,
|
|
168
|
+
// Timeouts): delegate.ExecutorTimeout for status and control, root.run longer.
|
|
169
|
+
func TestTheExecutorClientWaitsTheSDKsTimeout(t *testing.T) {
|
|
170
|
+
if got := testConfig(t).executor().Timeout; got != 0 {
|
|
171
|
+
t.Fatalf("executor client sets its own wait %v instead of the SDK's", got)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -29,6 +29,9 @@ and the background picker uses the retained session provider.
|
|
|
29
29
|
With `portal:` declared (`synopkgland add portal`, executor Apps only), the status page shows
|
|
30
30
|
the SDK's `PortalSettings`: the DSM Application Portal link, the alias form
|
|
31
31
|
for administrators, and the Control Panel shortcut.
|
|
32
|
+
The alias login page's wallpaper, button colour and title come from
|
|
33
|
+
`login_style:` in dsm-package.yaml (a default otherwise); see
|
|
34
|
+
`synopkgland skill show portal`.
|
|
32
35
|
|
|
33
36
|
Use public library controls, the embedded theme, per-app modal scope and unique
|
|
34
37
|
Vue ID prefixes. Backend route permissions and DSM checks remain authoritative.
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
"name": "native-dsm-vue-app",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@lucide/vue": "1.48.0",
|
|
10
|
-
"@synopackageland/sdk": "0.10.
|
|
11
|
-
"@synopackageland/ui": "0.9.
|
|
10
|
+
"@synopackageland/sdk": "0.10.3",
|
|
11
|
+
"@synopackageland/ui": "0.9.5",
|
|
12
12
|
"vue": "3.5.43"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
@@ -1148,13 +1148,13 @@
|
|
|
1148
1148
|
}
|
|
1149
1149
|
},
|
|
1150
1150
|
"node_modules/@synopackageland/sdk": {
|
|
1151
|
-
"version": "0.10.
|
|
1152
|
-
"resolved": "https://registry.npmjs.org/@synopackageland/sdk/-/sdk-0.10.
|
|
1153
|
-
"integrity": "sha512-
|
|
1151
|
+
"version": "0.10.3",
|
|
1152
|
+
"resolved": "https://registry.npmjs.org/@synopackageland/sdk/-/sdk-0.10.3.tgz",
|
|
1153
|
+
"integrity": "sha512-1YsPAtNm4azqCEhAUv/99o10dxwXMtjOg4aRKnwbrSpjrOYQrhsGKfyFj9bFimqIGy0mj2NvRPKGz8ET0HqyEg==",
|
|
1154
1154
|
"license": "MIT",
|
|
1155
1155
|
"peerDependencies": {
|
|
1156
1156
|
"@lucide/vue": "^1.48.0",
|
|
1157
|
-
"@synopackageland/ui": "^0.9.
|
|
1157
|
+
"@synopackageland/ui": "^0.9.5",
|
|
1158
1158
|
"vue": "^3.5.0"
|
|
1159
1159
|
},
|
|
1160
1160
|
"peerDependenciesMeta": {
|
|
@@ -1167,9 +1167,9 @@
|
|
|
1167
1167
|
}
|
|
1168
1168
|
},
|
|
1169
1169
|
"node_modules/@synopackageland/ui": {
|
|
1170
|
-
"version": "0.9.
|
|
1171
|
-
"resolved": "https://registry.npmjs.org/@synopackageland/ui/-/ui-0.9.
|
|
1172
|
-
"integrity": "sha512-
|
|
1170
|
+
"version": "0.9.5",
|
|
1171
|
+
"resolved": "https://registry.npmjs.org/@synopackageland/ui/-/ui-0.9.5.tgz",
|
|
1172
|
+
"integrity": "sha512-fytttAWLZ48H0w5UYsDzfJu7I4yBmafFviMoku+WZtwroNm6z26gTBdCgkg9a5MmxghFU8e1p5NWYnKfVVPbEw==",
|
|
1173
1173
|
"license": "MIT",
|
|
1174
1174
|
"dependencies": {
|
|
1175
1175
|
"@internationalized/date": "3.12.4",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"errors": {
|
|
12
12
|
"session_required": "DSM 登录已过期,请重新登录。",
|
|
13
13
|
"admin_required": "此操作必须由 DSM 管理员执行。",
|
|
14
|
-
"app_privilege_denied": "DSM
|
|
14
|
+
"app_privilege_denied": "DSM 应用程序权限不允许此账户使用此 App。",
|
|
15
15
|
"auth_unavailable": "DSM 验证暂时不可用,请刷新后重试。",
|
|
16
16
|
"request_failed": "请求失败({code}),请刷新后重试。"
|
|
17
17
|
}
|
|
@@ -119,6 +119,13 @@ A service refuses with its own code (`limit_exceeded`, `read_failed`, the
|
|
|
119
119
|
executor's refusals); the examples pass it on to the browser. `synopkgland add`
|
|
120
120
|
works on Go backends only: start a Node.js App with the capabilities it needs.
|
|
121
121
|
|
|
122
|
+
With `portal:` in dsm-package.yaml (executor Apps only, see
|
|
123
|
+
`synopkgland skill show portal`), the build also gives the Login Portal entry a
|
|
124
|
+
default wallpaper, thumbnail, button colour and the App icon. `login_style:`
|
|
125
|
+
replaces them: `color`, `wallpaper` (JPEG, at least 1920x1080) with
|
|
126
|
+
`wallpaper_thumbnail` (JPEG 320x200), and `title` (PNG 680x124); `synopkgland
|
|
127
|
+
check` validates the files.
|
|
128
|
+
|
|
122
129
|
## The SDK
|
|
123
130
|
|
|
124
131
|
`backend.sdk` in dsm-package.yaml names the SDK release: the build ships its runtime and its Node SDK as `backend/app/node_modules/@synopackageland/app`, and reads the method list from `main.js --describe`. `backend/vendor/@synopackageland/app` is the same SDK for tests and type checks; replace it with the new release's when you change `backend.sdk`. Upgrade the SDK by changing that version; `synopkgland check`
|
|
@@ -116,6 +116,13 @@ A service refuses with its own code (`limit_exceeded`, `read_failed`, the
|
|
|
116
116
|
executor's refusals); the examples pass it on to the browser. `synopkgland add`
|
|
117
117
|
works on Go backends only: start a Python App with the capabilities it needs.
|
|
118
118
|
|
|
119
|
+
With `portal:` in dsm-package.yaml (executor Apps only, see
|
|
120
|
+
`synopkgland skill show portal`), the build also gives the Login Portal entry a
|
|
121
|
+
default wallpaper, thumbnail, button colour and the App icon. `login_style:`
|
|
122
|
+
replaces them: `color`, `wallpaper` (JPEG, at least 1920x1080) with
|
|
123
|
+
`wallpaper_thumbnail` (JPEG 320x200), and `title` (PNG 680x124); `synopkgland
|
|
124
|
+
check` validates the files.
|
|
125
|
+
|
|
119
126
|
## The SDK
|
|
120
127
|
|
|
121
128
|
`backend.sdk` in dsm-package.yaml names the SDK release: the build ships its runtime and its Python SDK as `backend/app/vendor/synopkgland_app`, and reads the method list from `main.py --describe`. `backend/vendor/synopkgland_app` is the same SDK for tests; replace it with the new release's when you change `backend.sdk`. Upgrade the SDK by changing that version; `synopkgland check`
|
|
@@ -125,6 +125,13 @@ A service refuses with its own code (`limit_exceeded`, `read_failed`, the
|
|
|
125
125
|
executor's refusals); the examples pass it on to the browser. `synopkgland add`
|
|
126
126
|
works on Go backends only: start a Rust App with the capabilities it needs.
|
|
127
127
|
|
|
128
|
+
With `portal:` in dsm-package.yaml (executor Apps only, see
|
|
129
|
+
`synopkgland skill show portal`), the build also gives the Login Portal entry a
|
|
130
|
+
default wallpaper, thumbnail, button colour and the App icon. `login_style:`
|
|
131
|
+
replaces them: `color`, `wallpaper` (JPEG, at least 1920x1080) with
|
|
132
|
+
`wallpaper_thumbnail` (JPEG 320x200), and `title` (PNG 680x124); `synopkgland
|
|
133
|
+
check` validates the files.
|
|
134
|
+
|
|
128
135
|
## The SDK
|
|
129
136
|
|
|
130
137
|
The `syno-pkg-land-app` git dependency's `tag` in `backend/Cargo.toml` names the SDK release; the build reads it from `Cargo.lock` and ships that release's runtime. A cross-compiled binary cannot run on the build machine, so `backend.methods` in dsm-package.yaml lists every method the App registers; `synopkgland check` refuses a list that differs from the App's own. Upgrade the SDK by changing that version; `synopkgland check`
|
|
@@ -104,8 +104,8 @@ dependencies = [
|
|
|
104
104
|
|
|
105
105
|
[[package]]
|
|
106
106
|
name = "syno-pkg-land-app"
|
|
107
|
-
version = "0.10.
|
|
108
|
-
source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.10.
|
|
107
|
+
version = "0.10.3"
|
|
108
|
+
source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.10.3#4e0fe8ee1f71a9818e50a38242882cebaa776cee"
|
|
109
109
|
dependencies = [
|
|
110
110
|
"libc",
|
|
111
111
|
"serde",
|
|
@@ -9,7 +9,7 @@ libc = "0.2"
|
|
|
9
9
|
serde = { version = "1", features = ["derive"] }
|
|
10
10
|
serde_json = "1"
|
|
11
11
|
# The SDK version is the tag; `synopkgland check` reads it from Cargo.lock.
|
|
12
|
-
syno-pkg-land-app = { git = "https://github.com/synopackageland/syno-pkg-land-sdk", tag = "v0.10.
|
|
12
|
+
syno-pkg-land-app = { git = "https://github.com/synopackageland/syno-pkg-land-sdk", tag = "v0.10.3" }
|
|
13
13
|
|
|
14
14
|
[profile.release]
|
|
15
15
|
# A handler panic becomes an "internal" reply; abort would end the App without one.
|