@synopackageland/templates 0.9.8 → 0.10.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 (133) hide show
  1. package/README.md +27 -27
  2. package/package.json +2 -2
  3. package/templates/_shared/AGENTS.md +53 -15
  4. package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +1 -1
  5. package/templates/native-go/backend/cmd/app/main.go +15 -1
  6. package/templates/native-go/backend/cmd/app/main_test.go +33 -0
  7. package/templates/native-go/backend/go.mod +1 -1
  8. package/templates/native-go/backend/go.sum +2 -2
  9. package/templates/native-go/i18n/glossary.json +3 -1
  10. package/templates/native-go/i18n/messages/de.json +6 -0
  11. package/templates/native-go/i18n/messages/en.json +6 -0
  12. package/templates/native-go/i18n/messages/es.json +6 -0
  13. package/templates/native-go/i18n/messages/fr.json +6 -0
  14. package/templates/native-go/i18n/messages/it.json +6 -0
  15. package/templates/native-go/i18n/messages/ja.json +6 -0
  16. package/templates/native-go/i18n/messages/ko.json +6 -0
  17. package/templates/native-go/i18n/messages/zh-CN.json +6 -0
  18. package/templates/native-go/i18n/messages/zh-TW.json +6 -0
  19. package/templates/native-go/ui/app.js +2 -1
  20. package/templates/native-go-delegate/frontend/test/capability-panels.test.ts +3 -2
  21. package/templates/native-go-jobs/frontend/test/background-page.test.ts +4 -4
  22. package/templates/native-go-vue/README.md +19 -7
  23. package/templates/native-go-vue/frontend/package-lock.json +9 -9
  24. package/templates/native-go-vue/frontend/package.json +2 -2
  25. package/templates/native-go-vue/frontend/src/App.vue +31 -36
  26. package/templates/native-go-vue/frontend/test/apps.test.ts +65 -12
  27. package/templates/native-go-vue/frontend/test/context.ts +8 -0
  28. package/templates/native-go-vue/frontend/test/native-controls.test.ts +3 -4
  29. package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +2 -2
  30. package/templates/native-node/README.md +153 -0
  31. package/templates/native-node/backend/app/package.json +4 -0
  32. package/templates/native-node/backend/app/permissions.json +5 -0
  33. package/templates/native-node/backend/package-lock.json +59 -0
  34. package/templates/native-node/backend/package.json +17 -0
  35. package/templates/native-node/backend/src/delegate.ts +5 -0
  36. package/templates/native-node/backend/src/jobs.ts +5 -0
  37. package/templates/native-node/backend/src/main.ts +4 -0
  38. package/templates/native-node/backend/src/params.ts +11 -0
  39. package/templates/native-node/backend/src/root-ops.ts +5 -0
  40. package/templates/native-node/backend/src/routes.ts +97 -0
  41. package/templates/native-node/backend/src/service.ts +22 -0
  42. package/templates/native-node/backend/test/routes.test.ts +75 -0
  43. package/templates/native-node/backend/test/support.ts +67 -0
  44. package/templates/native-node/backend/tsconfig.build.json +8 -0
  45. package/templates/native-node/backend/tsconfig.json +18 -0
  46. package/templates/native-node/dsm-package.yaml +80 -0
  47. package/templates/native-node/gitignore +4 -0
  48. package/templates/native-node-delegate/backend/src/delegate.ts +35 -0
  49. package/templates/native-node-delegate/backend/test/delegate.test.ts +51 -0
  50. package/templates/native-node-jobs/backend/src/jobs.ts +38 -0
  51. package/templates/native-node-jobs/backend/test/jobs.test.ts +73 -0
  52. package/templates/native-node-root-ops/backend/src/root-ops.ts +16 -0
  53. package/templates/native-node-root-ops/backend/test/root-ops.test.ts +23 -0
  54. package/templates/native-node-vue/README.md +56 -0
  55. package/templates/native-node-vue/gitignore +4 -0
  56. package/templates/native-python/README.md +150 -0
  57. package/templates/native-python/backend/app/delegate.py +5 -0
  58. package/templates/native-python/backend/app/jobs.py +5 -0
  59. package/templates/native-python/backend/app/main.py +5 -0
  60. package/templates/native-python/backend/app/params.py +10 -0
  61. package/templates/native-python/backend/app/permissions.json +5 -0
  62. package/templates/native-python/backend/app/root_ops.py +5 -0
  63. package/templates/native-python/backend/app/routes.py +107 -0
  64. package/templates/native-python/backend/tests/support.py +72 -0
  65. package/templates/native-python/backend/tests/test_routes.py +73 -0
  66. package/templates/native-python/dsm-package.yaml +77 -0
  67. package/templates/native-python/gitignore +2 -0
  68. package/templates/native-python-delegate/backend/app/delegate.py +42 -0
  69. package/templates/native-python-delegate/backend/tests/test_delegate.py +58 -0
  70. package/templates/native-python-jobs/backend/app/jobs.py +40 -0
  71. package/templates/native-python-jobs/backend/tests/test_jobs.py +72 -0
  72. package/templates/native-python-root-ops/backend/app/root_ops.py +18 -0
  73. package/templates/native-python-root-ops/backend/tests/test_root_ops.py +34 -0
  74. package/templates/native-python-vue/README.md +56 -0
  75. package/templates/native-python-vue/gitignore +3 -0
  76. package/templates/native-rust/README.md +74 -296
  77. package/templates/native-rust/backend/Cargo.lock +6 -6
  78. package/templates/native-rust/backend/Cargo.toml +2 -10
  79. package/templates/native-rust/backend/src/delegate.rs +6 -0
  80. package/templates/native-rust/backend/src/jobs.rs +6 -0
  81. package/templates/native-rust/backend/src/main.rs +12 -0
  82. package/templates/native-rust/backend/src/root_ops.rs +6 -0
  83. package/templates/native-rust/backend/src/routes.rs +352 -0
  84. package/templates/native-rust/backend/src/test_support.rs +91 -0
  85. package/templates/native-rust/dsm-package.yaml +10 -21
  86. package/templates/native-rust-delegate/backend/src/delegate.rs +171 -0
  87. package/templates/native-rust-jobs/backend/src/jobs.rs +240 -0
  88. package/templates/native-rust-root-ops/backend/src/root_ops.rs +83 -0
  89. package/templates/native-rust-vue/README.md +35 -34
  90. package/templates/native-rust/backend/THIRD_PARTY_NOTICES.txt +0 -207
  91. package/templates/native-rust/backend/src/app/background/mod.rs +0 -424
  92. package/templates/native-rust/backend/src/app/background/owner.rs +0 -77
  93. package/templates/native-rust/backend/src/app/background/owner_tests.rs +0 -174
  94. package/templates/native-rust/backend/src/app/background/schedule.rs +0 -126
  95. package/templates/native-rust/backend/src/app/background/schedule_tests.rs +0 -108
  96. package/templates/native-rust/backend/src/app/background/tests.rs +0 -505
  97. package/templates/native-rust/backend/src/app/background/work.rs +0 -78
  98. package/templates/native-rust/backend/src/app/background/work_tests.rs +0 -123
  99. package/templates/native-rust/backend/src/app/background_routes.rs +0 -22
  100. package/templates/native-rust/backend/src/app/delegate_config.rs +0 -188
  101. package/templates/native-rust/backend/src/app/delegate_routes.rs +0 -22
  102. package/templates/native-rust/backend/src/app/identity.rs +0 -56
  103. package/templates/native-rust/backend/src/app/migrations.rs +0 -79
  104. package/templates/native-rust/backend/src/app/mod.rs +0 -30
  105. package/templates/native-rust/backend/src/app/portal.rs +0 -317
  106. package/templates/native-rust/backend/src/app/root_routes.rs +0 -23
  107. package/templates/native-rust/backend/src/app/routes.rs +0 -315
  108. package/templates/native-rust/backend/src/app/session_files.rs +0 -19
  109. package/templates/native-rust/backend/src/app/shared_folder.rs +0 -383
  110. package/templates/native-rust/backend/src/app/test_support.rs +0 -202
  111. package/templates/native-rust/backend/src/app/uninstall.rs +0 -38
  112. package/templates/native-rust/backend/src/bin/api.rs +0 -72
  113. package/templates/native-rust/backend/src/bin/background-worker.rs +0 -37
  114. package/templates/native-rust/backend/src/build_env.rs +0 -155
  115. package/templates/native-rust/backend/src/lib.rs +0 -6
  116. package/templates/native-rust/backend/src/permissions.rs +0 -54
  117. package/templates/native-rust/backend/src/process.rs +0 -91
  118. package/templates/native-rust/i18n/glossary.json +0 -663
  119. package/templates/native-rust/i18n/messages/de.json +0 -30
  120. package/templates/native-rust/i18n/messages/en.json +0 -30
  121. package/templates/native-rust/i18n/messages/es.json +0 -30
  122. package/templates/native-rust/i18n/messages/fr.json +0 -30
  123. package/templates/native-rust/i18n/messages/it.json +0 -30
  124. package/templates/native-rust/i18n/messages/ja.json +0 -30
  125. package/templates/native-rust/i18n/messages/ko.json +0 -30
  126. package/templates/native-rust/i18n/messages/zh-CN.json +0 -30
  127. package/templates/native-rust/i18n/messages/zh-TW.json +0 -30
  128. package/templates/native-rust/ui/app.css +0 -45
  129. package/templates/native-rust/ui/app.js +0 -111
  130. package/templates/native-rust-delegate/backend/src/app/delegate_routes.rs +0 -92
  131. package/templates/native-rust-delegate/backend/src/bin/background-worker.rs +0 -52
  132. package/templates/native-rust-jobs/backend/src/app/background_routes.rs +0 -109
  133. package/templates/native-rust-root-ops/backend/src/app/root_routes.rs +0 -475
package/README.md CHANGED
@@ -11,11 +11,11 @@ the files an App owns; the SDK (`github.com/synopackageland/syno-pkg-land-sdk`,
11
11
  | `native-go-jobs` | Background job routes in `internal/app` and their page test |
12
12
  | `native-go-delegate` | Delegate routes, the delegate background worker, the delegate `CapabilityPanels.vue` |
13
13
  | `native-go-root-ops` | Executor routes in `internal/app` and an example `root/whoami.sh` |
14
- | `native-rust` | Base: `dsm-package.yaml` with `backend.kind: rust`, Cargo package `app` (`backend/src/bin/{api,background-worker}.rs`, `backend/src/app`, `backend/permissions.json`, committed `Cargo.lock`, `rust-toolchain.toml`), plain `ui/`, i18n |
15
- | `native-rust-vue` | Only the Vue README and gitignore; the shell itself is `native-go-vue`'s `frontend/` |
16
- | `native-rust-jobs` | `backend/src/app/background_routes.rs`: the background job routes and their tests |
17
- | `native-rust-delegate` | `delegate_routes.rs` and the delegate `background-worker.rs` |
18
- | `native-rust-root-ops` | `root_routes.rs`: the executor routes and their tests |
14
+ | `native-python` | Base: `dsm-package.yaml` (`backend.runtime: python`), the App in `backend/app` (`routes.py`, stub capability modules, `permissions.json`), unittest tests |
15
+ | `native-node` | Base: `dsm-package.yaml` (`backend.runtime: node`), TypeScript in `backend/src` compiled into `backend/app`, node:test tests, `package-lock.json` |
16
+ | `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` |
17
+ | `native-{python,node,rust}-{jobs,root-ops,delegate}` | The capability's example module, replacing the base's stub, with its tests |
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
21
  | `_shared` | Agent guides, template license, Go license texts, third-party notice writer |
@@ -23,25 +23,22 @@ the files an App owns; the SDK (`github.com/synopackageland/syno-pkg-land-sdk`,
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
25
25
  `_none.go` file); nothing outside `internal/app` and the Vue shell differs.
26
+ The Python, Node.js and Rust templates borrow the Go template's UI: `ui/` and
27
+ `i18n/` from `native-go`, `frontend/` from `native-go-vue` (and the jobs and
28
+ delegate overlays' frontend files), `root/whoami.sh` from `native-go-root-ops`.
29
+ Their overlays are copied in the order vue, root-ops, jobs, delegate; delegate
30
+ also makes `app.status` and `report.save` `authenticated`, and the Rust
31
+ manifest gets the overlays' methods. `init` copies the App SDK into
32
+ `backend/vendor` (Python `synopkgland_app`; Node `@synopackageland/app`, its
33
+ package.json without devDependencies and scripts, and `dist/`).
26
34
  The placeholders `__PACKAGE__` (also the Go module path), `__DISPLAY_NAME__` and
27
35
  `__BACKGROUND_ENABLED__` are substituted by `init`.
28
36
 
29
- Rust has no build tags, so the `native-rust-*` overlays overwrite same-named
30
- base files (`background_routes.rs`, `delegate_routes.rs`, `root_routes.rs`,
31
- `bin/background-worker.rs`) and nothing is removed. They carry only the
32
- backend. A Rust project borrows the native-go overlays' non-backend files: the
33
- Vue shell from `native-go-vue` (then `native-rust-vue`), `frontend/` of
34
- `native-go-jobs` and `native-go-delegate`, and `root/whoami.sh` of
35
- `native-go-root-ops`. A delegate project without root-ops also takes
36
- `native-rust-root-ops`'s `root_routes.rs`, the executor shell Go borrows as
37
- `executor.go`. `scripts/assemble.sh --language rust` does exactly this.
38
-
39
- `backend/go.mod` requires `github.com/synopackageland/syno-pkg-land-sdk v0.9.9`; that line is
37
+ `backend/go.mod` requires `github.com/synopackageland/syno-pkg-land-sdk v0.10.0`; that line is
40
38
  the single source of the SDK version and `frontend/package.json` pins
41
- `@synopackageland/sdk` to the same version. A Rust project takes it from the
42
- `tag` of the `syno-pkg-land-sdk` git dependency in `backend/Cargo.toml`, which
43
- `Cargo.lock` repeats; build-time values reach it through the contract's
44
- `SYNOPKGLAND_*` environment variables.
39
+ `@synopackageland/sdk` to the same version. Python and Node.js name it in
40
+ `backend.sdk`, Rust in the `syno-pkg-land-app` tag of `backend/Cargo.toml`
41
+ (and `Cargo.lock`); all of them pin 0.10.0.
45
42
 
46
43
  ## Notice writer
47
44
 
@@ -62,9 +59,10 @@ and `UI-THIRD_PARTY.md` in the output directory; other files there stay.
62
59
  ```sh
63
60
  export GOPRIVATE='github.com/synopackageland/*' # the SDK repository is private
64
61
  export SYNOPKGLAND_SDK_DIR=~/Public/synopackageland/sdk # optional sdk checkout: Go module at the root, ts/
62
+ export SYNOPKGLAND_DOCKER_SSH=my-docker-host # optional: the Docker engine for the Linux tests
65
63
  scripts/assemble.sh /tmp/app vue delegate # one combination, as init lays it out
66
- scripts/assemble.sh --language rust /tmp/app vue delegate # the same, for native-rust
67
- scripts/gate.sh # layout, every combination (Go and Rust), binary, npm pack
64
+ scripts/assemble.sh --language rust /tmp/app-rs plain jobs # python, node or rust
65
+ scripts/gate.sh # layout, every combination, binary, npm pack
68
66
  ```
69
67
 
70
68
  Without `SYNOPKGLAND_SDK_DIR` the combinations use the released SDK that
@@ -72,11 +70,13 @@ Without `SYNOPKGLAND_SDK_DIR` the combinations use the released SDK that
72
70
  `replace github.com/synopackageland/syno-pkg-land-sdk => $SYNOPKGLAND_SDK_DIR`
73
71
  and installs `$SYNOPKGLAND_SDK_DIR/ts` as an `npm pack` tarball (not a link, so Vue
74
72
  resolves once). With `SYNOPKGLAND_UI_TARBALL` set it installs that tarball as
75
- `@synopackageland/ui`, for a UI version not yet on npm. The Rust gate runs `cargo fmt --check`, `cargo clippy -D warnings`, `cargo test --locked`
76
- and a target clippy for the three DSM targets per combination; `rustup` installs the
77
- toolchain `backend/rust-toolchain.toml` pins. With `SYNOPKGLAND_SDK_DIR`, `scripts/rust-env.sh`
78
- (sourced by the gate) makes cargo fetch the SDK's pinned tag from that checkout instead of
79
- GitHub, leaving the Cargo files as shipped. CI is not available; `scripts/gate.sh` is the gate.
73
+ `@synopackageland/ui`, for a UI version not yet on npm.
74
+ The Python and Node.js combinations need `SYNOPKGLAND_SDK_DIR` (its `python/`,
75
+ and `node/` built with `npm ci && npm run build`) for their App SDK, and the
76
+ Rust ones fetch the SDK crate from it (`scripts/rust-env.sh`), so it must hold
77
+ the tag `Cargo.lock` pins. The gate runs each language's tests on Linux in
78
+ Docker (`scripts/bridge-linux-test.sh`: Python 3.8, Node.js 18, Rust).
79
+ CI is not available; `scripts/gate.sh` is the gate.
80
80
 
81
81
  SDK usage, protocol and API documentation: <https://github.com/synopackageland/syno-pkg-land-sdk>.
82
82
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@synopackageland/templates",
3
- "version": "0.9.8",
4
- "description": "Project templates for synopkgland init: native-go and native-rust (plain or Vue, with jobs, delegate and root-ops overlays), binary and compose.",
3
+ "version": "0.10.0",
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"},
7
7
  "exports": {
@@ -213,20 +213,58 @@ sweep forward the cancel instead of admitting it.
213
213
  `Service.OperationStatus`, `Service.ExportExample` (the SDK's
214
214
  `delegate/example.go`).
215
215
 
216
+ ## Python, Node.js and Rust backends
217
+
218
+ The SDK runtime is the CGI: it checks the DSM session, the entry gate and
219
+ permissions.json, then runs the App once per call, as the package account, and
220
+ answers the browser itself for every refusal. The App only registers methods
221
+ and asks the runtime for services with `ctx.runtime(op, params)`: `files.read`
222
+ (the caller's file, `files: session`), `bg.submit`/`bg.get`/`bg.cancel` (the
223
+ caller's jobs, `jobs: true`, whose worker hashes each job's input), `root.run`
224
+ (`rootOps`), `delegate.move_from_staging` (`delegate`) and `portal.status`. A
225
+ service refusal is a code the browser may see; pass it on. The admin guard
226
+ inside a shared method is `ctx.admin`. State lives in
227
+ `SYNOPKGLAND_DATA_DIR`. `synopkgland add` does not change these backends: choose
228
+ their capabilities with `synopkgland init --with`.
229
+
230
+ ## Python backend
231
+
232
+ - Methods: `backend/app/routes.py` (`build` registers them, the capability
233
+ modules `jobs.py`, `root_ops.py`, `delegate.py` add theirs); permissions:
234
+ `backend/app/permissions.json`. DSM runs it with its own python3 (3.8):
235
+ standard library only, nothing newer than 3.8.
236
+ - Params: `fields(params, name=type)` (`params.py`); errors:
237
+ `Error(code, message)`, `Error.bad_request(message)`; anything else is
238
+ `internal`. `ctx.runtime` raises the runtime's refusal as an `Error`.
239
+ - Test with `(cd backend && python3 -m unittest discover -s tests)`;
240
+ `tests/support.py`'s `call` plays the runtime, with the services a test answers.
241
+
242
+ ## Node.js backend
243
+
244
+ - Methods: `backend/src/routes.ts` (`build` registers them, the capability
245
+ modules `jobs.ts`, `root-ops.ts`, `delegate.ts` add theirs); permissions:
246
+ `backend/app/permissions.json`. TypeScript with `"module": "NodeNext"`;
247
+ `npm run build` compiles it into `backend/app`, which the SPK ships, so run it
248
+ before `synopkgland check` or `build`.
249
+ - Params: `strings(params, ...names)` (`params.ts`); errors:
250
+ `new AppError(code, message)`, `AppError.badRequest(message)`. Call services
251
+ through `service(ctx, op, params)` (`service.ts`), which passes the runtime's
252
+ refusals on; a bare `ctx.runtime` refusal would reach the browser as `internal`.
253
+ - Test with `(cd backend && npm ci && npm test && npm run typecheck)`; `test/support.ts`'s
254
+ `call` plays the runtime.
255
+
216
256
  ## Rust backend
217
257
 
218
- - Routes: `backend/src/app/routes.rs`; App permissions:
219
- `backend/permissions.json`. Test with `(cd backend && cargo test --locked)`,
220
- then `cargo clippy --locked --all-targets -- -D warnings` and
221
- `cargo fmt --check`.
222
- - Admin guard inside a shared route: `api::require_admin(caller)`.
223
- - Jobs: `background::Work` is `Arc<dyn Fn(&Context, &mut Task<'_>) ->
224
- Result<JobResult, BoxError>>`; call `t.report(Progress {..})` and
225
- `t.checkpoint(state)`, and resume from `t.job.checkpoint`. The template's
226
- Work is `app::hash_work` (`app/background/work.rs`, hash state through
227
- `sha256::Sha256::save`/`restore`), set as `Runner.work` in
228
- `bin/background-worker.rs` and as `delegate::Service.work` with delegate.
229
- - Uninstall hook: `app::uninstall(data_dir, delete_state)`
230
- (`app/uninstall.rs`), reached by `api.cgi uninstall`.
231
- - Delegate: `Service::destination`, `move_from_staging`, `cancel_operation`,
232
- `operation_status`, `export_example` (the SDK's `delegate/example.rs`).
258
+ - Methods: `backend/src/routes.rs` (`build` registers them, the capability
259
+ modules `jobs.rs`, `root_ops.rs`, `delegate.rs` add theirs); permissions:
260
+ `backend/permissions.json`. The build cross-compiles the binary, which cannot
261
+ run on the build machine: list every method in `backend.methods` of
262
+ dsm-package.yaml too.
263
+ - Params: a `#[serde(deny_unknown_fields)]` struct and `params.decode()?`;
264
+ errors: `Error::new(code, message)`, `Error::bad_request(message)`,
265
+ `routes::internal(e)` for the unexpected. `ctx.runtime::<T>(op, &params)?`
266
+ passes the runtime's refusal on.
267
+ - Test with `(cd backend && cargo test --locked)`, then
268
+ `cargo clippy --locked --all-targets -- -D warnings` and `cargo fmt --check`;
269
+ `test_support::call` plays the runtime. `rust-toolchain.toml` pins the
270
+ toolchain and the DSM targets; keep `Cargo.lock` committed.
@@ -1,6 +1,6 @@
1
1
  Native Go package build dependencies
2
2
 
3
- github.com/synopackageland/syno-pkg-land-sdk v0.9.9 (MIT)
3
+ github.com/synopackageland/syno-pkg-land-sdk v0.10.0 (MIT)
4
4
 
5
5
  Copyright (c) 2026 synopkgland
6
6
 
@@ -11,6 +11,8 @@ import (
11
11
  "net/http"
12
12
  "net/http/cgi"
13
13
  "os"
14
+ "strconv"
15
+ "time"
14
16
 
15
17
  "github.com/synopackageland/syno-pkg-land-sdk/api"
16
18
  "github.com/synopackageland/syno-pkg-land-sdk/dsm"
@@ -40,8 +42,20 @@ var (
40
42
  // "on" when dsm-package.yaml declares portal: serves portal.status;
41
43
  // "executor" below DSM 7.2, where the executor registers the entry.
42
44
  portal = ""
45
+ // backend.timeout_seconds, 60 unless set.
46
+ requestTimeout = ""
43
47
  )
44
48
 
49
+ // deadline is the CGI request deadline: requestTimeout seconds, or 60 when it
50
+ // is unset or not a positive number.
51
+ func deadline() api.DeadlineOption {
52
+ seconds, err := strconv.Atoi(requestTimeout)
53
+ if err != nil || seconds <= 0 {
54
+ seconds = 60
55
+ }
56
+ return api.Timeout(time.Duration(seconds) * time.Second)
57
+ }
58
+
45
59
  func main() {
46
60
  log.SetFlags(0)
47
61
  log.SetPrefix(packageID + ": ")
@@ -104,7 +118,7 @@ func main() {
104
118
  if standalone != nil {
105
119
  handler = standalone.Wrap(handler)
106
120
  }
107
- if err := cgi.Serve(api.WithRequestDeadline(handler)); err != nil {
121
+ if err := cgi.Serve(api.WithRequestDeadline(handler, deadline())); err != nil {
108
122
  log.Fatal(err)
109
123
  }
110
124
  }
@@ -0,0 +1,33 @@
1
+ package main
2
+
3
+ import (
4
+ "net/http"
5
+ "net/http/httptest"
6
+ "testing"
7
+ "time"
8
+
9
+ "github.com/synopackageland/syno-pkg-land-sdk/api"
10
+ )
11
+
12
+ func TestRequestDeadlineFollowsTheBuildSetting(t *testing.T) {
13
+ saved := requestTimeout
14
+ t.Cleanup(func() { requestTimeout = saved })
15
+ for setting, want := range map[string]time.Duration{
16
+ "": 60 * time.Second,
17
+ "120": 120 * time.Second,
18
+ "1": time.Second,
19
+ "0": 60 * time.Second,
20
+ "-5": 60 * time.Second,
21
+ "x": 60 * time.Second,
22
+ } {
23
+ requestTimeout = setting
24
+ var left time.Duration
25
+ api.WithRequestDeadline(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
26
+ d, _ := r.Context().Deadline()
27
+ left = time.Until(d)
28
+ }), deadline()).ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("POST", "/", nil))
29
+ if left > want || left < want-time.Second {
30
+ t.Errorf("requestTimeout %q: deadline in %v, want %v", setting, left, want)
31
+ }
32
+ }
33
+ }
@@ -4,6 +4,6 @@ go 1.25.0
4
4
 
5
5
  toolchain go1.26.9
6
6
 
7
- require github.com/synopackageland/syno-pkg-land-sdk v0.9.9
7
+ require github.com/synopackageland/syno-pkg-land-sdk v0.10.0
8
8
 
9
9
  require golang.org/x/sys v0.44.0 // indirect
@@ -1,4 +1,4 @@
1
- github.com/synopackageland/syno-pkg-land-sdk v0.9.9 h1:TUsblZtIwlBO0DpBTUOj6gd8+xTi60Y0CwkKNb+OR3M=
2
- github.com/synopackageland/syno-pkg-land-sdk v0.9.9/go.mod h1:hlsvaVuH2wsAoR8jzI1Rg/NeejQSFpAaN6zpIWsVbjI=
1
+ github.com/synopackageland/syno-pkg-land-sdk v0.10.0 h1:YcKdeKZDRGqUuNuuGS1WIehCA9UgfB3cpHyP8eHYdds=
2
+ github.com/synopackageland/syno-pkg-land-sdk v0.10.0/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=
@@ -624,7 +624,9 @@
624
624
  "error.method_not_allowed",
625
625
  "error.json_required",
626
626
  "error.cross_origin",
627
- "error.request_too_large"
627
+ "error.request_too_large",
628
+ "error.request_timeout",
629
+ "error.request_canceled"
628
630
  ]
629
631
  },
630
632
  {
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
15
15
  "error.network": "Verbindung fehlgeschlagen. Bitte überprüfen Sie Ihre Netzwerkeinstellungen.",
16
16
  "error.request_too_large": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
17
+ "error.request_timeout": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
18
+ "error.request_canceled": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
17
19
  "error.session_required": "Verbindung abgelaufen. Melden Sie sich erneut an.",
18
20
  "error.unknown_method": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
21
+ "error.app_unavailable": "Die App ist derzeit nicht verfügbar. Versuchen Sie es später erneut.",
22
+ "error.limit_exceeded": "Die Datei ist größer als zulässig.",
23
+ "error.read_failed": "Die Datei kann nicht gelesen werden. Bitte versuchen Sie es später erneut.",
24
+ "error.identity_unavailable": "Dieses Benutzerkonto kann nicht ermittelt werden. Bitte versuchen Sie es später erneut.",
19
25
  "greeting.adminOnly": "Nur Mitglieder der Gruppe administrators können den Gruß ändern.",
20
26
  "greeting.label": "Neuer Gruß",
21
27
  "greeting.save": "Speichern",
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "Unable to perform this operation. Please try again later.",
15
15
  "error.network": "Connection failed. Please check your network settings.",
16
16
  "error.request_too_large": "Unable to perform this operation. Please try again later.",
17
+ "error.request_timeout": "Unable to perform this operation. Please try again later.",
18
+ "error.request_canceled": "Unable to perform this operation. Please try again later.",
17
19
  "error.session_required": "Connection expired. Please sign in again.",
18
20
  "error.unknown_method": "Unable to perform this operation. Please try again later.",
21
+ "error.app_unavailable": "The App is not available right now. Try again later.",
22
+ "error.limit_exceeded": "The file is larger than allowed.",
23
+ "error.read_failed": "Unable to read the file. Please try again later.",
24
+ "error.identity_unavailable": "Unable to identify this user account. Please try again later.",
19
25
  "greeting.adminOnly": "Only members of the administrators group can change the greeting.",
20
26
  "greeting.label": "New greeting",
21
27
  "greeting.save": "Save",
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
15
15
  "error.network": "Error de la conexión. Compruebe su conexión de red.",
16
16
  "error.request_too_large": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
17
+ "error.request_timeout": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
18
+ "error.request_canceled": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
17
19
  "error.session_required": "Conexión caducada. Vuelva a conectarse.",
18
20
  "error.unknown_method": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
21
+ "error.app_unavailable": "La App no está disponible en este momento. Vuelva a intentarlo más tarde.",
22
+ "error.limit_exceeded": "El archivo supera el tamaño permitido.",
23
+ "error.read_failed": "No se puede leer el archivo. Vuelva a intentarlo más tarde.",
24
+ "error.identity_unavailable": "No se puede identificar esta cuenta de usuario. Vuelva a intentarlo más tarde.",
19
25
  "greeting.adminOnly": "Solo los miembros del grupo administrators pueden cambiar el saludo.",
20
26
  "greeting.label": "Nuevo saludo",
21
27
  "greeting.save": "Guardar",
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
15
15
  "error.network": "La connexion a échoué. Vérifiez vos paramètres réseau.",
16
16
  "error.request_too_large": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
17
+ "error.request_timeout": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
18
+ "error.request_canceled": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
17
19
  "error.session_required": "La connexion a expiré. Reconnectez-vous.",
18
20
  "error.unknown_method": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
21
+ "error.app_unavailable": "L’App n’est pas disponible pour le moment. Réessayez plus tard.",
22
+ "error.limit_exceeded": "Le fichier dépasse la taille autorisée.",
23
+ "error.read_failed": "Impossible de lire le fichier. Veuillez réessayer ultérieurement.",
24
+ "error.identity_unavailable": "Impossible d'identifier ce compte utilisateur. Veuillez réessayer ultérieurement.",
19
25
  "greeting.adminOnly": "Seuls les membres du groupe administrators peuvent modifier le message d'accueil.",
20
26
  "greeting.label": "Nouveau message d'accueil",
21
27
  "greeting.save": "Sauvegarder",
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "Impossibile eseguire questa operazione. Riprovare più tardi.",
15
15
  "error.network": "Connessione non riuscita. Controllare le impostazioni di rete.",
16
16
  "error.request_too_large": "Impossibile eseguire questa operazione. Riprovare più tardi.",
17
+ "error.request_timeout": "Impossibile eseguire questa operazione. Riprovare più tardi.",
18
+ "error.request_canceled": "Impossibile eseguire questa operazione. Riprovare più tardi.",
17
19
  "error.session_required": "Connessione scaduta. Accedere nuovamente.",
18
20
  "error.unknown_method": "Impossibile eseguire questa operazione. Riprovare più tardi.",
21
+ "error.app_unavailable": "L’App non è al momento disponibile. Riprovare più tardi.",
22
+ "error.limit_exceeded": "Il file supera le dimensioni consentite.",
23
+ "error.read_failed": "Impossibile leggere il file. Riprovare più tardi.",
24
+ "error.identity_unavailable": "Impossibile identificare questo account utente. Riprovare più tardi.",
19
25
  "greeting.adminOnly": "Solo i membri del gruppo administrators possono modificare il saluto.",
20
26
  "greeting.label": "Nuovo saluto",
21
27
  "greeting.save": "Salva",
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "この操作は実行できません。後でもう一度お試しください。",
15
15
  "error.network": "接続に失敗しました。ネットワーク設定を確認してください。",
16
16
  "error.request_too_large": "この操作は実行できません。後でもう一度お試しください。",
17
+ "error.request_timeout": "この操作は実行できません。後でもう一度お試しください。",
18
+ "error.request_canceled": "この操作は実行できません。後でもう一度お試しください。",
17
19
  "error.session_required": "接続の期限が切れています。もう 1 度サイン インしてください。",
18
20
  "error.unknown_method": "この操作は実行できません。後でもう一度お試しください。",
21
+ "error.app_unavailable": "App は現在使用できません。しばらくしてから再試行してください。",
22
+ "error.limit_exceeded": "ファイルが許可されたサイズを超えています。",
23
+ "error.read_failed": "ファイルを読み取れません。後でもう一度お試しください。",
24
+ "error.identity_unavailable": "このユーザー アカウントを識別できません。後でもう一度お試しください。",
19
25
  "greeting.adminOnly": "あいさつを変更できるのは administrators グループのメンバーのみです。",
20
26
  "greeting.label": "新しいあいさつ",
21
27
  "greeting.save": "保存",
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
15
15
  "error.network": "연결 실패. 네트워크 설정을 확인해 주십시오.",
16
16
  "error.request_too_large": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
17
+ "error.request_timeout": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
18
+ "error.request_canceled": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
17
19
  "error.session_required": "연결 만료됨. 다시 로그인 해 주십시오.",
18
20
  "error.unknown_method": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
21
+ "error.app_unavailable": "현재 App을 사용할 수 없습니다. 나중에 다시 시도하십시오.",
22
+ "error.limit_exceeded": "파일이 허용된 크기를 초과합니다.",
23
+ "error.read_failed": "파일을 읽을 수 없습니다. 나중에 다시 시도하십시오.",
24
+ "error.identity_unavailable": "이 사용자 계정을 확인할 수 없습니다. 나중에 다시 시도하십시오.",
19
25
  "greeting.adminOnly": "administrators 그룹의 구성원만 인사말을 변경할 수 있습니다.",
20
26
  "greeting.label": "새 인사말",
21
27
  "greeting.save": "저장",
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "无法执行此操作。请稍后再试。",
15
15
  "error.network": "无法联机,请检查你的网络设置。",
16
16
  "error.request_too_large": "无法执行此操作。请稍后再试。",
17
+ "error.request_timeout": "无法执行此操作。请稍后再试。",
18
+ "error.request_canceled": "无法执行此操作。请稍后再试。",
17
19
  "error.session_required": "联机超时,请重新登录。",
18
20
  "error.unknown_method": "无法执行此操作。请稍后再试。",
21
+ "error.app_unavailable": "App 当前不可用,请稍后重试。",
22
+ "error.limit_exceeded": "文件超过允许的大小。",
23
+ "error.read_failed": "无法读取文件。请稍后再试。",
24
+ "error.identity_unavailable": "无法识别此用户帐号。请稍后再试。",
19
25
  "greeting.adminOnly": "只有 administrators 群组的成员可以更改问候语。",
20
26
  "greeting.label": "新的问候语",
21
27
  "greeting.save": "保存",
@@ -14,8 +14,14 @@
14
14
  "error.method_not_allowed": "無法執行此操作。請稍後再試。",
15
15
  "error.network": "無法連線,請檢查你的網路設定。",
16
16
  "error.request_too_large": "無法執行此操作。請稍後再試。",
17
+ "error.request_timeout": "無法執行此操作。請稍後再試。",
18
+ "error.request_canceled": "無法執行此操作。請稍後再試。",
17
19
  "error.session_required": "連線逾時。請重新登入。",
18
20
  "error.unknown_method": "無法執行此操作。請稍後再試。",
21
+ "error.app_unavailable": "App 目前無法使用,請稍後再試。",
22
+ "error.limit_exceeded": "檔案超過允許的大小。",
23
+ "error.read_failed": "無法讀取檔案。請稍後再試。",
24
+ "error.identity_unavailable": "無法識別此使用者帳號。請稍後再試。",
19
25
  "greeting.adminOnly": "只有 administrators 群組的成員可以變更問候語。",
20
26
  "greeting.label": "新的問候語",
21
27
  "greeting.save": "儲存",
@@ -71,7 +71,8 @@
71
71
  [[t("status.user"), data.admin ? t("status.userAdmin", { user: data.user }) : data.user],
72
72
  [t("status.package"), data.package],
73
73
  [t("status.version"), data.version],
74
- [t("status.backend"), data.go_version + " · " + data.platform],
74
+ // A Go backend reports go_version; a Python, Node.js or Rust App reports language.
75
+ [t("status.backend"), (data.language || data.go_version) + " · " + data.platform],
75
76
  [t("status.uid"), String(data.process.uid)]].forEach(function (row) {
76
77
  status.appendChild(el("dt", { text: row[0] }));
77
78
  status.appendChild(el("dd", { text: row[1] }));
@@ -5,6 +5,7 @@ import {AppRoot} from '@synopackageland/ui'
5
5
  import type {BackgroundSaveFacade} from '@synopackageland/sdk'
6
6
  import CapabilityPanels from '../src/CapabilityPanels.vue'
7
7
  import {mount} from '../src/main'
8
+ import {dsmWindow} from './context'
8
9
  const cleanup:Array<()=>void>=[]
9
10
  afterEach(()=>cleanup.splice(0).forEach(fn=>fn()))
10
11
  async function settle(){for(let i=0;i<30;i++){await Promise.resolve();await nextTick()}}
@@ -66,7 +67,7 @@ test('the app mount forwards ctx.executor to administrator setup only',async()=>
66
67
  throw {code:'unknown_method'}
67
68
  })
68
69
  const root=document.createElement('div');document.body.append(root)
69
- const app=mount(root,{locale:'en',call,reopen:()=>()=>{},executor:{status,authorize,control:vi.fn(async()=>({state:'ready' as const}))}} as any)
70
+ const app=mount(root,dsmWindow({call,executor:{status,authorize,control:vi.fn(async()=>({state:'ready' as const}))} as never}))
70
71
  cleanup.push(()=>{app.unmount();root.remove()});await settle()
71
72
  if(admin){
72
73
  expect(status).toHaveBeenCalled()
@@ -90,7 +91,7 @@ test('the header Refresh reloads the save destinations',async()=>{
90
91
  throw {code:'unknown_method'}
91
92
  })
92
93
  const root=document.createElement('div');document.body.append(root)
93
- const app=mount(root,{locale:'en',call,reopen:()=>()=>{}} as any)
94
+ const app=mount(root,dsmWindow({call}))
94
95
  cleanup.push(()=>{app.unmount();root.remove()});await settle()
95
96
  const reads=()=>call.mock.calls.filter(([method])=>method==='delegate.destination').length
96
97
  const before=reads();expect(before).toBeGreaterThan(0)
@@ -2,7 +2,7 @@
2
2
  import {expect,test,vi} from 'vitest'
3
3
  import {nextTick} from 'vue'
4
4
  import {mount} from '../src/main'
5
- import type {Context} from '@synopackageland/sdk'
5
+ import {dsmWindow} from './context'
6
6
  async function settle(){for(let i=0;i<20;i++){await Promise.resolve();await nextTick()}}
7
7
  // The CLI turns the background page on for jobs (and delegate) projects only.
8
8
  test('a jobs project mounts the background panel for the signed-in user',async()=>{
@@ -11,7 +11,7 @@ test('a jobs project mounts the background panel for the signed-in user',async()
11
11
  throw {code:'unknown_method'}
12
12
  })
13
13
  const root=document.createElement('div');document.body.append(root)
14
- const app=mount(root,{locale:'en',call,reopen:()=>()=>{}} as unknown as Context)
14
+ const app=mount(root,dsmWindow({call}))
15
15
  try{
16
16
  await settle()
17
17
  expect(call.mock.calls.some(([method])=>method.startsWith('bg.'))).toBe(true)
@@ -29,7 +29,7 @@ test('the background panel pauses a running job and resumes a paused one',async(
29
29
  return {}
30
30
  })
31
31
  const root=document.createElement('div');document.body.append(root)
32
- const app=mount(root,{locale:'en',call,reopen:()=>()=>{}} as unknown as Context)
32
+ const app=mount(root,dsmWindow({call}))
33
33
  const button=(id:string,label:string)=>Array.from(root.querySelectorAll(`[data-job-id="${id}"] button`)).find(b=>b.textContent===label) as HTMLButtonElement|undefined
34
34
  try{
35
35
  await settle()
@@ -48,7 +48,7 @@ test('the header Refresh reloads the background panel',async()=>{
48
48
  return {}
49
49
  })
50
50
  const root=document.createElement('div');document.body.append(root)
51
- const app=mount(root,{locale:'en',call,reopen:()=>()=>{}} as unknown as Context)
51
+ const app=mount(root,dsmWindow({call}))
52
52
  const reads=()=>call.mock.calls.filter(([method])=>method==='bg.jobs.list').length
53
53
  try{
54
54
  await settle();const before=reads()
@@ -33,14 +33,26 @@ Generated build and unit tests do not establish NAS runtime acceptance.
33
33
  The manifest is dsm-package.yaml schema 2: backend.kind: go and capabilities.files: session, jobs: true, identity: standalone, rootOps: true. Use --with login to declare standalone identity. Existing projects use synopkgland add <cap>...; app entrypoints stay app-owned, SDK conflicts are refused. check, inspect, build, deploy and status accept --json.
34
34
 
35
35
  Use the installed `@synopackageland/ui`; package.json pins its version.
36
- `AppRoot` defaults to app modal scope and stays bounded at `height: 100%`;
37
- `AppLayout wide-layout="window"` keeps the DSM shell in window mode even when
38
- maximized. Only whole-page web/Portal apps should opt into document scope or
39
- `wide-layout="web"`. The DSM host sets the 700px minimum window width.
40
- In a DSM window (`ctx.host.platform().host === 'dsm'`) `AppRoot` takes
36
+ `App.vue` lays the shell out with the SDK's `AppShell` (`@synopackageland/sdk/vue`):
37
+ `pages` from `shellPages`, the header buttons in `#actions` and the pages in its
38
+ default slot. Given `ctx`, it follows the launch. In a DSM desktop window it
39
+ keeps `wide-layout="window"`, even maximized; the DSM host sets the 700px
40
+ minimum window width. A Portal or standalone launch owns the whole page
41
+ (`ctx.fullPage`, from the generated window): `AppShell` takes
42
+ `wide-layout="web"` (the SaaS layout at 1200px or wider, mobile on a phone) and
43
+ a device-width viewport, undone at unmount, since DSM's page has no
44
+ device-width viewport. Its full-page sidebar names the App with
45
+ `ctx.displayName` and `ctx.appIcon` (without them the page title and icon) and
46
+ shows the signed-in DSM account and its role from `ctx.user`. See the ui's
47
+ `docs/adaptive-layout.md`.
48
+ `AppShell`'s `app-root` wraps it in an app-local `AppRoot` (app modal scope, on
49
+ a full page as well, bounded at `height: 100%`) with the UI locale from
50
+ `locale`; do not add another `AppRoot`.
51
+ In a DSM window (not a full page) that `AppRoot` takes
41
52
  `dialog-bounds="viewport"`, so Dialogs can be dragged out of the window, and
42
- its `activate` event calls `ctx.host.activateWindow()` to bring the window to
43
- the front. Elsewhere Dialogs stay inside the App.
53
+ pressing one calls `ctx.host.activateWindow()` to bring the window to the
54
+ front. Elsewhere Dialogs stay inside the App. A confirmed sign-in need sets
55
+ `denied`: the `#denied` slot's `LoginPage` takes the place of the App's pages.
44
56
  Import `themes/dsm7-embedded.css` and assign each mount a unique
45
57
  `app.config.idPrefix` before mounting.
46
58
 
@@ -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.9.9",
11
- "@synopackageland/ui": "0.9.3",
10
+ "@synopackageland/sdk": "0.10.0",
11
+ "@synopackageland/ui": "0.9.4",
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.9.9",
1152
- "resolved": "https://registry.npmjs.org/@synopackageland/sdk/-/sdk-0.9.9.tgz",
1153
- "integrity": "sha512-O73D+s+yJPmYLfZ2l261S1izqa5lAc9hgbuBScE4uoKyydUDfWEhAmb7CUM6Er25wY8nYqG480GMcyfLuESFGw==",
1151
+ "version": "0.10.0",
1152
+ "resolved": "https://registry.npmjs.org/@synopackageland/sdk/-/sdk-0.10.0.tgz",
1153
+ "integrity": "sha512-oRwr3I4WNWCqknTPvDnlR7wjM/6pBX+UJ/GRc2U4l9+VUGrdgq0UH9gCjmGIZS9beE5y33tcxmj2ASweLUbJIg==",
1154
1154
  "license": "MIT",
1155
1155
  "peerDependencies": {
1156
1156
  "@lucide/vue": "^1.48.0",
1157
- "@synopackageland/ui": "^0.9.3",
1157
+ "@synopackageland/ui": "^0.9.4",
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.3",
1171
- "resolved": "https://registry.npmjs.org/@synopackageland/ui/-/ui-0.9.3.tgz",
1172
- "integrity": "sha512-CcCpSiQ2y4GJnbWjBxRrPO6QzLboMdEzqgbMdpXGaEI3IaTrxwS6zy8yXuuMBQHuqAcfBf3jL7fmcL9A58oVqw==",
1170
+ "version": "0.9.4",
1171
+ "resolved": "https://registry.npmjs.org/@synopackageland/ui/-/ui-0.9.4.tgz",
1172
+ "integrity": "sha512-yu0RrYtT/QcAn/lNwqZBoqqjLTXrpqqnSWB+0swGou8IWLrhfwXrHVBf+oJc+NjLj+G4kB7AyP9kbvw9FHxNOA==",
1173
1173
  "license": "MIT",
1174
1174
  "dependencies": {
1175
1175
  "@internationalized/date": "3.12.4",
@@ -8,8 +8,8 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@lucide/vue": "1.48.0",
11
- "@synopackageland/sdk": "0.9.9",
12
- "@synopackageland/ui": "0.9.3",
11
+ "@synopackageland/sdk": "0.10.0",
12
+ "@synopackageland/ui": "0.9.4",
13
13
  "vue": "3.5.43"
14
14
  },
15
15
  "devDependencies": {