@synopackageland/templates 0.42.1 → 0.43.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +30 -16
  3. package/package.json +2 -2
  4. package/templates/_shared/AGENTS.md +8 -2
  5. package/templates/_shared/package.json +1 -1
  6. package/templates/_shared/pnpm-workspace.yaml +1 -0
  7. package/templates/compose/dsm-package.yaml +1 -1
  8. package/templates/native-go/README.md +7 -1
  9. package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +1 -1
  10. package/templates/native-go/backend/go.mod +1 -1
  11. package/templates/native-go/backend/go.sum +2 -2
  12. package/templates/native-go/i18n/glossary.json +4 -4
  13. package/templates/native-go/i18n/messages/de.json +1 -1
  14. package/templates/native-go/i18n/messages/en.json +1 -1
  15. package/templates/native-go/i18n/messages/es.json +1 -1
  16. package/templates/native-go/i18n/messages/fr.json +1 -1
  17. package/templates/native-go/i18n/messages/it.json +1 -1
  18. package/templates/native-go/i18n/messages/ja.json +1 -1
  19. package/templates/native-go/i18n/messages/ko.json +1 -1
  20. package/templates/native-go/i18n/messages/zh-CN.json +1 -1
  21. package/templates/native-go/i18n/messages/zh-TW.json +1 -1
  22. package/templates/native-go/ui/app.css +2 -1
  23. package/templates/native-go/ui/app.js +8 -4
  24. package/templates/native-node/README.md +1 -1
  25. package/templates/native-node/dsm-package.yaml +1 -1
  26. package/templates/native-python/dsm-package.yaml +1 -1
  27. package/templates/native-rust/README.md +3 -0
  28. package/templates/native-rust/backend/Cargo.lock +8 -8
  29. package/templates/native-rust/backend/Cargo.toml +1 -1
  30. package/templates/{native-go-delegate → overlays/native-go-delegate}/frontend/test/capability-panels.test.ts +6 -3
  31. package/templates/overlays/native-go-jobs/frontend/test/background-shell.test.ts +37 -0
  32. package/templates/{native-go-vue → overlays/native-go-vue}/README.md +16 -6
  33. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/DESIGN.md +7 -3
  34. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/package.json +2 -2
  35. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/App.vue +7 -4
  36. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/de.json +4 -7
  37. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/en.json +4 -7
  38. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/es.json +4 -7
  39. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/fr.json +4 -7
  40. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/it.json +4 -7
  41. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/ja.json +4 -7
  42. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/ko.json +4 -7
  43. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/zh-CN.json +4 -7
  44. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/zh-TW.json +4 -7
  45. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/apps.test.ts +49 -7
  46. package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/shell-i18n.test.ts +6 -4
  47. package/templates/{native-node-vue → overlays/native-node-vue}/README.md +12 -4
  48. package/templates/{native-python-vue → overlays/native-python-vue}/README.md +12 -4
  49. package/templates/{native-rust-delegate → overlays/native-rust-delegate}/backend/Cargo.lock +8 -8
  50. package/templates/{native-rust-delegate → overlays/native-rust-delegate}/backend/Cargo.toml +1 -1
  51. package/templates/{native-rust-vue → overlays/native-rust-vue}/README.md +12 -4
  52. package/templates/_shared/pnpm-lock.yaml +0 -1636
  53. package/templates/native-go-jobs/frontend/test/background-shell.test.ts +0 -19
  54. package/templates/native-go-vue/frontend/pnpm-lock.yaml +0 -2269
  55. package/templates/native-node/backend/pnpm-lock.yaml +0 -207
  56. /package/templates/{native-go-delegate → overlays/native-go-delegate}/backend/cmd/background-worker/main.go +0 -0
  57. /package/templates/{native-go-delegate → overlays/native-go-delegate}/backend/internal/app/delegate.go +0 -0
  58. /package/templates/{native-go-delegate → overlays/native-go-delegate}/backend/internal/app/delegate_on.go +0 -0
  59. /package/templates/{native-go-delegate → overlays/native-go-delegate}/backend/internal/app/delegate_routes_test.go +0 -0
  60. /package/templates/{native-go-delegate → overlays/native-go-delegate}/frontend/src/CapabilityPanels.vue +0 -0
  61. /package/templates/{native-go-jobs → overlays/native-go-jobs}/backend/internal/app/background_on.go +0 -0
  62. /package/templates/{native-go-jobs → overlays/native-go-jobs}/backend/internal/app/background_routes_test.go +0 -0
  63. /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/backend/internal/app/executor.go +0 -0
  64. /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/backend/internal/app/executor_test.go +0 -0
  65. /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/frontend/src/ExecutorGate.vue +0 -0
  66. /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/frontend/test/executor-gate.test.ts +0 -0
  67. /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/root/whoami.sh +0 -0
  68. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/pnpm-workspace.yaml +0 -0
  69. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/CapabilityPanels.vue +0 -0
  70. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/ExecutorGate.vue +0 -0
  71. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n.ts +0 -0
  72. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/main.ts +0 -0
  73. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/style.css +0 -0
  74. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/context.ts +0 -0
  75. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/module-bundle.test.ts +0 -0
  76. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/native-controls.test.ts +0 -0
  77. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/page-spacing.test.ts +0 -0
  78. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/tsconfig.json +0 -0
  79. /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/vite.config.ts +0 -0
  80. /package/templates/{native-go-vue → overlays/native-go-vue}/gitignore +0 -0
  81. /package/templates/{native-node-delegate → overlays/native-node-delegate}/backend/src/delegate.ts +0 -0
  82. /package/templates/{native-node-delegate → overlays/native-node-delegate}/backend/test/delegate.test.ts +0 -0
  83. /package/templates/{native-node-delegate → overlays/native-node-delegate}/operations.patch.json +0 -0
  84. /package/templates/{native-node-jobs → overlays/native-node-jobs}/backend/src/jobs.ts +0 -0
  85. /package/templates/{native-node-jobs → overlays/native-node-jobs}/backend/test/jobs.test.ts +0 -0
  86. /package/templates/{native-node-jobs → overlays/native-node-jobs}/operations.patch.json +0 -0
  87. /package/templates/{native-node-root-ops → overlays/native-node-root-ops}/backend/src/root-ops.ts +0 -0
  88. /package/templates/{native-node-root-ops → overlays/native-node-root-ops}/backend/test/root-ops.test.ts +0 -0
  89. /package/templates/{native-node-root-ops → overlays/native-node-root-ops}/operations.patch.json +0 -0
  90. /package/templates/{native-node-vue → overlays/native-node-vue}/gitignore +0 -0
  91. /package/templates/{native-python-delegate → overlays/native-python-delegate}/backend/app/delegate.py +0 -0
  92. /package/templates/{native-python-delegate → overlays/native-python-delegate}/backend/tests/test_delegate.py +0 -0
  93. /package/templates/{native-python-delegate → overlays/native-python-delegate}/operations.patch.json +0 -0
  94. /package/templates/{native-python-jobs → overlays/native-python-jobs}/backend/app/jobs.py +0 -0
  95. /package/templates/{native-python-jobs → overlays/native-python-jobs}/backend/tests/test_jobs.py +0 -0
  96. /package/templates/{native-python-jobs → overlays/native-python-jobs}/operations.patch.json +0 -0
  97. /package/templates/{native-python-root-ops → overlays/native-python-root-ops}/backend/app/root_ops.py +0 -0
  98. /package/templates/{native-python-root-ops → overlays/native-python-root-ops}/backend/tests/test_root_ops.py +0 -0
  99. /package/templates/{native-python-root-ops → overlays/native-python-root-ops}/operations.patch.json +0 -0
  100. /package/templates/{native-python-vue → overlays/native-python-vue}/gitignore +0 -0
  101. /package/templates/{native-rust-delegate → overlays/native-rust-delegate}/backend/src/delegate.rs +0 -0
  102. /package/templates/{native-rust-delegate → overlays/native-rust-delegate}/operations.patch.json +0 -0
  103. /package/templates/{native-rust-jobs → overlays/native-rust-jobs}/backend/src/jobs.rs +0 -0
  104. /package/templates/{native-rust-jobs → overlays/native-rust-jobs}/operations.patch.json +0 -0
  105. /package/templates/{native-rust-root-ops → overlays/native-rust-root-ops}/backend/src/root_ops.rs +0 -0
  106. /package/templates/{native-rust-root-ops → overlays/native-rust-root-ops}/operations.patch.json +0 -0
  107. /package/templates/{native-rust-vue → overlays/native-rust-vue}/gitignore +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.43.0
4
+
5
+ - Move Vue and capability layers under `templates/overlays/`; keep six main templates.
6
+ - Let init resolve compatible SDK/UI releases and its own CLI version from shipped defaults.
7
+ - Refresh offline defaults and remove shipped npm lockfiles; first install creates them.
8
+ - Preserve release checksums and document Go/Rust dependency initialization.
9
+
10
+ ## 0.42.2
11
+
12
+ - New Apps get no header Refresh. The Vue templates leave `AppShell`'s `#actions` empty (Sign out only with standalone login), so the shell draws no bar above the page; the plain UI's title row drops its Refresh button
13
+ - Data stays fresh without it: reopening the window reads the status, panels and portal again, the Vue status page reads again each time it is shown, and a failed read offers Retry beside its error
14
+ - Delegate templates keep their Retry inside the capability's own error Callout
15
+ - READMEs, `DESIGN.md` and `AGENTS.md` say `#actions` is for real page actions (such as Add), never a Refresh
16
+ - Drop the unused `refresh`, `greeting`, `save` and `saved` messages; error texts no longer ask the user to refresh
17
+
3
18
  ## 0.42.1
4
19
 
5
20
  - The commented `backup` example in the native and binary `dsm-package.yaml` says online backup reads SQLite in place, and shows the optional `exclude` list of data-folder globs left out of the archive (SDK 0.53.35, CLI 0.53.13)
package/README.md CHANGED
@@ -24,7 +24,7 @@ daemon:
24
24
  window_seconds: 300
25
25
  ```
26
26
 
27
- Templates pin compatible UI and SDK releases in native and Compose projects.
27
+ Templates carry offline fallback dependency versions; init resolves compatible current releases.
28
28
  Use a CLI that supports executor manifest format 1. The Vue `AppShell` shows a
29
29
  non-blocking **Reload** notice when an upgrade replaced the UI an open page
30
30
  loaded. Go Apps select
@@ -50,15 +50,20 @@ An opt-in [native UI plus DSM console example](examples/dual-entry-console/READM
50
50
  shows the `console` declaration for an App that wraps a web service behind the
51
51
  identity gateway and keeps its own settings in an administrator-only DSM window.
52
52
 
53
- | Template | What it adds |
53
+ The first level of `templates/` contains the six main templates, `_shared/`,
54
+ and `overlays/`. All Vue, jobs, delegate and root-ops layers live under `overlays/`.
55
+ The shipped manifest versions are fallback defaults; init rewrites them through its
56
+ existing substitution pass. SDK/UI/CLI patches do not require a templates release.
57
+
58
+ | Template or overlay | What it adds |
54
59
  | --- | --- |
55
60
  | `native-go` | Base: `dsm-package.yaml`, Go module (`backend/cmd/{app,background-worker}`, `backend/internal/app`, `backend/internal/api/permissions.json`), plain `ui/`, i18n |
56
- | `native-go-vue` | Vue shell in `frontend/` (`App.vue`, `main.ts`, app i18n, `CapabilityPanels.vue`, `ExecutorGate.vue`) |
57
- | `native-go-jobs` | Background job routes in `internal/app` and a shell lifecycle test |
58
- | `native-go-delegate` | Delegate routes, the delegate background worker, the delegate `CapabilityPanels.vue` |
59
- | `native-go-root-ops` | The SDK's executor routes and `root.run` in `internal/app`, an example `root/whoami.sh`, and the Vue `ExecutorGate.vue` that holds the pages until the executor is approved |
61
+ | `overlays/native-go-vue` | Vue shell in `frontend/` (`App.vue`, `main.ts`, app i18n, `CapabilityPanels.vue`, `ExecutorGate.vue`) |
62
+ | `overlays/native-go-jobs` | Background job routes in `internal/app` and a shell lifecycle test |
63
+ | `overlays/native-go-delegate` | Delegate routes, the delegate background worker, the delegate `CapabilityPanels.vue` |
64
+ | `overlays/native-go-root-ops` | The SDK's executor routes and `root.run` in `internal/app`, an example `root/whoami.sh`, and the Vue `ExecutorGate.vue` that holds the pages until the executor is approved |
60
65
  | `native-python` | Base: `dsm-package.yaml` (`backend.runtime: python`), the App in `backend/app` (`routes.py`, stub capability modules, `permissions.json`), unittest tests |
61
- | `native-node` | Base: `dsm-package.yaml` (`backend.runtime: node`), TypeScript in `backend/src` compiled into `backend/app`, node:test tests, `pnpm-lock.yaml` |
66
+ | `native-node` | Base: `dsm-package.yaml` (`backend.runtime: node`), TypeScript in `backend/src` compiled into `backend/app`, node:test tests, an install-generated lockfile |
62
67
  | `native-rust` | Base: `dsm-package.yaml` (`backend.runtime: rust`, `methods`), the Cargo project in `backend` on the `syno-pkg-land-app` crate, `Cargo.lock`, `rust-toolchain.toml` |
63
68
  | `native-{python,node,rust}-{jobs,root-ops,delegate}` | The capability's example module, replacing the base's stub, with its tests |
64
69
  | `native-{python,node,rust}-vue` | The README and `.gitignore` of the Vue shell |
@@ -70,8 +75,8 @@ Overlays are copied over `native-go` in the order root-ops, vue, jobs, delegate.
70
75
  An overlay may replace `internal/app/*_none.go` (the CLI deletes the matching
71
76
  `_none.go` file); nothing outside `internal/app` and the Vue shell differs.
72
77
  The Python, Node.js and Rust templates borrow the Go template's UI: `ui/` and
73
- `i18n/` from `native-go`, `frontend/` from `native-go-vue` (and the jobs and
74
- delegate overlays' frontend files), `root/whoami.sh` from `native-go-root-ops`.
78
+ `i18n/` from `native-go`, `frontend/` from `overlays/native-go-vue` (and the jobs and
79
+ delegate overlays' frontend files), `root/whoami.sh` from `overlays/native-go-root-ops`.
75
80
  Their overlays are copied in the order vue, root-ops, jobs, delegate; delegate
76
81
  also makes `app.status` and `report.save` `authenticated`, and the Rust
77
82
  manifest gets the overlays' methods. `init` copies the App SDK into
@@ -84,13 +89,22 @@ calls each one from the generated script of the same name (`synopkgland skill sh
84
89
  The placeholders `__PACKAGE__` (also the Go module path), `__DISPLAY_NAME__` and
85
90
  `__BACKGROUND_ENABLED__` are substituted by `init`.
86
91
 
87
- `backend/go.mod` requires `github.com/synopackageland/syno-pkg-land-sdk`; that line is
88
- the single source of the SDK version and `frontend/package.json` sets
89
- `@synopackageland/sdk` to a patch range starting at the same version. Python and Node.js name it in
90
- `backend.sdk`, Rust in the `syno-pkg-land-app` tag of `backend/Cargo.toml`
91
- (and `Cargo.lock`). The Vue frontend uses a compatible patch range for
92
- `@synopackageland/ui`. The shipped lockfile fixes both installed versions;
93
- update it deliberately to take newer patches.
92
+ `init` defaults to `native-go` with Vue. The CLI writes its own `~` version,
93
+ selects the newest stable, non-deprecated SDK and UI releases in its declared
94
+ compatibility ranges, and writes the same exact SDK version to npm and the backend.
95
+ UI stays in the supported minor line. Registry errors or unavailable compatible
96
+ releases print one hint and use the shipped defaults; there is no short custom timeout.
97
+ Templates are still read from the installed package, never downloaded by `init`.
98
+ The CLI compatibility ranges live in `src/init-versions.ts`.
99
+
100
+ Templates do not ship npm lockfiles. Run `pnpm install` in the project root and
101
+ frontend (and the Node backend) to create them, then commit them and use
102
+ `pnpm install --frozen-lockfile` for subsequent installs. For Go, run
103
+ `(cd backend && go mod tidy)` before check/build. When init selects a newer Rust
104
+ SDK tag, run `(cd backend && cargo generate-lockfile)` before check/build;
105
+ the old release's Cargo.lock is removed rather than relabeling its commit.
106
+ `SYNOPKGLAND_SDK_DIR` still overrides the generated SDK dependency for local development.
107
+
94
108
  Read the SDK's published peer dependency range with
95
109
  `npm view @synopackageland/sdk peerDependencies` rather than overriding it. Tests use jsdom 30 for UI floating-layer styles.
96
110
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@synopackageland/templates",
3
- "version": "0.42.1",
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.",
3
+ "version": "0.43.0",
4
+ "description": "Project templates for synopkgland init: native-go, native-python, native-node and native-rust (plain or Vue, with layers in templates/overlays), binary and compose.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -17,12 +17,18 @@ Only a confirmed refusal (signed out, expired session, not an administrator)
17
17
  shows the sign-in page or a `@synopackageland/ui` Dialog; loading text inside a
18
18
  section is fine.
19
19
 
20
+ Do not add a header Refresh. Re-read data when the window is shown again
21
+ (`ctx.reopen`) and when a page is shown; a failed read offers Retry beside its
22
+ error. `AppShell`'s `#actions` is for real page actions (such as Add); with
23
+ nothing in it the shell draws no bar. A section that needs a manual re-read
24
+ gets its own action in that section.
25
+
20
26
  Everything below holds for every native backend language; the backend
21
27
  sections at the end name each language's files, types and test commands.
22
28
 
23
29
  From the project root, run `synopkgland check --json`,
24
30
  `synopkgland build --json`, then `synopkgland inspect <spk> --json` on the emitted SPK.
25
- For Vue, first run `pnpm install --frozen-lockfile --prod=false` and `pnpm run build` in frontend. Run its tests only if the user chose tests.
31
+ For Vue, first run `pnpm install --prod=false` (creates its lockfile) and `pnpm run build` in frontend. Run its tests only if the user chose tests.
26
32
  Do not connect to or change a NAS without explicit task authorization.
27
33
 
28
34
  ## Optional testing
@@ -402,7 +408,7 @@ their capabilities with `synopkgland init --with`.
402
408
  `new AppError(code, message)`, `AppError.badRequest(message)`. Call services
403
409
  through `service(ctx, op, params)` (`service.ts`), which passes the runtime's
404
410
  refusals on; a bare `ctx.runtime` refusal would reach the browser as `internal`.
405
- - Test with `(cd backend && pnpm install --frozen-lockfile --prod=false && pnpm test && pnpm run typecheck)`; `test/support.ts`'s
411
+ - Test with `(cd backend && pnpm install --prod=false && pnpm test && pnpm run typecheck)`; `test/support.ts`'s
406
412
  `call` plays the runtime.
407
413
 
408
414
  ## Rust backend
@@ -11,7 +11,7 @@
11
11
  "e2e:ai": "node --env-file-if-exists=.env node_modules/@synopackageland/cli/dist/e2e/dsm.js tunnel -- e2e run --config e2e.ai.config.ts tests/e2e/action.ai.e2e.ts"
12
12
  },
13
13
  "devDependencies": {
14
- "@synopackageland/cli": "~0.52.11",
14
+ "@synopackageland/cli": "~0.53.18",
15
15
  "@e2e-dev/web": "^0.14.0",
16
16
  "e2e": "^0.19.0"
17
17
  },
@@ -1,2 +1,3 @@
1
1
  allowBuilds:
2
2
  esbuild: true
3
+ koffi: true
@@ -23,7 +23,7 @@ compose:
23
23
  web: {service: web, port: 8080, health: {path: /, status: 200}}
24
24
  network: {egress: isolated}
25
25
  identity_gateway:
26
- sdk: 0.53.16
26
+ sdk: 0.53.42
27
27
  mode: none
28
28
  listen: {http: 28000}
29
29
  # Web Apps default to new-page through the shared app-launch resolver.
@@ -205,7 +205,10 @@ the new version; `synopkgland check` refuses mismatched versions.
205
205
  `ui/app.js` must register `window.DsmPackageApps[<package>].mount(root, ctx)`
206
206
  (the template shows how, using `document.currentScript.dataset.package`).
207
207
  `ctx.call(method, params)` is the only transport. `ctx.reopen(fn)` runs `fn`
208
- whenever DSM shows the window again and returns an idempotent unsubscribe function. Scope your CSS under your own root class:
208
+ whenever DSM shows the window again and returns an idempotent unsubscribe function.
209
+ The template re-reads its status there instead of showing a Refresh button; a
210
+ failed read shows Retry beside its error. Keep header buttons for real page
211
+ actions, such as Add. Scope your CSS under your own root class:
209
212
  every DSM app shares one page.
210
213
 
211
214
  Plain JS and Vue receive the same `ctx.host` adapter. `ctx.host.platform()`
@@ -495,3 +498,6 @@ Keep `synology/backend/`, `synology/i18n/messages/`, `synology/operations.json`
495
498
  the local/ctl tests: the entry gate still needs the backend and message catalogs.
496
499
  Read `synopkgland skill show upstream-fork` and
497
500
  `synopkgland skill show orchestrator` for the wrapper workflow.
501
+
502
+ Before the first check/build, install the project dependencies with `pnpm install`
503
+ and run `(cd backend && go mod tidy)` to populate checksums for the selected SDK.
@@ -1,6 +1,6 @@
1
1
  Native Go package build dependencies
2
2
 
3
- github.com/synopackageland/syno-pkg-land-sdk v0.53.16 (MIT)
3
+ github.com/synopackageland/syno-pkg-land-sdk v0.53.42 (MIT)
4
4
 
5
5
  Copyright (c) 2026 synopkgland
6
6
 
@@ -2,6 +2,6 @@ module __PACKAGE__
2
2
 
3
3
  go 1.26.10
4
4
 
5
- require github.com/synopackageland/syno-pkg-land-sdk v0.53.16
5
+ require github.com/synopackageland/syno-pkg-land-sdk v0.53.42
6
6
 
7
7
  require golang.org/x/sys v0.44.0 // indirect
@@ -1,4 +1,4 @@
1
- github.com/synopackageland/syno-pkg-land-sdk v0.53.16 h1:i4FCBCpOr7ma31zFathuS2QLpCWa13y3v9rWvlg+AfE=
2
- github.com/synopackageland/syno-pkg-land-sdk v0.53.16/go.mod h1:JMfenGwAhlVgGUtoSQFA9XRbtN8Zcs+0xdrOaaam+Fg=
1
+ github.com/synopackageland/syno-pkg-land-sdk v0.53.42 h1:qhbKCjU6ME8OpuMgpz03LHs3KGL66xSwDRvePGWlyEU=
2
+ github.com/synopackageland/syno-pkg-land-sdk v0.53.42/go.mod h1:mmtgnyafLwci1588LJFpRIsWflHwjaHJoDm7grXFh8A=
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=
@@ -163,9 +163,7 @@
163
163
  "es": "Actualizar",
164
164
  "it": "Aggiorna"
165
165
  },
166
- "keys": [
167
- "app.refresh"
168
- ]
166
+ "keys": []
169
167
  },
170
168
  {
171
169
  "id": "retry",
@@ -181,7 +179,9 @@
181
179
  "es": "Volver a intentar",
182
180
  "it": "Riprova"
183
181
  },
184
- "keys": []
182
+ "keys": [
183
+ "app.retry"
184
+ ]
185
185
  },
186
186
  {
187
187
  "id": "back",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "Aktualisieren",
2
+ "app.retry": "Neuer Versuch",
3
3
  "app.title": "Es funktioniert",
4
4
  "error.admin_required": "Dieses Benutzerkonto verfügt nicht über die erforderlichen Berechtigungen, um diese Aktion durchzuführen",
5
5
  "error.app_privilege_denied": "Dieses Benutzerkonto verfügt nicht über die erforderlichen Berechtigungen, um diese Aktion durchzuführen",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "Refresh",
2
+ "app.retry": "Retry",
3
3
  "app.title": "It works",
4
4
  "error.admin_required": "Sorry, this user account has not been assigned proper privileges to perform this action",
5
5
  "error.app_privilege_denied": "Sorry, this user account has not been assigned proper privileges to perform this action",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "Actualizar",
2
+ "app.retry": "Volver a intentar",
3
3
  "app.title": "Funciona",
4
4
  "error.admin_required": "A esta cuenta de usuario no se le han asignado los privilegios adecuados para realizar esta acción",
5
5
  "error.app_privilege_denied": "A esta cuenta de usuario no se le han asignado los privilegios adecuados para realizar esta acción",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "Actualiser",
2
+ "app.retry": "Réessayer",
3
3
  "app.title": "Ça fonctionne",
4
4
  "error.admin_required": "Désolé, ce compte utilisateur ne dispose pas des droits nécessaires pour accomplir cette action",
5
5
  "error.app_privilege_denied": "Désolé, ce compte utilisateur ne dispose pas des droits nécessaires pour accomplir cette action",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "Aggiorna",
2
+ "app.retry": "Riprova",
3
3
  "app.title": "Funziona",
4
4
  "error.admin_required": "Siamo spiacenti, a questo account utente non sono stati assegnati privilegi appropriati per eseguire questa azione",
5
5
  "error.app_privilege_denied": "Siamo spiacenti, a questo account utente non sono stati assegnati privilegi appropriati per eseguire questa azione",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "最新の情報に更新",
2
+ "app.retry": "再試行",
3
3
  "app.title": "動作しています",
4
4
  "error.admin_required": "申し訳ありませんが、このユーザー アカウントにはこの操作を行うための権限が与えられていません",
5
5
  "error.app_privilege_denied": "申し訳ありませんが、このユーザー アカウントにはこの操作を行うための権限が与えられていません",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "새로 고침",
2
+ "app.retry": "재시도",
3
3
  "app.title": "정상적으로 작동합니다",
4
4
  "error.admin_required": "죄송합니다. 이 사용자 계정에는 이 작업을 수행하기에 적절한 권한이 할당되지 않았습니다",
5
5
  "error.app_privilege_denied": "죄송합니다. 이 사용자 계정에는 이 작업을 수행하기에 적절한 권한이 할당되지 않았습니다",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "刷新",
2
+ "app.retry": "重试",
3
3
  "app.title": "运行成功",
4
4
  "error.admin_required": "抱歉,此用户帐户权限不足,无法执行此操作",
5
5
  "error.app_privilege_denied": "抱歉,此用户帐户权限不足,无法执行此操作",
@@ -1,5 +1,5 @@
1
1
  {
2
- "app.refresh": "重新整理",
2
+ "app.retry": "重試",
3
3
  "app.title": "成功運作了",
4
4
  "error.admin_required": "抱歉,此使用者帳號權限不足,無法執行此動作",
5
5
  "error.app_privilege_denied": "抱歉,此使用者帳號權限不足,無法執行此動作",
@@ -34,7 +34,6 @@
34
34
  background: var(--ui-surface);
35
35
  }
36
36
  .dsmapp *, .dsmapp *::before, .dsmapp *::after { box-sizing: inherit; }
37
- .dsmapp-header { display: flex; align-items: center; justify-content: space-between; gap: var(--ui-space-3); }
38
37
  .dsmapp h1 { margin: 0 0 var(--ui-space-1); font-size: var(--ui-font-size-title); font-weight: 600; }
39
38
  .dsmapp-secondary {
40
39
  height: var(--ui-control-md); padding: 0 var(--ui-space-3); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm);
@@ -55,6 +54,8 @@
55
54
  .dsmapp-form button:disabled { opacity: 0.6; cursor: default; }
56
55
  .dsmapp-note { margin: 0; color: var(--ui-text-secondary); font-size: var(--ui-font-size-sm); }
57
56
  .dsmapp-note[hidden] { display: none; }
57
+ .dsmapp-message-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-3); }
58
+ .dsmapp-message-row .dsmapp-message { flex: 1 1 auto; }
58
59
  .dsmapp-message { min-height: var(--ui-line-height); color: var(--ui-danger-text); }
59
60
  .dsmapp-facts { display: grid; grid-template-columns: fit-content(40%) minmax(0, 1fr); gap: var(--ui-space-1) var(--ui-space-4); margin: 0; }
60
61
  .dsmapp-facts dt { color: var(--ui-text-secondary); }
@@ -36,14 +36,16 @@
36
36
  function mount(root, ctx) {
37
37
  var t = ctx.t;
38
38
  var status = el("dl", { class: "dsmapp-facts" });
39
- var refreshButton = el("button", { type: "button", class: "dsmapp-secondary", text: t("app.refresh") });
40
39
  var message = el("p", { class: "dsmapp-message", role: "status" });
40
+ // Shown only after a failed read; the App re-reads on reopen, so no header Refresh.
41
+ var retryButton = el("button", { type: "button", class: "dsmapp-secondary", text: t("app.retry") });
42
+ retryButton.hidden = true;
41
43
  var portal = ctx.portal ? el("section", { class: "dsmapp-portal" }) : null;
42
44
 
43
45
  root.classList.add("dsmapp");
44
46
  root.replaceChildren(
45
- el("div", { class: "dsmapp-header" }, [el("h1", { text: t("app.title") }), refreshButton]),
46
- message,
47
+ el("h1", { text: t("app.title") }),
48
+ el("div", { class: "dsmapp-message-row" }, [message, retryButton]),
47
49
  el("h2", { text: t("status.heading") }),
48
50
  status
49
51
  );
@@ -54,10 +56,12 @@
54
56
  var code = (error && error.code) || "internal";
55
57
  var text = t("error." + code);
56
58
  message.textContent = text === "error." + code ? (error && error.message) || t("error.internal") : text;
59
+ retryButton.hidden = false;
57
60
  }
58
61
 
59
62
  function refresh() {
60
63
  message.textContent = "";
64
+ retryButton.hidden = true;
61
65
  ctx.call("app.status").then(function (data) {
62
66
  status.replaceChildren();
63
67
  [[t("status.user"), data.admin ? t("status.userAdmin", { user: data.user }) : data.user],
@@ -73,7 +77,7 @@
73
77
  }).catch(showError);
74
78
  }
75
79
 
76
- refreshButton.addEventListener("click", refresh);
80
+ retryButton.addEventListener("click", refresh);
77
81
 
78
82
  ctx.reopen(refresh);
79
83
  refresh();
@@ -51,7 +51,7 @@ run `synopkgland ctl generate`.
51
51
  Needs Node.js 20 or later with `synopkgland` installed. The SPK depends on DSM's **Node.js v20** package (INFO `install_dep_packages`).
52
52
 
53
53
  ```bash
54
- (cd backend && pnpm install --frozen-lockfile --prod=false && pnpm test && pnpm run build) # method tests, then app/*.js
54
+ (cd backend && pnpm install --prod=false && pnpm test && pnpm run build) # method tests, then app/*.js
55
55
  synopkgland ctl generate
56
56
  synopkgland check
57
57
  synopkgland build # → dist/__PACKAGE__-0.1.0-0001-{x86_64,aarch64}.spk
@@ -49,7 +49,7 @@ backend:
49
49
  runtime: node
50
50
  dir: backend/app
51
51
  entry: main.js
52
- sdk: 0.53.16
52
+ sdk: 0.53.42
53
53
  node: { package: Node.js_v22 }
54
54
 
55
55
  ui:
@@ -47,7 +47,7 @@ backend:
47
47
  runtime: python
48
48
  dir: backend/app
49
49
  entry: main.py
50
- sdk: 0.53.16
50
+ sdk: 0.53.42
51
51
 
52
52
  ui:
53
53
  # Non-UI-SDK frontends open a full page; Portal is a separate opt-in.
@@ -225,3 +225,6 @@ Draft writes require a non-mutating preview and explicit human confirmation.
225
225
  Long operations use the existing job flow; tools own polling and pagination.
226
226
 
227
227
  Use a matching SDK/CLI/templates release containing the registry support.
228
+
229
+ After init selects a new SDK tag, run `(cd backend && cargo generate-lockfile)`
230
+ before check/build, then commit the generated Cargo.lock.
@@ -14,15 +14,15 @@ dependencies = [
14
14
 
15
15
  [[package]]
16
16
  name = "itoa"
17
- version = "1.0.18"
17
+ version = "1.0.19"
18
18
  source = "registry+https://github.com/rust-lang/crates.io-index"
19
- checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
19
+ checksum = "3bd1574e617a9a6c1f8f8181bd7e841e1f20e4277607ef28945765188d6284d4"
20
20
 
21
21
  [[package]]
22
22
  name = "libc"
23
- version = "0.2.190"
23
+ version = "0.2.191"
24
24
  source = "registry+https://github.com/rust-lang/crates.io-index"
25
- checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
25
+ checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
26
26
 
27
27
  [[package]]
28
28
  name = "memchr"
@@ -93,9 +93,9 @@ dependencies = [
93
93
 
94
94
  [[package]]
95
95
  name = "syn"
96
- version = "3.0.9"
96
+ version = "3.0.10"
97
97
  source = "registry+https://github.com/rust-lang/crates.io-index"
98
- checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
98
+ checksum = "4ae9ccbea3a7b0b09443036490c8f34a8b1b760fd345e5c0dae0aac718faea79"
99
99
  dependencies = [
100
100
  "proc-macro2",
101
101
  "quote",
@@ -104,8 +104,8 @@ dependencies = [
104
104
 
105
105
  [[package]]
106
106
  name = "syno-pkg-land-app"
107
- version = "0.53.16"
108
- source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.53.16#6751951c140fb032e5f050dc53f5cc58fcd0bf60"
107
+ version = "0.53.42"
108
+ source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.53.42#02d5b526c852b3bd30e4dc9031414c9907fadb57"
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.53.16" }
12
+ syno-pkg-land-app = { git = "https://github.com/synopackageland/syno-pkg-land-sdk", tag = "v0.53.42" }
13
13
 
14
14
  [profile.release]
15
15
  # A handler panic becomes an "internal" reply; abort would end the App without one.
@@ -102,7 +102,8 @@ test('the app mount forwards ctx.executor to administrator setup only',async()=>
102
102
  }
103
103
  }
104
104
  })
105
- test('the header Refresh reloads the save destinations',async()=>{
105
+ // No header Refresh: reopening the App reloads the save destinations.
106
+ test('reopening the App reloads the save destinations',async()=>{
106
107
  const call=vi.fn(async(method:string)=>{
107
108
  if(method==='app.status')return {package:'DelegateApp',version:'1',user:'alice',admin:false}
108
109
  if(method==='delegate.status')return {state:'ready',disabled:false,lifetime:'until-revoked',destinations:['save']}
@@ -112,11 +113,13 @@ test('the header Refresh reloads the save destinations',async()=>{
112
113
  throw {code:'unknown_method'}
113
114
  })
114
115
  const root=document.createElement('div');document.body.append(root)
115
- const app=mount(root,dsmWindow({call}))
116
+ const reopen:Array<()=>void>=[]
117
+ const app=mount(root,dsmWindow({call,reopen(fn:()=>void){reopen.push(fn);return ()=>{}}}))
116
118
  cleanup.push(()=>{app.unmount();root.remove()});await settle()
117
119
  const reads=()=>call.mock.calls.filter(([method])=>method==='delegate.destination').length
118
120
  const before=reads();expect(before).toBeGreaterThan(0)
119
- button(root,'Refresh').click();await settle()
121
+ expect([...root.querySelectorAll('button')].some(n=>n.textContent?.trim()==='Refresh')).toBe(false)
122
+ reopen.forEach(fn=>fn());await settle()
120
123
  expect(reads()).toBeGreaterThan(before)
121
124
  })
122
125
  test('the panels show a skeleton while the delegate status loads',async()=>{
@@ -0,0 +1,37 @@
1
+ // @vitest-environment jsdom
2
+ import {expect,test,vi} from 'vitest'
3
+ import {nextTick} from 'vue'
4
+ import {mount} from '../src/main'
5
+ import {dsmWindow} from './context'
6
+ async function settle(){for(let i=0;i<20;i++){await Promise.resolve();await nextTick()}}
7
+ test('a jobs project opens its shell without starting a job',async()=>{
8
+ const call=vi.fn(async(method:string)=>{
9
+ if(method==='app.status')return {package:'Jobs',version:'1',user:'alice',admin:false}
10
+ throw {code:'unknown_method'}
11
+ })
12
+ const root=document.createElement('div');document.body.append(root)
13
+ const app=mount(root,dsmWindow({call}))
14
+ try{
15
+ await settle()
16
+ expect(root.querySelector('[data-app-status]')).not.toBeNull()
17
+ expect(call.mock.calls.some(([method])=>method.startsWith('bg.'))).toBe(false)
18
+ }finally{app.unmount();root.remove()}
19
+ })
20
+ // No header Refresh: showing the status page again reads its status again.
21
+ test('returning to the status page reads its status again',async()=>{
22
+ const call=vi.fn(async(method:string)=>{
23
+ if(method==='app.status')return {package:'Jobs',version:'1',user:'alice',admin:false}
24
+ throw {code:'unknown_method'}
25
+ })
26
+ const root=document.createElement('div');document.body.append(root)
27
+ const app=mount(root,dsmWindow({call}))
28
+ try{
29
+ await settle()
30
+ const reads=()=>call.mock.calls.filter(([method])=>method==='app.status').length
31
+ const item=(name:string)=>[...root.querySelectorAll<HTMLElement>('button')].find(n=>n.textContent?.trim()===name)!
32
+ item('Background jobs').click();await settle()
33
+ const before=reads()
34
+ item('Status').click();await settle()
35
+ expect(reads()).toBeGreaterThan(before)
36
+ }finally{app.unmount();root.remove()}
37
+ })
@@ -37,13 +37,12 @@ See the [fork guide](https://github.com/synopackageland/syno-pkg-land-templates#
37
37
 
38
38
  ```sh
39
39
  cd frontend
40
- pnpm install --frozen-lockfile --prod=false
40
+ pnpm install --prod=false
41
41
  pnpm test
42
42
  pnpm run build
43
43
  ```
44
44
 
45
- The base app reads package status and edits the package greeting through
46
- `ctx.call`. Each window has its own Vue mount, request state and host
45
+ The base app reads package status through `ctx.call`. Each window has its own Vue mount, request state and host
47
46
  subscriptions; unmount disposes subscriptions and ignores late responses.
48
47
 
49
48
  The build emits `app.module.js`, `app.css` and any lazy chunks. The entry
@@ -94,7 +93,7 @@ SDK's light default in place.
94
93
 
95
94
  Use the installed `@synopackageland/ui` and its declared compatible patch range.
96
95
  `App.vue` lays the shell out with the SDK's `AppShell` (`@synopackageland/sdk/vue`):
97
- `pages` from `shellPages`, the page's buttons in `#actions` and the pages in its
96
+ `pages` from `shellPages`, real page actions in `#actions` and the pages in its
98
97
  default slot. On desktop, the sidebar names the page: the shell shows no page title, puts
99
98
  `#actions` in a bar above the page and scrolls only the content; a settings
100
99
  page (`SectionTabs fill` or `SettingsPage`) keeps its tabs and footer in place
@@ -109,6 +108,14 @@ device-width viewport. Its full-page sidebar names the App with
109
108
  shows the signed-in DSM account and its role from `ctx.user`. See the ui's
110
109
  `docs/adaptive-layout.md`.
111
110
 
111
+ The template puts no Refresh in `#actions`, and with nothing there `AppShell`
112
+ draws no bar above the page. Data stays fresh without one: `ctx.reopen` reads
113
+ the status, the panels and the portal again when the window is shown again,
114
+ and showing the status page again reads it again. A failed read offers Retry
115
+ beside its error. Sign out appears in `#actions` only when standalone login is
116
+ on. Keep `#actions` for real page actions, such as Add; a section that needs a
117
+ manual re-read gets its own action in that section, not a header Refresh.
118
+
112
119
  The frontend SDK and UI use patch ranges; the lockfile records the installed
113
120
  versions. Update the lockfile deliberately when taking a newer patch.
114
121
 
@@ -120,8 +127,8 @@ keeps that branding, and the UI hides a bar with nothing in it. When using
120
127
  even with `phone-bar-title="none"`. Pages outside the tab bar and detail pages
121
128
  with Back keep their title bar. `header-actions` share one "…" menu; only an
122
129
  entry marked `primary: true`, or a sole entry with an icon, becomes a separate
123
- bar button. The template's `#actions` stays page actions; no title or empty-bar
124
- workaround is needed.
130
+ bar button. The template's `#actions` holds only real page actions; no title or
131
+ empty-bar workaround is needed.
125
132
 
126
133
  `AppShell`'s `app-root` wraps it in an app-local `AppRoot` (app modal scope, on
127
134
  a full page as well, bounded at `height: 100%`) with the UI locale from
@@ -143,3 +150,6 @@ For UI discovery, run `pnpm exec syno-pkg-land-ui catalog --json` and
143
150
  `pnpm exec syno-pkg-land-ui describe Button --json` from the installed frontend.
144
151
  Read its prompt and exported Vue docs/types before choosing component APIs.
145
152
  Use `syno-pkg-land-ui` directly in package scripts; keep AI guidance version-independent.
153
+
154
+ Before the first check/build, install the project dependencies with `pnpm install`
155
+ and run `(cd backend && go mod tidy)` to populate checksums for the selected SDK.
@@ -30,8 +30,8 @@ Use `syno-pkg-land-ui` directly in package scripts; keep AI guidance version-ind
30
30
  ## Overview
31
31
 
32
32
  The template runs inside a DSM package window. `AppShell` provides status and
33
- optional background navigation. The base page shows package status and a greeting
34
- editor; the root overlay adds its existing fixed-operation authorization gate.
33
+ optional background navigation. The base page shows package status; the root
34
+ overlay adds its existing fixed-operation authorization gate.
35
35
 
36
36
  Use the installed `@synopackageland/ui` controls and `themes/dsm7-embedded.css`.
37
37
  The theme owns colors, typography, spacing and dialogs. Keep per-app modal scope,
@@ -39,7 +39,11 @@ a unique Vue ID prefix and vertical scrolling at the DSM minimum window size.
39
39
  In a DSM window, Dialogs may leave the window (`dialog-bounds="viewport"`) and a
40
40
  press on one brings the window to the front; below 600px they are bottom sheets.
41
41
 
42
- Refresh and save expose busy state and localized errors. Reopen refreshes status.
42
+ There is no header Refresh: reopening the window, or showing the status page
43
+ again, reads it again, and a failed read offers Retry beside its error. The
44
+ shell's `#actions` holds only real page actions (Sign out with standalone
45
+ login); empty, the shell draws no bar. Reads expose busy state and localized
46
+ errors.
43
47
  Each mount owns its state; unmount unsubscribes from host events and ignores late
44
48
  responses. Backend route policies decide access.
45
49
 
@@ -8,8 +8,8 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@lucide/vue": "1.48.0",
11
- "@synopackageland/sdk": "~0.53.16",
12
- "@synopackageland/ui": "~0.25.2",
11
+ "@synopackageland/sdk": "~0.53.42",
12
+ "@synopackageland/ui": "~0.25.17",
13
13
  "vue": "3.5.43"
14
14
  },
15
15
  "devDependencies": {