@synopackageland/templates 0.0.0-stage → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +62 -2
- package/package.json +11 -4
- package/templates/_shared/AGENTS.md +146 -0
- package/templates/_shared/CLAUDE.md +1 -0
- package/templates/_shared/GO-LICENSE +27 -0
- package/templates/_shared/GO-PATENTS +22 -0
- package/templates/_shared/LICENSES/TEMPLATE.txt +21 -0
- package/templates/_shared/third-party-notices.mjs +55 -0
- package/templates/binary/LICENSES/GO-LICENSE +27 -0
- package/templates/binary/LICENSES/GO-PATENTS +22 -0
- package/templates/binary/dsm-package.yaml +46 -0
- package/templates/binary/example/main.go +16 -0
- package/templates/binary/gitignore +2 -0
- package/templates/binary/i18n/messages/de.json +4 -0
- package/templates/binary/i18n/messages/en.json +4 -0
- package/templates/binary/i18n/messages/es.json +4 -0
- package/templates/binary/i18n/messages/fr.json +4 -0
- package/templates/binary/i18n/messages/it.json +4 -0
- package/templates/binary/i18n/messages/ja.json +4 -0
- package/templates/binary/i18n/messages/ko.json +4 -0
- package/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/templates/binary/ui/app.css +4 -0
- package/templates/binary/ui/app.js +32 -0
- package/templates/compose/compose.yaml +8 -0
- package/templates/compose/synology-app.yaml +16 -0
- package/templates/native-go/README.md +368 -0
- package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +53 -0
- package/templates/native-go/backend/cmd/app/main.go +101 -0
- package/templates/native-go/backend/cmd/background-worker/main.go +38 -0
- package/templates/native-go/backend/go.mod +9 -0
- package/templates/native-go/backend/go.sum +4 -0
- package/templates/native-go/backend/internal/api/permissions.go +26 -0
- package/templates/native-go/backend/internal/api/permissions.json +5 -0
- package/templates/native-go/backend/internal/api/permissions_test.go +30 -0
- package/templates/native-go/backend/internal/app/background.go +249 -0
- package/templates/native-go/backend/internal/app/background_none.go +8 -0
- package/templates/native-go/backend/internal/app/background_owner.go +38 -0
- package/templates/native-go/backend/internal/app/background_owner_test.go +163 -0
- package/templates/native-go/backend/internal/app/background_schedule.go +69 -0
- package/templates/native-go/backend/internal/app/background_schedule_test.go +62 -0
- package/templates/native-go/backend/internal/app/background_test.go +320 -0
- package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/templates/native-go/backend/internal/app/delegate_none.go +5 -0
- package/templates/native-go/backend/internal/app/identity.go +20 -0
- package/templates/native-go/backend/internal/app/identity_test.go +15 -0
- package/templates/native-go/backend/internal/app/migrations.go +41 -0
- package/templates/native-go/backend/internal/app/migrations_test.go +41 -0
- package/templates/native-go/backend/internal/app/portal.go +30 -0
- package/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/templates/native-go/backend/internal/app/root_none.go +9 -0
- package/templates/native-go/backend/internal/app/routes.go +137 -0
- package/templates/native-go/backend/internal/app/routes_test.go +197 -0
- package/templates/native-go/backend/internal/app/session_files.go +9 -0
- package/templates/native-go/backend/internal/app/session_files_test.go +14 -0
- package/templates/native-go/backend/internal/app/shared_folder.go +144 -0
- package/templates/native-go/backend/internal/app/shared_folder_test.go +158 -0
- package/templates/native-go/dsm-package.yaml +71 -0
- package/templates/native-go/gitignore +1 -0
- package/templates/native-go/i18n/glossary.json +663 -0
- package/templates/native-go/i18n/messages/de.json +29 -0
- package/templates/native-go/i18n/messages/en.json +29 -0
- package/templates/native-go/i18n/messages/es.json +29 -0
- package/templates/native-go/i18n/messages/fr.json +29 -0
- package/templates/native-go/i18n/messages/it.json +29 -0
- package/templates/native-go/i18n/messages/ja.json +29 -0
- package/templates/native-go/i18n/messages/ko.json +29 -0
- package/templates/native-go/i18n/messages/zh-CN.json +29 -0
- package/templates/native-go/i18n/messages/zh-TW.json +29 -0
- package/templates/native-go/ui/app.css +45 -0
- package/templates/native-go/ui/app.js +111 -0
- package/templates/native-go-delegate/backend/cmd/background-worker/main.go +49 -0
- package/templates/native-go-delegate/backend/internal/app/delegate.go +25 -0
- package/templates/native-go-delegate/backend/internal/app/delegate_on.go +5 -0
- package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +31 -0
- package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +32 -0
- package/templates/native-go-delegate/frontend/test/capability-panels.test.ts +77 -0
- package/templates/native-go-jobs/backend/internal/app/background_on.go +7 -0
- package/templates/native-go-jobs/backend/internal/app/background_routes_test.go +87 -0
- package/templates/native-go-jobs/frontend/test/background-page.test.ts +20 -0
- package/templates/native-go-root-ops/backend/internal/app/executor.go +140 -0
- package/templates/native-go-root-ops/backend/internal/app/executor_test.go +118 -0
- package/templates/native-go-root-ops/root/whoami.sh +3 -0
- package/templates/native-go-vue/README.md +51 -0
- package/templates/native-go-vue/frontend/DESIGN.md +61 -0
- package/templates/native-go-vue/frontend/package-lock.json +2550 -0
- package/templates/native-go-vue/frontend/package.json +23 -0
- package/templates/native-go-vue/frontend/src/App.vue +90 -0
- package/templates/native-go-vue/frontend/src/CapabilityPanels.vue +6 -0
- package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/templates/native-go-vue/frontend/src/main.ts +33 -0
- package/templates/native-go-vue/frontend/src/style.css +27 -0
- package/templates/native-go-vue/frontend/test/apps.test.ts +57 -0
- package/templates/native-go-vue/frontend/test/native-controls.test.ts +27 -0
- package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
- package/templates/native-go-vue/frontend/tsconfig.json +1 -0
- package/templates/native-go-vue/frontend/vite.config.ts +11 -0
- package/templates/native-go-vue/gitignore +2 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 synopkgland
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,63 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @synopackageland/templates
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Project templates for `synopkgland init` and `synopkgland add`. They hold only
|
|
4
|
+
the files an App owns; the SDK (`github.com/synopackageland/syno-pkg-land-sdk`, npm
|
|
5
|
+
`@synopackageland/sdk`) is a dependency of the generated project, never a copy.
|
|
6
|
+
|
|
7
|
+
| Template | What it adds |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `native-go` | Base: `dsm-package.yaml`, Go module (`backend/cmd/{app,background-worker}`, `backend/internal/app`, `backend/internal/api/permissions.json`), plain `ui/`, i18n |
|
|
10
|
+
| `native-go-vue` | Vue shell in `frontend/` (`App.vue`, `main.ts`, app i18n, `CapabilityPanels.vue`) |
|
|
11
|
+
| `native-go-jobs` | Background job routes in `internal/app` and their page test |
|
|
12
|
+
| `native-go-delegate` | Delegate routes, the delegate background worker, the delegate `CapabilityPanels.vue` |
|
|
13
|
+
| `native-go-root-ops` | Executor routes in `internal/app` and an example `root/whoami.sh` |
|
|
14
|
+
| `binary` | A prebuilt static CGI (`example/main.go`) with a plain UI |
|
|
15
|
+
| `compose` | Container Manager project (`compose.yaml`, `synology-app.yaml`) |
|
|
16
|
+
| `_shared` | Agent guides, template license, Go license texts, third-party notice writer |
|
|
17
|
+
|
|
18
|
+
Overlays are copied over `native-go` in the order root-ops, vue, jobs, delegate.
|
|
19
|
+
An overlay may replace `internal/app/*_none.go` (the CLI deletes the matching
|
|
20
|
+
`_none.go` file); nothing outside `internal/app` and the Vue shell differs.
|
|
21
|
+
The placeholders `__PACKAGE__` (also the Go module path), `__DISPLAY_NAME__` and
|
|
22
|
+
`__BACKGROUND_ENABLED__` are substituted by `init`.
|
|
23
|
+
|
|
24
|
+
`backend/go.mod` requires `github.com/synopackageland/syno-pkg-land-sdk v0.9.0`; that line is
|
|
25
|
+
the single source of the SDK version and `frontend/package.json` pins
|
|
26
|
+
`@synopackageland/sdk` to the same version.
|
|
27
|
+
|
|
28
|
+
## Notice writer
|
|
29
|
+
|
|
30
|
+
`init` copies the writer to `frontend/third-party-notices.mjs`. Tools that keep
|
|
31
|
+
their own copy of the templates import it from the package instead; no other
|
|
32
|
+
path is exported:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import {writeThirdPartyNotices} from '@synopackageland/templates/notices'
|
|
36
|
+
writeThirdPartyNotices('frontend', 'ui/LICENSES', {ui: true})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
It replaces only `THIRD_PARTY_NOTICES.txt`, `inventory.json`, `UI-LICENSE`
|
|
40
|
+
and `UI-THIRD_PARTY.md` in the output directory; other files there stay.
|
|
41
|
+
|
|
42
|
+
## Develop
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
export GOPRIVATE='github.com/synopackageland/*' # the SDK repository is private
|
|
46
|
+
export SYNOPKGLAND_SDK_DIR=~/Public/synopackageland/sdk # optional sdk checkout: Go module at the root, ts/
|
|
47
|
+
scripts/assemble.sh /tmp/app vue delegate # one combination, as init lays it out
|
|
48
|
+
scripts/gate.sh # layout, every combination, binary, npm pack
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Without `SYNOPKGLAND_SDK_DIR` the combinations use the released SDK that
|
|
52
|
+
`backend/go.mod` and `frontend/package.json` pin. With it, `assemble.sh` adds
|
|
53
|
+
`replace github.com/synopackageland/syno-pkg-land-sdk => $SYNOPKGLAND_SDK_DIR`
|
|
54
|
+
and installs `$SYNOPKGLAND_SDK_DIR/ts` as an `npm pack` tarball (not a link, so Vue
|
|
55
|
+
resolves once). With `SYNOPKGLAND_UI_TARBALL` set it installs that tarball as
|
|
56
|
+
`@synopackageland/ui`, for a UI version not yet on npm. CI is not available; `scripts/gate.sh` is the gate.
|
|
57
|
+
|
|
58
|
+
SDK usage, protocol and API documentation: <https://github.com/synopackageland/syno-pkg-land-sdk>.
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
MIT, see [LICENSE](LICENSE). Generated projects receive
|
|
63
|
+
`templates/_shared/LICENSES/TEMPLATE.txt`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/templates",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
}
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Project templates for synopkgland init: native-go (plain or Vue, with jobs, delegate and root-ops overlays), binary and compose.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {"type": "git", "url": "git+https://github.com/synopackageland/syno-pkg-land-templates.git"},
|
|
7
|
+
"exports": {
|
|
8
|
+
"./package.json": "./package.json",
|
|
9
|
+
"./notices": "./templates/_shared/third-party-notices.mjs"
|
|
10
|
+
},
|
|
11
|
+
"files": ["templates/", "LICENSE", "README.md"],
|
|
12
|
+
"scripts": {"gate": "scripts/gate.sh"}
|
|
13
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# AI authoring
|
|
2
|
+
|
|
3
|
+
Start with `synopkgland skill list`, then `synopkgland skill show orchestrator`.
|
|
4
|
+
Use `synopkgland skill path` to locate the bundled references; read the relevant
|
|
5
|
+
skill with `synopkgland skill show <id>` before editing.
|
|
6
|
+
For UI work, read `synopkgland skill show ui-vue` and `synopkgland skill show ui-json`.
|
|
7
|
+
Use the installed SDK contracts and preserve package.json/lockfile pins.
|
|
8
|
+
|
|
9
|
+
For UI discovery, run `npx --no syno-pkg-land-ui catalog --json` and
|
|
10
|
+
`npx --no syno-pkg-land-ui describe Button --json` from the installed frontend.
|
|
11
|
+
Read its prompt and exported Vue docs/types before choosing component APIs.
|
|
12
|
+
Use `syno-pkg-land-ui` directly in npm scripts; keep AI guidance version-independent.
|
|
13
|
+
|
|
14
|
+
From the project root, run `synopkgland check --json`,
|
|
15
|
+
`synopkgland build --json`, then `synopkgland inspect <spk> --json` on the emitted SPK.
|
|
16
|
+
For Vue, first run `npm ci`, `npm test` and `npm run build` in frontend.
|
|
17
|
+
Do not connect to or change a NAS without explicit task authorization.
|
|
18
|
+
|
|
19
|
+
## Who may use the app (`entry`)
|
|
20
|
+
|
|
21
|
+
Omit `entry` to keep legacy access. `entry: admin-only` admits DSM administrators
|
|
22
|
+
only. `entry: app-privilege` also admits accounts that Control Panel >
|
|
23
|
+
Application Privileges allows for `SYNO.SDS.<package>.Instance`; DSM's install
|
|
24
|
+
default allows administrators only, so nobody else enters until an admin grants
|
|
25
|
+
access. One CGI check covers every route; failures refuse; changes apply within
|
|
26
|
+
30 seconds. Never re-implement AppPriv rules in the App.
|
|
27
|
+
Mark routes ordinary users call `authenticated` in permissions.json, keep whole
|
|
28
|
+
admin routes at the default, guard global settings inside shared routes with
|
|
29
|
+
`api.RequireAdmin(caller)`, and hide admin controls with `ctx.user?.isAdmin`
|
|
30
|
+
(UI only, never the authority). Example: users read the greeting; only admins
|
|
31
|
+
call `greeting.set`.
|
|
32
|
+
|
|
33
|
+
## DSM Application Portal (`portal`)
|
|
34
|
+
|
|
35
|
+
`synopkgland add portal` (or `portal: {}` / `portal: {alias: my-app}` in
|
|
36
|
+
dsm-package.yaml; Compose: `integration.web.portal` for a DSM-window app behind
|
|
37
|
+
the auth gateway) registers `https://<nas>/<alias>/`, which opens the app after
|
|
38
|
+
DSM sign-in. Read `synopkgland skill show portal` before changing it.
|
|
39
|
+
The install wizard only proposes the alias; an administrator activates it from
|
|
40
|
+
the app's portal panel (`ctx.portal`, DSM's own `SYNO.Core.AppPortal` in the
|
|
41
|
+
admin's session) or Control Panel > Login Portal > Applications. Ordinary users
|
|
42
|
+
get the link from the backend's read-only `portal.status`, else "ask an
|
|
43
|
+
administrator". Never write `AppPortal.json` or `@appconf/<package>`, never add
|
|
44
|
+
a backend route that sets the alias, and never relay QuickConnect responses or
|
|
45
|
+
build QuickConnect links. A portal needs os_min_ver 7.3.2-86009 or later (DSM
|
|
46
|
+
7.1.1 refuses it with error 320; 7.2 is untested) and `add portal` raises it;
|
|
47
|
+
beyond that, support is detected (SYNO.API.Info), not version-gated.
|
|
48
|
+
|
|
49
|
+
## Permanent destination integration
|
|
50
|
+
|
|
51
|
+
`init --with delegate` / `add delegate` default to `operations: [files.moveFromStaging]`,
|
|
52
|
+
`destinations: [save]`, `lifetime: until-revoked`, `scope: install-selected`. Existing legacy
|
|
53
|
+
TTL declarations retain their 1–3600 second service / 30-day wire ceiling and
|
|
54
|
+
64 MiB / 60-second URL example. Do not apply those limits to the new move API.
|
|
55
|
+
Delegate can coexist with daemon; ordinary standalone jobs cannot. Preserve
|
|
56
|
+
App business route floors. Binary/compose remain unsupported.
|
|
57
|
+
|
|
58
|
+
Use File Station `/home[/...]`, never `/homes/<user>`. The SDK destination picker
|
|
59
|
+
selection itself grants access after fresh DSM session/UID/write verification,
|
|
60
|
+
without a second consent dialog. Ordinary and administrator subjects use their
|
|
61
|
+
own nonzero UID/current groups, never root. An online App can create an in-scope
|
|
62
|
+
grant using a valid session; there is no trusted external consent or notification.
|
|
63
|
+
|
|
64
|
+
Use the default `createBackgroundSaveFacade(ctx)` / CapabilityPanels management
|
|
65
|
+
page. `delegate.status` exposes verified `disabled` and manifest mode; missing
|
|
66
|
+
protected evidence must not imply enabled. `delegate.operations.list` accepts
|
|
67
|
+
only `{}`, uses the backend move mirrors, and returns the caller's username+UID
|
|
68
|
+
operations only, including for admins. Mirrors are not completion receipts:
|
|
69
|
+
query original `delegate.operations.get` and show Saved only for committed with
|
|
70
|
+
a receipt. Cancel by the same reference; revoke by grant ID. Never resubmit
|
|
71
|
+
uncertain/interrupted work. Admin disable is protected and revokes grants;
|
|
72
|
+
enable/mailbox start does not resurrect them. Keep IDs, never session credentials.
|
|
73
|
+
|
|
74
|
+
App-owned daemon completion and scheduled CSV export call configured Go
|
|
75
|
+
`Service.MoveFromStaging` with `delegation_id`, stable `job_id`, private relative
|
|
76
|
+
`staging`, `name`, `size`. No owner/UID selector. Bounds: 16 GiB/file, queued16,
|
|
77
|
+
active1/package, 24-hour attempt, 5-second revalidation, 10 MiB operation records,
|
|
78
|
+
50 MiB audit. Scope is a usage restriction, not hard subtree confinement.
|
|
79
|
+
Local production-executor fixtures use fake DSM/peer/bulk writer; do not claim
|
|
80
|
+
NAS ACL, actual writer UID, logout/reboot or full lifecycle acceptance from them.
|
|
81
|
+
Gopeed product wiring remains a separate task.
|
|
82
|
+
|
|
83
|
+
Admission recovery (per job): on `EXECUTOR_UNAVAILABLE`, `EXECUTOR_TIMEOUT`,
|
|
84
|
+
`EXECUTOR_PROTOCOL`, `canceled`, `EXECUTOR_PAUSED`, `queue-full`,
|
|
85
|
+
`STORAGE_ERROR`, `ADMISSION_PENDING`, `jobs_busy` or `jobs_unavailable` (the
|
|
86
|
+
package journal was busy or failed transiently; a caller deadline or cancel
|
|
87
|
+
spent waiting for it is `canceled`), call `MoveFromStaging` again later with
|
|
88
|
+
the same exact params. It queries the original reference first and re-sends
|
|
89
|
+
admission only when the executor does not know it and the pinned source is
|
|
90
|
+
unchanged; executor tuple deduplication keeps one operation, so a lost reply or a
|
|
91
|
+
racing caller never copies twice. At most 10 possibly-delivered sends, 2 s
|
|
92
|
+
backoff doubling to 5 min; the worker sweep does the same. Terminal, do not
|
|
93
|
+
retry: `APP_DENIED`, `DELEGATION_DENIED`, `operation-conflict`, `disabled`,
|
|
94
|
+
`SCOPE_DENIED` and other executor refusals, `STAGING_CHANGED`,
|
|
95
|
+
`ADMISSION_EXHAUSTED`, `spool_unsafe` and `journal_corrupt` (repair the package
|
|
96
|
+
spool first), and `operation-not-found` for an accepted operation.
|
|
97
|
+
Never change job/grant IDs, delete mirrors or call the socket directly to retry.
|
|
98
|
+
|
|
99
|
+
Cancellation (per job): `CancelOperation` / `delegate.operations.cancel` with the
|
|
100
|
+
original ref is idempotent; repeat it with the same ref after any retryable
|
|
101
|
+
error or a lost reply. A reply `queued`→`canceled` is final at once. A copy in
|
|
102
|
+
flight answers `copying` with code `CANCEL_REQUESTED`: the cancel is accepted and
|
|
103
|
+
durable, not finished; poll `OperationStatus` on the same ref until terminal
|
|
104
|
+
(repeating the cancel is harmless). `canceled` (`OPERATION_CANCELED`) guarantees the writer
|
|
105
|
+
stopped, its part file is removed, nothing was published and staging is kept; it
|
|
106
|
+
stays canceled across executor crash, package stop/start and logout. `committed`
|
|
107
|
+
means publication won the race: the file stays (cancel never removes it) and only
|
|
108
|
+
the app record may be dropped. `uncertain` means a publish attempt failed before
|
|
109
|
+
the cancel; keep querying. A cancel of a ref the executor has not admitted yet
|
|
110
|
+
(reserved/sent mirror) returns `canceled` and leaves a tombstone, so a late or
|
|
111
|
+
recovered admission of that ref returns `canceled` and never copies; a producer
|
|
112
|
+
cancel is also written to the mirror first, so `MoveFromStaging` and the worker
|
|
113
|
+
sweep forward the cancel instead of admitting it.
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
### Install-selected scope and the destination API
|
|
117
|
+
|
|
118
|
+
- The DSM install wizard dynamically lists local shares (`SYNO.Core.Share list`
|
|
119
|
+
via `api_store`) and offers home. It saves only a package-owned pre-selection
|
|
120
|
+
in `var/delegate-install.json`; never trust that file for authority.
|
|
121
|
+
- The existing administrator PasswordConfirm form displays this pre-selection
|
|
122
|
+
at first enable. `ctx.executor.authorize(password, selectedScope)` confirms it
|
|
123
|
+
through a pinned, exact-readback one-time root task. Settings changes use the
|
|
124
|
+
same form/password path; no App CGI route may set protected scope directly.
|
|
125
|
+
- The executor trusts `/usr/local/etc/synopkgland/<pkg>/delegations/selected-scope.record`
|
|
126
|
+
only. Its scope/generation are runtime protected state; shipped policy pins
|
|
127
|
+
lock the selection mode and operations. Changes revoke old grants and cancel
|
|
128
|
+
pending writes. Change-away-and-back never revives an old grant.
|
|
129
|
+
- Follow `selection` from verified `delegate.status` / `sdk.destination(key)`.
|
|
130
|
+
If the draft differs, display the difference and follow the protected value.
|
|
131
|
+
Home and fixed `shared:<name>` manifests stay compatible.
|
|
132
|
+
- Frontend: `const sdk = createBackgroundSaveFacade(ctx); const current = await
|
|
133
|
+
sdk.destination('save')` returns typed `{key, selection, destination, status}`.
|
|
134
|
+
`selection` contains `{scope, root, generation}`; `destination` is this caller's
|
|
135
|
+
grant or null. Handle active/missing/reselection-required/needs-scope-confirmation/disabled.
|
|
136
|
+
- Go: `Service.Destination(ctx, caller, request, key)` verifies the fresh DSM
|
|
137
|
+
session and username+UID. Capture its active grant ID into the App job. The
|
|
138
|
+
offline producer uses existing `Service.MoveFromStaging`; no user/UID selector,
|
|
139
|
+
cookie, token, or browser path cache. Executor revalidates at use/publication.
|
|
140
|
+
- The generated Background saves page includes a working **Save example file**
|
|
141
|
+
(`sdk.exportExample({key, job_id})`, `delegate.example.export`). Go
|
|
142
|
+
`ExportExample` creates a private JSON file, calls `MoveFromStaging` once, and
|
|
143
|
+
repeats the original request on repeated IDs. Review `example.go` to
|
|
144
|
+
adapt a real producer; show Saved only from a protected committed receipt.
|
|
145
|
+
- Wizard support is measured on vt-nas DSM 7.4 via a session-only SSH local
|
|
146
|
+
forward. This is not proof of other DSM releases or full writer/reboot behavior.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Read [AGENTS.md](AGENTS.md).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright 2009 The Go Authors.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions are
|
|
5
|
+
met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright
|
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
|
9
|
+
* Redistributions in binary form must reproduce the above
|
|
10
|
+
copyright notice, this list of conditions and the following disclaimer
|
|
11
|
+
in the documentation and/or other materials provided with the
|
|
12
|
+
distribution.
|
|
13
|
+
* Neither the name of Google LLC nor the names of its
|
|
14
|
+
contributors may be used to endorse or promote products derived from
|
|
15
|
+
this software without specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
18
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
19
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
20
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
21
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
22
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
23
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
24
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
25
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Additional IP Rights Grant (Patents)
|
|
2
|
+
|
|
3
|
+
"This implementation" means the copyrightable works distributed by
|
|
4
|
+
Google as part of the Go project.
|
|
5
|
+
|
|
6
|
+
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
7
|
+
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
8
|
+
patent license to make, have made, use, offer to sell, sell, import,
|
|
9
|
+
transfer and otherwise run, modify and propagate the contents of this
|
|
10
|
+
implementation of Go, where such license applies only to those patent
|
|
11
|
+
claims, both currently owned or controlled by Google and acquired in
|
|
12
|
+
the future, licensable by Google that are necessarily infringed by this
|
|
13
|
+
implementation of Go. This grant does not include claims that would be
|
|
14
|
+
infringed only as a consequence of further modification of this
|
|
15
|
+
implementation. If you or your agent or exclusive licensee institute or
|
|
16
|
+
order or agree to the institution of patent litigation against any
|
|
17
|
+
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
18
|
+
that this implementation of Go or any code incorporated within this
|
|
19
|
+
implementation of Go constitutes direct or contributory patent
|
|
20
|
+
infringement, or inducement of patent infringement, then any patent
|
|
21
|
+
rights granted to you under this License for this implementation of Go
|
|
22
|
+
shall terminate as of the date such litigation is filed.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 synopkgland
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const OWNED = ['THIRD_PARTY_NOTICES.txt', 'inventory.json', 'UI-LICENSE', 'UI-THIRD_PARTY.md'];
|
|
5
|
+
|
|
6
|
+
// Conservative inventory of every locked production dependency, including
|
|
7
|
+
// dependencies tree-shaken from the bundle. Build tools marked dev are omitted.
|
|
8
|
+
// Read actual upstream license/notice files, never synthesize license text from
|
|
9
|
+
// SPDX metadata. npm ci must have installed the exact lock before this runs.
|
|
10
|
+
export function writeThirdPartyNotices(root, output, { ui = false } = {}) {
|
|
11
|
+
const lock = JSON.parse(readFileSync(join(root, 'package-lock.json'), 'utf8'));
|
|
12
|
+
if (lock.lockfileVersion < 2 || !lock.packages) throw new Error('Notice generation requires a v2/v3 npm lockfile');
|
|
13
|
+
const inventory = [];
|
|
14
|
+
const sections = [];
|
|
15
|
+
let uiFiles;
|
|
16
|
+
for (const [path, entry] of Object.entries(lock.packages).sort(([a], [b]) => a.localeCompare(b, 'en'))) {
|
|
17
|
+
if (!path || entry.dev) continue;
|
|
18
|
+
if (!/^node_modules\//.test(path) || path.split('/').includes('..') || entry.link) throw new Error(`Unsupported notice package path: ${path}`);
|
|
19
|
+
const dir = join(root, path);
|
|
20
|
+
const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
|
|
21
|
+
if (pkg.version !== entry.version) throw new Error(`Notice version mismatch: ${path}; run npm ci`);
|
|
22
|
+
const files = readdirSync(dir, { withFileTypes: true })
|
|
23
|
+
.filter(f => f.isFile() && /^(licen[sc]e|copying|notice|copyright)([.-]|$)/i.test(f.name))
|
|
24
|
+
.map(f => f.name).sort();
|
|
25
|
+
const texts = files.map(file => ({ file, text: readFileSync(join(dir, file), 'utf8') }));
|
|
26
|
+
let source, provenance;
|
|
27
|
+
if (!files.some(f => /^(licen[sc]e|copying)([.-]|$)/i.test(f))) {
|
|
28
|
+
const index = new URL('./notice-overrides/index.json', import.meta.url);
|
|
29
|
+
const overrides = existsSync(index) ? JSON.parse(readFileSync(index, 'utf8')) : {};
|
|
30
|
+
const override = overrides[`${pkg.name}@${pkg.version}`];
|
|
31
|
+
if (!override || !entry.integrity || override.integrity !== entry.integrity) throw new Error(`Missing upstream license text: ${pkg.name}@${pkg.version}`);
|
|
32
|
+
source = override.source;
|
|
33
|
+
provenance = override.provenance;
|
|
34
|
+
texts.push({file: 'LICENSE (pinned upstream source)', text: readFileSync(new URL(`./notice-overrides/${override.file}`, import.meta.url), 'utf8')});
|
|
35
|
+
files.push(override.file);
|
|
36
|
+
}
|
|
37
|
+
// UI ships its own aggregate for fonts, icons and dependencies/assets.
|
|
38
|
+
if (pkg.name === '@synopackageland/ui') {
|
|
39
|
+
uiFiles = {
|
|
40
|
+
'UI-LICENSE': readFileSync(join(dir, 'LICENSE'), 'utf8'),
|
|
41
|
+
'UI-THIRD_PARTY.md': readFileSync(join(dir, 'LICENSES/THIRD_PARTY.md'), 'utf8'),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
inventory.push({ name: pkg.name, version: pkg.version, license: pkg.license ?? entry.license ?? 'unknown', integrity: entry.integrity, path, files, ...(source ? {source, provenance} : {}) });
|
|
45
|
+
sections.push(`\n===== ${pkg.name}@${pkg.version} (${pkg.license ?? entry.license ?? 'unknown'}) =====\n` + (source ? `Source: ${source}\n${provenance}\n` : '') + texts.map(({ file, text }) => `\n--- ${file} ---\n${text}\n`).join(''));
|
|
46
|
+
}
|
|
47
|
+
if (ui && !uiFiles) throw new Error('UI dependency is missing from the locked production inventory');
|
|
48
|
+
// Replace only the files this writer owns: the App may keep its own legal
|
|
49
|
+
// texts in the same directory (ui/licenses is ui/LICENSES on macOS).
|
|
50
|
+
mkdirSync(output, { recursive: true });
|
|
51
|
+
for (const name of OWNED) rmSync(join(output, name), { force: true });
|
|
52
|
+
writeFileSync(join(output, 'THIRD_PARTY_NOTICES.txt'), 'Locked production dependency notices (conservative superset of bundled code).\n' + sections.join(''));
|
|
53
|
+
writeFileSync(join(output, 'inventory.json'), JSON.stringify(inventory, null, 2) + '\n');
|
|
54
|
+
for (const [name, text] of Object.entries(uiFiles ?? {})) writeFileSync(join(output, name), text);
|
|
55
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright 2009 The Go Authors.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions are
|
|
5
|
+
met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright
|
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
|
9
|
+
* Redistributions in binary form must reproduce the above
|
|
10
|
+
copyright notice, this list of conditions and the following disclaimer
|
|
11
|
+
in the documentation and/or other materials provided with the
|
|
12
|
+
distribution.
|
|
13
|
+
* Neither the name of Google LLC nor the names of its
|
|
14
|
+
contributors may be used to endorse or promote products derived from
|
|
15
|
+
this software without specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
18
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
19
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
20
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
21
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
22
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
23
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
24
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
25
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Additional IP Rights Grant (Patents)
|
|
2
|
+
|
|
3
|
+
"This implementation" means the copyrightable works distributed by
|
|
4
|
+
Google as part of the Go project.
|
|
5
|
+
|
|
6
|
+
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
7
|
+
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
8
|
+
patent license to make, have made, use, offer to sell, sell, import,
|
|
9
|
+
transfer and otherwise run, modify and propagate the contents of this
|
|
10
|
+
implementation of Go, where such license applies only to those patent
|
|
11
|
+
claims, both currently owned or controlled by Google and acquired in
|
|
12
|
+
the future, licensable by Google that are necessarily infringed by this
|
|
13
|
+
implementation of Go. This grant does not include claims that would be
|
|
14
|
+
infringed only as a consequence of further modification of this
|
|
15
|
+
implementation. If you or your agent or exclusive licensee institute or
|
|
16
|
+
order or agree to the institution of patent litigation against any
|
|
17
|
+
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
18
|
+
that this implementation of Go or any code incorporated within this
|
|
19
|
+
implementation of Go constitutes direct or contributory patent
|
|
20
|
+
infringement, or inducement of patent infringement, then any patent
|
|
21
|
+
rights granted to you under this License for this implementation of Go
|
|
22
|
+
shall terminate as of the date such litigation is filed.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# A prebuilt, static Linux CGI using the same DSM package surface as native-go.
|
|
2
|
+
schema: 2
|
|
3
|
+
package: __PACKAGE__
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
build: 1
|
|
6
|
+
displayname: __DISPLAY_NAME__
|
|
7
|
+
description: A DSM package with a prebuilt binary CGI and DSM window UI.
|
|
8
|
+
# Package Center and DSM window icon: a square PNG of at least 256x256, or a
|
|
9
|
+
# folder of icon_<size>.png. Omit to use the SDK default icon.
|
|
10
|
+
# icon: assets/icon.png
|
|
11
|
+
maintainer: Your Name
|
|
12
|
+
# Optional INFO/website metadata. Omit fields you do not need.
|
|
13
|
+
# metadata:
|
|
14
|
+
# contact_email: you@example.com
|
|
15
|
+
# support_email: support@example.com
|
|
16
|
+
# homepage: https://example.com
|
|
17
|
+
# source_url: https://github.com/you/your-app
|
|
18
|
+
# issues_url: https://github.com/you/your-app/issues
|
|
19
|
+
# license: MIT
|
|
20
|
+
# long_description:
|
|
21
|
+
# en: |-
|
|
22
|
+
# Explain what the app does and how to use it.
|
|
23
|
+
# zh-TW: Translated description.
|
|
24
|
+
# changelog: # text, or per-language like long_description
|
|
25
|
+
# en: |-
|
|
26
|
+
# - Most important change first. Omit to use Release notes.
|
|
27
|
+
# zh-TW: |-
|
|
28
|
+
# - Translated changes.
|
|
29
|
+
# screenshots: [https://example.com/screenshot.png]
|
|
30
|
+
os_min_ver: "7.1-42661"
|
|
31
|
+
# One SPK per architecture. For armv7, add it here and a static 32-bit ARM file
|
|
32
|
+
# under files (e.g. CGO_ENABLED=0 GOARCH=arm GOARM=7 go build).
|
|
33
|
+
arches: [x86_64, aarch64]
|
|
34
|
+
backend:
|
|
35
|
+
kind: binary
|
|
36
|
+
files:
|
|
37
|
+
x86_64: prebuilt/api-x86_64
|
|
38
|
+
aarch64: prebuilt/api-aarch64
|
|
39
|
+
ui: {dir: ui}
|
|
40
|
+
# UI languages: i18n/messages/<locale>.json for en, zh-TW, zh-CN, ja, ko, de,
|
|
41
|
+
# fr, es and it (DSM's other languages fall back to English); ctx.t(key) reads them.
|
|
42
|
+
i18n:
|
|
43
|
+
messages: i18n/messages
|
|
44
|
+
# init compiles example/main.go for convenience. Replace prebuilt/api-* with
|
|
45
|
+
# your application's static Linux ELF files; the CGI owns authentication.
|
|
46
|
+
# daemon may optionally declare a separately packaged foreground service.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The starter CGI is compiled once by init. Production binary apps supply their
|
|
2
|
+
// own static Linux executables and must authenticate their application routes.
|
|
3
|
+
package main
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
"encoding/json"
|
|
7
|
+
"net/http"
|
|
8
|
+
"net/http/cgi"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
func main() {
|
|
12
|
+
_ = cgi.Serve(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
13
|
+
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
14
|
+
_ = json.NewEncoder(w).Encode(map[string]string{"status": "ready", "backend": "binary"})
|
|
15
|
+
}))
|
|
16
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
"use strict";
|
|
3
|
+
window.DsmPackageApps = window.DsmPackageApps || {};
|
|
4
|
+
window.DsmPackageApps["__PACKAGE__"] = {
|
|
5
|
+
// ctx.t(key) returns text from i18n/messages/<locale>.json in DSM's language.
|
|
6
|
+
// ctx.portal exists only with `portal:` in dsm-package.yaml; its panel
|
|
7
|
+
// shows the DSM Application Portal link, or the alias form to administrators.
|
|
8
|
+
mount(root, ctx) {
|
|
9
|
+
const app = document.createElement("main");
|
|
10
|
+
app.className = "binary-app";
|
|
11
|
+
const title = document.createElement("h1");
|
|
12
|
+
title.textContent = ctx.t("app.title");
|
|
13
|
+
const description = document.createElement("p");
|
|
14
|
+
description.textContent = ctx.t("app.description");
|
|
15
|
+
app.append(title, description);
|
|
16
|
+
let portalPanel = null;
|
|
17
|
+
if (ctx.portal) {
|
|
18
|
+
const portal = document.createElement("section");
|
|
19
|
+
portal.setAttribute("class", "dsmapp-portal");
|
|
20
|
+
app.append(portal);
|
|
21
|
+
portalPanel = ctx.portal.mountPanel(portal);
|
|
22
|
+
}
|
|
23
|
+
root.append(app);
|
|
24
|
+
return {
|
|
25
|
+
unmount() {
|
|
26
|
+
if (portalPanel) portalPanel.dispose();
|
|
27
|
+
app.remove();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
})();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
services:
|
|
2
|
+
worker:
|
|
3
|
+
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
|
|
4
|
+
command: ["sleep", "infinity"]
|
|
5
|
+
volumes:
|
|
6
|
+
# intentionally outside the zero-config docker-project resource-worker path.
|
|
7
|
+
- "${MEDIA_SHARE}/data:/data:ro"
|
|
8
|
+
- "${SYNOPKG_PKGVAR}/state:/state"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
schema: 1
|
|
2
|
+
package: com.synology.hello.files
|
|
3
|
+
version: 0.1.0
|
|
4
|
+
displayname: Hello Files
|
|
5
|
+
description: A minimal headless app with a Shared Folder mount.
|
|
6
|
+
# Package Center and DSM window icon: a square PNG of at least 256x256, or a
|
|
7
|
+
# folder of icon_<size>.png. Omit to use the SDK default icon.
|
|
8
|
+
# icon: assets/icon.png
|
|
9
|
+
maintainer: Syno Package Land
|
|
10
|
+
os_min_ver: "7.2.1-69057"
|
|
11
|
+
|
|
12
|
+
install:
|
|
13
|
+
MEDIA_SHARE:
|
|
14
|
+
type: shared_folder
|
|
15
|
+
RUN_AS:
|
|
16
|
+
type: dsm_user
|