@synopackageland/templates 0.10.2 → 0.10.4
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 +20 -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/messages/de.json +2 -0
- package/templates/native-go/i18n/messages/en.json +2 -0
- package/templates/native-go/i18n/messages/es.json +2 -0
- package/templates/native-go/i18n/messages/fr.json +2 -0
- package/templates/native-go/i18n/messages/it.json +2 -0
- package/templates/native-go/i18n/messages/ja.json +2 -0
- package/templates/native-go/i18n/messages/ko.json +2 -0
- package/templates/native-go/i18n/messages/zh-CN.json +2 -0
- package/templates/native-go/i18n/messages/zh-TW.json +2 -0
- 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.4`; 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.4. The Vue frontend pins
|
|
46
|
+
`@synopackageland/ui` 0.9.6.
|
|
42
47
|
|
|
43
48
|
## Notice writer
|
|
44
49
|
|
|
@@ -63,6 +68,8 @@ export SYNOPKGLAND_DOCKER_SSH=my-docker-host # optional: the Dock
|
|
|
63
68
|
scripts/assemble.sh /tmp/app vue delegate # one combination, as init lays it out
|
|
64
69
|
scripts/assemble.sh --language rust /tmp/app-rs plain jobs # python, node or rust
|
|
65
70
|
scripts/gate.sh # layout, every combination, binary, npm pack
|
|
71
|
+
scripts/gate.sh --fast # only the combinations the changes reach
|
|
72
|
+
scripts/assemble.sh --list vue jobs # the templates a combination uses
|
|
66
73
|
```
|
|
67
74
|
|
|
68
75
|
Without `SYNOPKGLAND_SDK_DIR` the combinations use the released SDK that
|
|
@@ -78,6 +85,16 @@ the tag `Cargo.lock` pins. The gate runs each language's tests on Linux in
|
|
|
78
85
|
Docker (`scripts/bridge-linux-test.sh`: Python 3.8, Node.js 18, Rust).
|
|
79
86
|
CI is not available; `scripts/gate.sh` is the gate.
|
|
80
87
|
|
|
88
|
+
Use `scripts/gate.sh --fast` while developing: it tests only the combinations
|
|
89
|
+
that use a template changed since `origin/main` (`SYNOPKGLAND_GATE_BASE`),
|
|
90
|
+
committed or not, and prints the ones it skipped; a change under `scripts/`
|
|
91
|
+
tests them all. Run the full gate once before a release. The gate runs each
|
|
92
|
+
phase's jobs in parallel, `SYNOPKGLAND_GATE_JOBS` (default 3) at a time, and
|
|
93
|
+
prints a failed job's whole log. On `SYNOPKGLAND_DOCKER_SSH` the Rust checks
|
|
94
|
+
run in `synopkgland-gate-templates:<hash>` (`scripts/gate.Dockerfile`) with
|
|
95
|
+
the host's shared `synopkgland-cache-cargo` volume, and wait for one of its
|
|
96
|
+
two gate slots.
|
|
97
|
+
|
|
81
98
|
SDK usage, protocol and API documentation: <https://github.com/synopackageland/syno-pkg-land-sdk>.
|
|
82
99
|
|
|
83
100
|
## License
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/templates",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4",
|
|
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.4 h1:dCv3B5B8/WEqkz5gwGHfw6iBj2eokbigHyo/lC1JntA=
|
|
2
|
+
github.com/synopackageland/syno-pkg-land-sdk v0.10.4/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=
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "Die Datei ist größer als zulässig.",
|
|
23
23
|
"error.read_failed": "Die Datei kann nicht gelesen werden. Bitte versuchen Sie es später erneut.",
|
|
24
24
|
"error.identity_unavailable": "Dieses Benutzerkonto kann nicht ermittelt werden. Bitte versuchen Sie es später erneut.",
|
|
25
|
+
"error.APP_STOPPED": "Die App ist angehalten. Starten Sie sie im Paket-Zentrum und versuchen Sie es dann erneut.",
|
|
26
|
+
"error.APP_STARTING": "Die App wird gestartet. Versuchen Sie es gleich erneut.",
|
|
25
27
|
"greeting.adminOnly": "Nur Mitglieder der Gruppe administrators können den Gruß ändern.",
|
|
26
28
|
"greeting.label": "Neuer Gruß",
|
|
27
29
|
"greeting.save": "Speichern",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "The file is larger than allowed.",
|
|
23
23
|
"error.read_failed": "Unable to read the file. Please try again later.",
|
|
24
24
|
"error.identity_unavailable": "Unable to identify this user account. Please try again later.",
|
|
25
|
+
"error.APP_STOPPED": "The App is stopped. Start it in Package Center, then try again.",
|
|
26
|
+
"error.APP_STARTING": "The App is starting. Try again in a moment.",
|
|
25
27
|
"greeting.adminOnly": "Only members of the administrators group can change the greeting.",
|
|
26
28
|
"greeting.label": "New greeting",
|
|
27
29
|
"greeting.save": "Save",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "El archivo supera el tamaño permitido.",
|
|
23
23
|
"error.read_failed": "No se puede leer el archivo. Vuelva a intentarlo más tarde.",
|
|
24
24
|
"error.identity_unavailable": "No se puede identificar esta cuenta de usuario. Vuelva a intentarlo más tarde.",
|
|
25
|
+
"error.APP_STOPPED": "La App está detenida. Iníciela en el Centro de paquetes y vuelva a intentarlo.",
|
|
26
|
+
"error.APP_STARTING": "La App se está iniciando. Vuelva a intentarlo en un momento.",
|
|
25
27
|
"greeting.adminOnly": "Solo los miembros del grupo administrators pueden cambiar el saludo.",
|
|
26
28
|
"greeting.label": "Nuevo saludo",
|
|
27
29
|
"greeting.save": "Guardar",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "Le fichier dépasse la taille autorisée.",
|
|
23
23
|
"error.read_failed": "Impossible de lire le fichier. Veuillez réessayer ultérieurement.",
|
|
24
24
|
"error.identity_unavailable": "Impossible d'identifier ce compte utilisateur. Veuillez réessayer ultérieurement.",
|
|
25
|
+
"error.APP_STOPPED": "L’App est arrêtée. Démarrez-la dans le Centre de paquets, puis réessayez.",
|
|
26
|
+
"error.APP_STARTING": "L’App démarre. Réessayez dans un instant.",
|
|
25
27
|
"greeting.adminOnly": "Seuls les membres du groupe administrators peuvent modifier le message d'accueil.",
|
|
26
28
|
"greeting.label": "Nouveau message d'accueil",
|
|
27
29
|
"greeting.save": "Sauvegarder",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "Il file supera le dimensioni consentite.",
|
|
23
23
|
"error.read_failed": "Impossibile leggere il file. Riprovare più tardi.",
|
|
24
24
|
"error.identity_unavailable": "Impossibile identificare questo account utente. Riprovare più tardi.",
|
|
25
|
+
"error.APP_STOPPED": "L’App è arrestata. Avviarla in Centro pacchetti, quindi riprovare.",
|
|
26
|
+
"error.APP_STARTING": "L’App è in fase di avvio. Riprovare tra poco.",
|
|
25
27
|
"greeting.adminOnly": "Solo i membri del gruppo administrators possono modificare il saluto.",
|
|
26
28
|
"greeting.label": "Nuovo saluto",
|
|
27
29
|
"greeting.save": "Salva",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "ファイルが許可されたサイズを超えています。",
|
|
23
23
|
"error.read_failed": "ファイルを読み取れません。後でもう一度お試しください。",
|
|
24
24
|
"error.identity_unavailable": "このユーザー アカウントを識別できません。後でもう一度お試しください。",
|
|
25
|
+
"error.APP_STOPPED": "App は停止しています。パッケージ センターで起動してから、もう一度お試しください。",
|
|
26
|
+
"error.APP_STARTING": "App を起動しています。しばらくしてから再試行してください。",
|
|
25
27
|
"greeting.adminOnly": "あいさつを変更できるのは administrators グループのメンバーのみです。",
|
|
26
28
|
"greeting.label": "新しいあいさつ",
|
|
27
29
|
"greeting.save": "保存",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "파일이 허용된 크기를 초과합니다.",
|
|
23
23
|
"error.read_failed": "파일을 읽을 수 없습니다. 나중에 다시 시도하십시오.",
|
|
24
24
|
"error.identity_unavailable": "이 사용자 계정을 확인할 수 없습니다. 나중에 다시 시도하십시오.",
|
|
25
|
+
"error.APP_STOPPED": "App이 중지되었습니다. 패키지 센터에서 시작한 후 다시 시도하십시오.",
|
|
26
|
+
"error.APP_STARTING": "App을 시작하는 중입니다. 잠시 후 다시 시도하십시오.",
|
|
25
27
|
"greeting.adminOnly": "administrators 그룹의 구성원만 인사말을 변경할 수 있습니다.",
|
|
26
28
|
"greeting.label": "새 인사말",
|
|
27
29
|
"greeting.save": "저장",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "文件超过允许的大小。",
|
|
23
23
|
"error.read_failed": "无法读取文件。请稍后再试。",
|
|
24
24
|
"error.identity_unavailable": "无法识别此用户账号。请稍后再试。",
|
|
25
|
+
"error.APP_STOPPED": "App 已停止。请在套件中心启动后重试。",
|
|
26
|
+
"error.APP_STARTING": "App 正在启动,请稍后重试。",
|
|
25
27
|
"greeting.adminOnly": "只有 administrators 群组的成员可以更改问候语。",
|
|
26
28
|
"greeting.label": "新的问候语",
|
|
27
29
|
"greeting.save": "保存",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"error.limit_exceeded": "檔案超過允許的大小。",
|
|
23
23
|
"error.read_failed": "無法讀取檔案。請稍後再試。",
|
|
24
24
|
"error.identity_unavailable": "無法識別此使用者帳號。請稍後再試。",
|
|
25
|
+
"error.APP_STOPPED": "App 已停止。請在套件中心啟動後再試一次。",
|
|
26
|
+
"error.APP_STARTING": "App 正在啟動,請稍後再試。",
|
|
25
27
|
"greeting.adminOnly": "只有 administrators 群組的成員可以變更問候語。",
|
|
26
28
|
"greeting.label": "新的問候語",
|
|
27
29
|
"greeting.save": "儲存",
|
|
@@ -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.4",
|
|
11
|
+
"@synopackageland/ui": "0.9.6",
|
|
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.4",
|
|
1152
|
+
"resolved": "https://registry.npmjs.org/@synopackageland/sdk/-/sdk-0.10.4.tgz",
|
|
1153
|
+
"integrity": "sha512-cYH1G/+mBCQfwA+lyF62kpt2yKmLalnUzZ4S/tO4O7oKOm9wTANq9EnWuy06ulKbK83BGzYmPgEISNX6f/ryaQ==",
|
|
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.6",
|
|
1171
|
+
"resolved": "https://registry.npmjs.org/@synopackageland/ui/-/ui-0.9.6.tgz",
|
|
1172
|
+
"integrity": "sha512-Nunp7pVVCsqR73OcreJOAgzZGtr1YBK8Dip3B6YRbIZQTtIPQ23Z5ZJVnpV7P72H03P4WwpWuprKxCBHPKMhUg==",
|
|
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.4"
|
|
108
|
+
source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.10.4#60a92993e58ad1bb3480e8978dd9171e49142360"
|
|
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.4" }
|
|
13
13
|
|
|
14
14
|
[profile.release]
|
|
15
15
|
# A handler panic becomes an "internal" reply; abort would end the App without one.
|