@synopackageland/templates 0.9.9 → 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 (132) 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/messages/de.json +4 -0
  10. package/templates/native-go/i18n/messages/en.json +4 -0
  11. package/templates/native-go/i18n/messages/es.json +4 -0
  12. package/templates/native-go/i18n/messages/fr.json +4 -0
  13. package/templates/native-go/i18n/messages/it.json +4 -0
  14. package/templates/native-go/i18n/messages/ja.json +4 -0
  15. package/templates/native-go/i18n/messages/ko.json +4 -0
  16. package/templates/native-go/i18n/messages/zh-CN.json +4 -0
  17. package/templates/native-go/i18n/messages/zh-TW.json +4 -0
  18. package/templates/native-go/ui/app.js +2 -1
  19. package/templates/native-go-delegate/frontend/test/capability-panels.test.ts +3 -2
  20. package/templates/native-go-jobs/frontend/test/background-page.test.ts +4 -4
  21. package/templates/native-go-vue/README.md +19 -7
  22. package/templates/native-go-vue/frontend/package-lock.json +9 -9
  23. package/templates/native-go-vue/frontend/package.json +2 -2
  24. package/templates/native-go-vue/frontend/src/App.vue +31 -36
  25. package/templates/native-go-vue/frontend/test/apps.test.ts +65 -12
  26. package/templates/native-go-vue/frontend/test/context.ts +8 -0
  27. package/templates/native-go-vue/frontend/test/native-controls.test.ts +3 -4
  28. package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +2 -2
  29. package/templates/native-node/README.md +153 -0
  30. package/templates/native-node/backend/app/package.json +4 -0
  31. package/templates/native-node/backend/app/permissions.json +5 -0
  32. package/templates/native-node/backend/package-lock.json +59 -0
  33. package/templates/native-node/backend/package.json +17 -0
  34. package/templates/native-node/backend/src/delegate.ts +5 -0
  35. package/templates/native-node/backend/src/jobs.ts +5 -0
  36. package/templates/native-node/backend/src/main.ts +4 -0
  37. package/templates/native-node/backend/src/params.ts +11 -0
  38. package/templates/native-node/backend/src/root-ops.ts +5 -0
  39. package/templates/native-node/backend/src/routes.ts +97 -0
  40. package/templates/native-node/backend/src/service.ts +22 -0
  41. package/templates/native-node/backend/test/routes.test.ts +75 -0
  42. package/templates/native-node/backend/test/support.ts +67 -0
  43. package/templates/native-node/backend/tsconfig.build.json +8 -0
  44. package/templates/native-node/backend/tsconfig.json +18 -0
  45. package/templates/native-node/dsm-package.yaml +80 -0
  46. package/templates/native-node/gitignore +4 -0
  47. package/templates/native-node-delegate/backend/src/delegate.ts +35 -0
  48. package/templates/native-node-delegate/backend/test/delegate.test.ts +51 -0
  49. package/templates/native-node-jobs/backend/src/jobs.ts +38 -0
  50. package/templates/native-node-jobs/backend/test/jobs.test.ts +73 -0
  51. package/templates/native-node-root-ops/backend/src/root-ops.ts +16 -0
  52. package/templates/native-node-root-ops/backend/test/root-ops.test.ts +23 -0
  53. package/templates/native-node-vue/README.md +56 -0
  54. package/templates/native-node-vue/gitignore +4 -0
  55. package/templates/native-python/README.md +150 -0
  56. package/templates/native-python/backend/app/delegate.py +5 -0
  57. package/templates/native-python/backend/app/jobs.py +5 -0
  58. package/templates/native-python/backend/app/main.py +5 -0
  59. package/templates/native-python/backend/app/params.py +10 -0
  60. package/templates/native-python/backend/app/permissions.json +5 -0
  61. package/templates/native-python/backend/app/root_ops.py +5 -0
  62. package/templates/native-python/backend/app/routes.py +107 -0
  63. package/templates/native-python/backend/tests/support.py +72 -0
  64. package/templates/native-python/backend/tests/test_routes.py +73 -0
  65. package/templates/native-python/dsm-package.yaml +77 -0
  66. package/templates/native-python/gitignore +2 -0
  67. package/templates/native-python-delegate/backend/app/delegate.py +42 -0
  68. package/templates/native-python-delegate/backend/tests/test_delegate.py +58 -0
  69. package/templates/native-python-jobs/backend/app/jobs.py +40 -0
  70. package/templates/native-python-jobs/backend/tests/test_jobs.py +72 -0
  71. package/templates/native-python-root-ops/backend/app/root_ops.py +18 -0
  72. package/templates/native-python-root-ops/backend/tests/test_root_ops.py +34 -0
  73. package/templates/native-python-vue/README.md +56 -0
  74. package/templates/native-python-vue/gitignore +3 -0
  75. package/templates/native-rust/README.md +74 -296
  76. package/templates/native-rust/backend/Cargo.lock +6 -6
  77. package/templates/native-rust/backend/Cargo.toml +2 -10
  78. package/templates/native-rust/backend/src/delegate.rs +6 -0
  79. package/templates/native-rust/backend/src/jobs.rs +6 -0
  80. package/templates/native-rust/backend/src/main.rs +12 -0
  81. package/templates/native-rust/backend/src/root_ops.rs +6 -0
  82. package/templates/native-rust/backend/src/routes.rs +352 -0
  83. package/templates/native-rust/backend/src/test_support.rs +91 -0
  84. package/templates/native-rust/dsm-package.yaml +10 -21
  85. package/templates/native-rust-delegate/backend/src/delegate.rs +171 -0
  86. package/templates/native-rust-jobs/backend/src/jobs.rs +240 -0
  87. package/templates/native-rust-root-ops/backend/src/root_ops.rs +83 -0
  88. package/templates/native-rust-vue/README.md +35 -34
  89. package/templates/native-rust/backend/THIRD_PARTY_NOTICES.txt +0 -207
  90. package/templates/native-rust/backend/src/app/background/mod.rs +0 -424
  91. package/templates/native-rust/backend/src/app/background/owner.rs +0 -77
  92. package/templates/native-rust/backend/src/app/background/owner_tests.rs +0 -174
  93. package/templates/native-rust/backend/src/app/background/schedule.rs +0 -126
  94. package/templates/native-rust/backend/src/app/background/schedule_tests.rs +0 -108
  95. package/templates/native-rust/backend/src/app/background/tests.rs +0 -505
  96. package/templates/native-rust/backend/src/app/background/work.rs +0 -78
  97. package/templates/native-rust/backend/src/app/background/work_tests.rs +0 -123
  98. package/templates/native-rust/backend/src/app/background_routes.rs +0 -22
  99. package/templates/native-rust/backend/src/app/delegate_config.rs +0 -188
  100. package/templates/native-rust/backend/src/app/delegate_routes.rs +0 -22
  101. package/templates/native-rust/backend/src/app/identity.rs +0 -56
  102. package/templates/native-rust/backend/src/app/migrations.rs +0 -79
  103. package/templates/native-rust/backend/src/app/mod.rs +0 -30
  104. package/templates/native-rust/backend/src/app/portal.rs +0 -317
  105. package/templates/native-rust/backend/src/app/root_routes.rs +0 -23
  106. package/templates/native-rust/backend/src/app/routes.rs +0 -315
  107. package/templates/native-rust/backend/src/app/session_files.rs +0 -19
  108. package/templates/native-rust/backend/src/app/shared_folder.rs +0 -383
  109. package/templates/native-rust/backend/src/app/test_support.rs +0 -202
  110. package/templates/native-rust/backend/src/app/uninstall.rs +0 -38
  111. package/templates/native-rust/backend/src/bin/api.rs +0 -72
  112. package/templates/native-rust/backend/src/bin/background-worker.rs +0 -37
  113. package/templates/native-rust/backend/src/build_env.rs +0 -155
  114. package/templates/native-rust/backend/src/lib.rs +0 -6
  115. package/templates/native-rust/backend/src/permissions.rs +0 -54
  116. package/templates/native-rust/backend/src/process.rs +0 -91
  117. package/templates/native-rust/i18n/glossary.json +0 -665
  118. package/templates/native-rust/i18n/messages/de.json +0 -32
  119. package/templates/native-rust/i18n/messages/en.json +0 -32
  120. package/templates/native-rust/i18n/messages/es.json +0 -32
  121. package/templates/native-rust/i18n/messages/fr.json +0 -32
  122. package/templates/native-rust/i18n/messages/it.json +0 -32
  123. package/templates/native-rust/i18n/messages/ja.json +0 -32
  124. package/templates/native-rust/i18n/messages/ko.json +0 -32
  125. package/templates/native-rust/i18n/messages/zh-CN.json +0 -32
  126. package/templates/native-rust/i18n/messages/zh-TW.json +0 -32
  127. package/templates/native-rust/ui/app.css +0 -45
  128. package/templates/native-rust/ui/app.js +0 -111
  129. package/templates/native-rust-delegate/backend/src/app/delegate_routes.rs +0 -92
  130. package/templates/native-rust-delegate/backend/src/bin/background-worker.rs +0 -52
  131. package/templates/native-rust-jobs/backend/src/app/background_routes.rs +0 -109
  132. package/templates/native-rust-root-ops/backend/src/app/root_routes.rs +0 -475
@@ -0,0 +1,240 @@
1
+ //! Background jobs: hash a NAS file the caller may read.
2
+ //!
3
+ //! The SDK's worker runs each job as the package account: it hashes the job's
4
+ //! input (SHA-256) and keeps the result for the job's owner, the caller. The
5
+ //! runtime serves files.read with the caller's DSM session and bg.* for the
6
+ //! caller's own jobs only.
7
+
8
+ use crate::routes::{Config, internal};
9
+ use serde::Deserialize;
10
+ use serde_json::{Value, json};
11
+ use std::os::unix::fs::DirBuilderExt;
12
+ use std::path::{Path, PathBuf};
13
+ use syno_pkg_land_app::{App, Context, Error, Params};
14
+
15
+ /// A job's input is at most 512 KiB, copied into the job when it is submitted.
16
+ const MAX_INPUT: u64 = 512 * 1024;
17
+
18
+ #[derive(Deserialize)]
19
+ #[serde(deny_unknown_fields)]
20
+ struct Submit {
21
+ key: String,
22
+ path: String,
23
+ }
24
+
25
+ #[derive(Deserialize)]
26
+ #[serde(deny_unknown_fields)]
27
+ struct JobId {
28
+ id: String,
29
+ }
30
+
31
+ #[derive(Deserialize)]
32
+ struct Read {
33
+ path: PathBuf,
34
+ size: u64,
35
+ }
36
+
37
+ pub fn register(app: &mut App, cfg: &Config) {
38
+ let cfg = cfg.clone();
39
+ app.method("hash.submit", move |ctx, params| submit(&cfg, ctx, params));
40
+ app.method("hash.get", |ctx, params| job(ctx, "bg.get", params));
41
+ app.method("hash.cancel", |ctx, params| job(ctx, "bg.cancel", params));
42
+ }
43
+
44
+ fn job(ctx: &Context, op: &str, params: &Params) -> Result<Value, Error> {
45
+ let JobId { id } = params.decode()?;
46
+ ctx.runtime(op, &json!({"id": id}))
47
+ }
48
+
49
+ fn submit(cfg: &Config, ctx: &Context, params: &Params) -> Result<Value, Error> {
50
+ let p: Submit = params.decode()?;
51
+ let read: Read = ctx.runtime("files.read", &json!({"path": p.path}))?;
52
+ if read.size > MAX_INPUT {
53
+ return Err(Error::new(
54
+ "limit_exceeded",
55
+ "The file is larger than allowed.",
56
+ ));
57
+ }
58
+ // bg.submit takes its input from the data directory; the call's spool is elsewhere.
59
+ let inputs = cfg.data_dir.join("hash-inputs");
60
+ std::fs::DirBuilder::new()
61
+ .recursive(true)
62
+ .mode(0o700)
63
+ .create(&inputs)
64
+ .map_err(internal)?;
65
+ let copy = inputs.join(&ctx.request_id);
66
+ std::fs::copy(&read.path, &copy).map_err(internal)?;
67
+ let name = Path::new(&p.path)
68
+ .file_name()
69
+ .map_or(String::new(), |n| n.to_string_lossy().into_owned());
70
+ let submitted = ctx.runtime(
71
+ "bg.submit",
72
+ &json!({"key": p.key, "name": name, "input": copy}),
73
+ );
74
+ let _ = std::fs::remove_file(&copy);
75
+ submitted
76
+ }
77
+
78
+ #[cfg(test)]
79
+ mod tests {
80
+ use super::*;
81
+ use crate::test_support::{Services, TempDir, call};
82
+ use serde_json::{Value, json};
83
+ use std::sync::{Arc, Mutex};
84
+
85
+ /// What bg.submit was asked: its params and the input it read.
86
+ type Submitted = Arc<Mutex<Vec<(Value, Vec<u8>)>>>;
87
+
88
+ fn setup() -> (TempDir, Config) {
89
+ let dir = TempDir::new();
90
+ let cfg = Config {
91
+ package: "ExampleApp".into(),
92
+ data_dir: dir.path().join("var"),
93
+ packages_root: dir.path().into(),
94
+ };
95
+ std::fs::create_dir(&cfg.data_dir).unwrap();
96
+ (dir, cfg)
97
+ }
98
+
99
+ fn job() -> Value {
100
+ json!({"job": {"id": "j1", "state": "queued"}, "duplicate": false})
101
+ }
102
+
103
+ /// files.read answers a spool file with content; bg.submit records its params and the input it read.
104
+ fn services(dir: &TempDir, content: Vec<u8>, submitted: &Submitted) -> Services {
105
+ let spool = dir.path().join("spool");
106
+ std::fs::write(&spool, &content).unwrap();
107
+ let read = json!({"path": spool, "size": content.len()});
108
+ let submitted = submitted.clone();
109
+ [
110
+ (
111
+ "files.read",
112
+ Box::new(move |_: &Value| Ok(read.clone())) as _,
113
+ ),
114
+ (
115
+ "bg.submit",
116
+ Box::new(move |p: &Value| {
117
+ // The runtime reads the input file while it answers bg.submit.
118
+ let input = std::fs::read(p["input"].as_str().unwrap()).unwrap();
119
+ submitted.lock().unwrap().push((p.clone(), input));
120
+ Ok(job())
121
+ }) as _,
122
+ ),
123
+ ]
124
+ .into()
125
+ }
126
+
127
+ #[test]
128
+ fn submit_hashes_a_copy_of_the_callers_file() {
129
+ let (dir, cfg) = setup();
130
+ let submitted = Arc::new(Mutex::new(Vec::new()));
131
+ let services = services(&dir, b"hello".to_vec(), &submitted);
132
+ let reply = call(
133
+ crate::routes::build(cfg.clone()),
134
+ "hash.submit",
135
+ json!({"key": "k1", "path": "/home/report.txt"}),
136
+ "alice",
137
+ &services,
138
+ );
139
+ assert_eq!(reply.data, job());
140
+ let ops: Vec<_> = reply.services.iter().map(|(op, _)| op.as_str()).collect();
141
+ assert_eq!(ops, ["files.read", "bg.submit"]);
142
+ assert_eq!(reply.services[0].1, json!({"path": "/home/report.txt"}));
143
+ let submitted = submitted.lock().unwrap();
144
+ let (params, content) = &submitted[0];
145
+ assert_eq!(
146
+ (&params["key"], &params["name"], content.as_slice()),
147
+ (&json!("k1"), &json!("report.txt"), b"hello".as_slice())
148
+ );
149
+ let input = params["input"].as_str().unwrap();
150
+ assert!(input.starts_with(cfg.data_dir.to_str().unwrap()), "{input}");
151
+ assert!(
152
+ !std::path::Path::new(input).exists(),
153
+ "the copy is removed once submitted"
154
+ );
155
+ }
156
+
157
+ #[test]
158
+ fn submit_refuses_a_file_over_the_job_input_limit() {
159
+ let (dir, cfg) = setup();
160
+ let submitted = Arc::new(Mutex::new(Vec::new()));
161
+ let services = services(&dir, vec![0; MAX_INPUT as usize + 1], &submitted);
162
+ let reply = call(
163
+ crate::routes::build(cfg),
164
+ "hash.submit",
165
+ json!({"key": "k1", "path": "/home/big.bin"}),
166
+ "alice",
167
+ &services,
168
+ );
169
+ assert_eq!(reply.code(), "limit_exceeded");
170
+ assert!(submitted.lock().unwrap().is_empty());
171
+ }
172
+
173
+ #[test]
174
+ fn submit_passes_on_the_runtimes_refusal() {
175
+ let (_dir, cfg) = setup();
176
+ let services: Services = [(
177
+ "files.read",
178
+ Box::new(|_: &Value| Err(Error::new("read_failed", "Unable to read the file."))) as _,
179
+ )]
180
+ .into();
181
+ let reply = call(
182
+ crate::routes::build(cfg),
183
+ "hash.submit",
184
+ json!({"key": "k1", "path": "/home/a"}),
185
+ "alice",
186
+ &services,
187
+ );
188
+ assert_eq!(reply.code(), "read_failed");
189
+ }
190
+
191
+ #[test]
192
+ fn submit_refuses_invalid_params_before_any_service() {
193
+ let (_dir, cfg) = setup();
194
+ for params in [
195
+ Value::Null,
196
+ json!({"key": "k1"}),
197
+ json!({"key": 1, "path": "/home/a"}),
198
+ json!({"key": "k1", "path": "/home/a", "x": 1}),
199
+ ] {
200
+ let reply = call(
201
+ crate::routes::build(cfg.clone()),
202
+ "hash.submit",
203
+ params.clone(),
204
+ "alice",
205
+ &Services::new(),
206
+ );
207
+ assert_eq!(
208
+ (reply.code(), reply.services.len()),
209
+ ("bad_request", 0),
210
+ "{params}"
211
+ );
212
+ }
213
+ }
214
+
215
+ #[test]
216
+ fn get_and_cancel_act_on_the_callers_job() {
217
+ let (_dir, cfg) = setup();
218
+ for (method, op) in [("hash.get", "bg.get"), ("hash.cancel", "bg.cancel")] {
219
+ let services: Services =
220
+ [(op, Box::new(|_: &Value| Ok(job()["job"].clone())) as _)].into();
221
+ let reply = call(
222
+ crate::routes::build(cfg.clone()),
223
+ method,
224
+ json!({"id": "j1"}),
225
+ "alice",
226
+ &services,
227
+ );
228
+ assert_eq!(reply.data, job()["job"]);
229
+ assert_eq!(reply.services, vec![(op.to_string(), json!({"id": "j1"}))]);
230
+ let reply = call(
231
+ crate::routes::build(cfg.clone()),
232
+ method,
233
+ json!({}),
234
+ "alice",
235
+ &Services::new(),
236
+ );
237
+ assert_eq!(reply.code(), "bad_request");
238
+ }
239
+ }
240
+ }
@@ -0,0 +1,83 @@
1
+ //! Root operations: run `whoami`, a program the package ships in root/ and
2
+ //! dsm-package.yaml approves, as root through the executor. The runtime
3
+ //! serves root.run only when the executor has the program's grant.
4
+
5
+ use crate::routes::Config;
6
+ use serde::Deserialize;
7
+ use serde_json::Value;
8
+ use syno_pkg_land_app::App;
9
+
10
+ #[derive(Deserialize)]
11
+ #[serde(deny_unknown_fields)]
12
+ struct NoParams {}
13
+
14
+ pub fn register(app: &mut App, _cfg: &Config) {
15
+ app.method("whoami.run", |ctx, params| {
16
+ params.decode::<Option<NoParams>>()?;
17
+ ctx.runtime::<Value>("root.run", &serde_json::json!({"name": "whoami"}))
18
+ });
19
+ }
20
+
21
+ #[cfg(test)]
22
+ mod tests {
23
+ use crate::routes::{Config, build};
24
+ use crate::test_support::{Services, call};
25
+ use serde_json::{Value, json};
26
+ use syno_pkg_land_app::Error;
27
+
28
+ fn cfg() -> Config {
29
+ Config {
30
+ package: "ExampleApp".into(),
31
+ data_dir: "/nonexistent".into(),
32
+ packages_root: "/nonexistent".into(),
33
+ }
34
+ }
35
+
36
+ #[test]
37
+ fn whoami_runs_the_approved_root_program() {
38
+ let output = json!({"exit_code": 0, "stdout": "0\n", "stderr": ""});
39
+ for params in [Value::Null, json!({})] {
40
+ let answer = output.clone();
41
+ let services: Services = [(
42
+ "root.run",
43
+ Box::new(move |_: &Value| Ok(answer.clone())) as _,
44
+ )]
45
+ .into();
46
+ let reply = call(build(cfg()), "whoami.run", params, "admin", &services);
47
+ assert_eq!(reply.data, output);
48
+ assert_eq!(
49
+ reply.services,
50
+ vec![("root.run".to_string(), json!({"name": "whoami"}))]
51
+ );
52
+ }
53
+ }
54
+
55
+ #[test]
56
+ fn whoami_passes_on_the_executors_refusal() {
57
+ let services: Services = [(
58
+ "root.run",
59
+ Box::new(|_: &Value| Err(Error::new("EXECUTOR_PAUSED", "The executor is paused.")))
60
+ as _,
61
+ )]
62
+ .into();
63
+ assert_eq!(
64
+ call(build(cfg()), "whoami.run", json!({}), "admin", &services).code(),
65
+ "EXECUTOR_PAUSED"
66
+ );
67
+ }
68
+
69
+ #[test]
70
+ fn whoami_takes_no_params() {
71
+ assert_eq!(
72
+ call(
73
+ build(cfg()),
74
+ "whoami.run",
75
+ json!({"name": "other"}),
76
+ "admin",
77
+ &Services::new()
78
+ )
79
+ .code(),
80
+ "bad_request"
81
+ );
82
+ }
83
+ }
@@ -1,10 +1,10 @@
1
1
  # Native Rust with Vue
2
2
 
3
- Edit `frontend/src/App.vue` and `main.ts` to build a DSM-window app with the
4
- public `@synopackageland/ui` components and embedded theme. The shell, sign-in,
5
- files, portal, jobs and delegate components come from `@synopackageland/sdk/vue`
6
- (types from `@synopackageland/sdk`); its version must equal the
7
- `syno-pkg-land-sdk` tag in `backend/Cargo.toml`. See
3
+ The Vue shell is the same as the Go template's. Edit `frontend/src/App.vue`
4
+ and `main.ts` to build a DSM-window app with the public `@synopackageland/ui`
5
+ components and embedded theme. The shell, sign-in, files, portal, jobs and
6
+ delegate components come from `@synopackageland/sdk/vue` (types from
7
+ `@synopackageland/sdk`); its version must equal the `syno-pkg-land-app` tag in backend/Cargo.toml. See
8
8
  <https://github.com/synopackageland/syno-pkg-land-sdk> for the components and their props.
9
9
 
10
10
  ```sh
@@ -15,41 +15,42 @@ npm run build
15
15
  ```
16
16
 
17
17
  The base app reads package status and edits the package greeting through
18
- `ctx.call`. Each window has its own Vue mount, request state and host
19
- subscriptions; unmount disposes subscriptions and ignores late responses.
18
+ `ctx.call`. Errors show the app's own `frontend/src/i18n` text, or the SDK's
19
+ `bridgeErrorCopy` for the codes the bridge runtime adds (`app_unavailable`
20
+ and the services' refusals). Each window has its own Vue mount, request state
21
+ and host subscriptions; unmount disposes subscriptions and ignores late responses.
20
22
 
21
- `--with root-ops` adds the existing DSM approval gate for fixed `root/*.sh`
22
- operations. `--with jobs` adds package-account jobs and schedules; it combines with root-ops and files. `--with files` enables current-session File Station access,
23
- and the background picker uses the retained session provider.
24
-
25
- With `portal:` declared (`synopkgland add portal`, executor Apps only), the status page shows
26
- the SDK's `PortalSettings`: the DSM Application Portal link, the alias form
27
- for administrators, and the Control Panel shortcut.
28
-
29
- Use public library controls, the embedded theme, per-app modal scope and unique
30
- Vue ID prefixes. Backend route permissions and DSM checks remain authoritative.
31
- Generated build and unit tests do not establish NAS runtime acceptance.
32
-
33
- The manifest is dsm-package.yaml schema 2: backend.kind: rust 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.
23
+ The `--with jobs`, `root-ops` and `delegate` examples add their methods to
24
+ the Rust App; the shell's panels call them with `ctx.call`. The SDK's
25
+ background-jobs page and executor settings call the runtime's own browser
26
+ methods (`bg.*`, `executor.*`); check the SDK release notes for the ones a
27
+ bridge App's runtime serves.
34
28
 
35
29
  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
30
+ `App.vue` lays the shell out with the SDK's `AppShell` (`@synopackageland/sdk/vue`):
31
+ `pages` from `shellPages`, the header buttons in `#actions` and the pages in its
32
+ default slot. Given `ctx`, it follows the launch. In a DSM desktop window it
33
+ keeps `wide-layout="window"`, even maximized; the DSM host sets the 700px
34
+ minimum window width. A Portal or standalone launch owns the whole page
35
+ (`ctx.fullPage`, from the generated window): `AppShell` takes
36
+ `wide-layout="web"` (the SaaS layout at 1200px or wider, mobile on a phone) and
37
+ a device-width viewport, undone at unmount, since DSM's page has no
38
+ device-width viewport. Its full-page sidebar names the App with
39
+ `ctx.displayName` and `ctx.appIcon` (without them the page title and icon) and
40
+ shows the signed-in DSM account and its role from `ctx.user`. See the ui's
41
+ `docs/adaptive-layout.md`.
42
+ `AppShell`'s `app-root` wraps it in an app-local `AppRoot` (app modal scope, on
43
+ a full page as well, bounded at `height: 100%`) with the UI locale from
44
+ `locale`; do not add another `AppRoot`.
45
+ In a DSM window (not a full page) that `AppRoot` takes
41
46
  `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.
47
+ pressing one calls `ctx.host.activateWindow()` to bring the window to the
48
+ front. Elsewhere Dialogs stay inside the App. A confirmed sign-in need sets
49
+ `denied`: the `#denied` slot's `LoginPage` takes the place of the App's pages.
44
50
  Import `themes/dsm7-embedded.css` and assign each mount a unique
45
51
  `app.config.idPrefix` before mounting.
46
52
 
47
53
  Start with AGENTS.md, `synopkgland skill list` and `synopkgland skill path`.
48
- Read `synopkgland skill show ui-vue` for direct Vue component work and
49
- `synopkgland skill show ui-json` for optional declarative specs and their
50
- validate/render workflow. The existing host/backend lifecycle remains in place.
51
-
52
- For UI discovery, run `npx --no syno-pkg-land-ui catalog --json` and
54
+ Read `synopkgland skill show ui-vue` for direct Vue component work. For UI
55
+ discovery, run `npx --no syno-pkg-land-ui catalog --json` and
53
56
  `npx --no syno-pkg-land-ui describe Button --json` from the installed frontend.
54
- Read its prompt and exported Vue docs/types before choosing component APIs.
55
- Use `syno-pkg-land-ui` directly in npm scripts; keep AI guidance version-independent.
@@ -1,207 +0,0 @@
1
- Native Rust package build dependencies (crates linked into the backend binaries)
2
-
3
- syno-pkg-land-sdk v0.9.9 (MIT)
4
-
5
- MIT License
6
-
7
- Copyright (c) 2026 synopkgland
8
-
9
- Permission is hereby granted, free of charge, to any person obtaining a copy
10
- of this software and associated documentation files (the "Software"), to deal
11
- in the Software without restriction, including without limitation the rights
12
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
- copies of the Software, and to permit persons to whom the Software is
14
- furnished to do so, subject to the following conditions:
15
-
16
- The above copyright notice and this permission notice shall be included in all
17
- copies or substantial portions of the Software.
18
-
19
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
- SOFTWARE.
26
-
27
- itoa v1.0.18 (MIT OR Apache-2.0; used under MIT)
28
-
29
- Permission is hereby granted, free of charge, to any
30
- person obtaining a copy of this software and associated
31
- documentation files (the "Software"), to deal in the
32
- Software without restriction, including without
33
- limitation the rights to use, copy, modify, merge,
34
- publish, distribute, sublicense, and/or sell copies of
35
- the Software, and to permit persons to whom the Software
36
- is furnished to do so, subject to the following
37
- conditions:
38
-
39
- The above copyright notice and this permission notice
40
- shall be included in all copies or substantial portions
41
- of the Software.
42
-
43
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
44
- ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
45
- TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
46
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
47
- SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
48
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
49
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
50
- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
51
- DEALINGS IN THE SOFTWARE.
52
-
53
- libc v0.2.190 (MIT OR Apache-2.0; used under MIT)
54
-
55
- Copyright (c) The Rust Project Developers
56
-
57
- Permission is hereby granted, free of charge, to any
58
- person obtaining a copy of this software and associated
59
- documentation files (the "Software"), to deal in the
60
- Software without restriction, including without
61
- limitation the rights to use, copy, modify, merge,
62
- publish, distribute, sublicense, and/or sell copies of
63
- the Software, and to permit persons to whom the Software
64
- is furnished to do so, subject to the following
65
- conditions:
66
-
67
- The above copyright notice and this permission notice
68
- shall be included in all copies or substantial portions
69
- of the Software.
70
-
71
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
72
- ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
73
- TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
74
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
75
- SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
76
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
77
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
78
- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
79
- DEALINGS IN THE SOFTWARE.
80
-
81
- memchr v2.8.3 (Unlicense OR MIT; used under MIT)
82
-
83
- The MIT License (MIT)
84
-
85
- Copyright (c) 2015 Andrew Gallant
86
-
87
- Permission is hereby granted, free of charge, to any person obtaining a copy
88
- of this software and associated documentation files (the "Software"), to deal
89
- in the Software without restriction, including without limitation the rights
90
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91
- copies of the Software, and to permit persons to whom the Software is
92
- furnished to do so, subject to the following conditions:
93
-
94
- The above copyright notice and this permission notice shall be included in
95
- all copies or substantial portions of the Software.
96
-
97
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
98
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
99
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
100
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
101
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
102
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
103
- THE SOFTWARE.
104
-
105
- serde v1.0.229 (MIT OR Apache-2.0; used under MIT)
106
-
107
- Permission is hereby granted, free of charge, to any
108
- person obtaining a copy of this software and associated
109
- documentation files (the "Software"), to deal in the
110
- Software without restriction, including without
111
- limitation the rights to use, copy, modify, merge,
112
- publish, distribute, sublicense, and/or sell copies of
113
- the Software, and to permit persons to whom the Software
114
- is furnished to do so, subject to the following
115
- conditions:
116
-
117
- The above copyright notice and this permission notice
118
- shall be included in all copies or substantial portions
119
- of the Software.
120
-
121
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
122
- ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
123
- TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
124
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
125
- SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
126
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
127
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
128
- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
129
- DEALINGS IN THE SOFTWARE.
130
-
131
- serde_core v1.0.229 (MIT OR Apache-2.0; used under MIT)
132
-
133
- Permission is hereby granted, free of charge, to any
134
- person obtaining a copy of this software and associated
135
- documentation files (the "Software"), to deal in the
136
- Software without restriction, including without
137
- limitation the rights to use, copy, modify, merge,
138
- publish, distribute, sublicense, and/or sell copies of
139
- the Software, and to permit persons to whom the Software
140
- is furnished to do so, subject to the following
141
- conditions:
142
-
143
- The above copyright notice and this permission notice
144
- shall be included in all copies or substantial portions
145
- of the Software.
146
-
147
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
148
- ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
149
- TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
150
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
151
- SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
152
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
153
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
154
- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
155
- DEALINGS IN THE SOFTWARE.
156
-
157
- serde_json v1.0.154 (MIT OR Apache-2.0; used under MIT)
158
-
159
- Permission is hereby granted, free of charge, to any
160
- person obtaining a copy of this software and associated
161
- documentation files (the "Software"), to deal in the
162
- Software without restriction, including without
163
- limitation the rights to use, copy, modify, merge,
164
- publish, distribute, sublicense, and/or sell copies of
165
- the Software, and to permit persons to whom the Software
166
- is furnished to do so, subject to the following
167
- conditions:
168
-
169
- The above copyright notice and this permission notice
170
- shall be included in all copies or substantial portions
171
- of the Software.
172
-
173
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
174
- ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
175
- TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
176
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
177
- SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
178
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
179
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
180
- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
181
- DEALINGS IN THE SOFTWARE.
182
-
183
- zmij v1.0.23 (MIT)
184
-
185
- Permission is hereby granted, free of charge, to any
186
- person obtaining a copy of this software and associated
187
- documentation files (the "Software"), to deal in the
188
- Software without restriction, including without
189
- limitation the rights to use, copy, modify, merge,
190
- publish, distribute, sublicense, and/or sell copies of
191
- the Software, and to permit persons to whom the Software
192
- is furnished to do so, subject to the following
193
- conditions:
194
-
195
- The above copyright notice and this permission notice
196
- shall be included in all copies or substantial portions
197
- of the Software.
198
-
199
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
200
- ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
201
- TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
202
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
203
- SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
204
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
205
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
206
- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
207
- DEALINGS IN THE SOFTWARE.