@synopackageland/sdk 0.10.2 → 0.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +77 -5
  2. package/dist/i18n/background/zh-CN.json +7 -7
  3. package/dist/i18n/bridge/de.json +3 -1
  4. package/dist/i18n/bridge/en.json +3 -1
  5. package/dist/i18n/bridge/es.json +3 -1
  6. package/dist/i18n/bridge/fr.json +3 -1
  7. package/dist/i18n/bridge/it.json +3 -1
  8. package/dist/i18n/bridge/ja.json +3 -1
  9. package/dist/i18n/bridge/ko.json +3 -1
  10. package/dist/i18n/bridge/zh-CN.json +3 -1
  11. package/dist/i18n/bridge/zh-TW.json +3 -1
  12. package/dist/i18n/delegate/de.json +5 -3
  13. package/dist/i18n/delegate/en.json +5 -3
  14. package/dist/i18n/delegate/es.json +5 -3
  15. package/dist/i18n/delegate/fr.json +5 -3
  16. package/dist/i18n/delegate/it.json +5 -3
  17. package/dist/i18n/delegate/ja.json +5 -3
  18. package/dist/i18n/delegate/ko.json +5 -3
  19. package/dist/i18n/delegate/zh-CN.json +5 -3
  20. package/dist/i18n/delegate/zh-TW.json +5 -3
  21. package/dist/i18n/identity/zh-CN.json +5 -5
  22. package/dist/i18n/save/de.json +16 -17
  23. package/dist/i18n/save/en.json +16 -17
  24. package/dist/i18n/save/es.json +16 -17
  25. package/dist/i18n/save/fr.json +16 -17
  26. package/dist/i18n/save/it.json +16 -17
  27. package/dist/i18n/save/ja.json +16 -17
  28. package/dist/i18n/save/ko.json +16 -17
  29. package/dist/i18n/save/zh-CN.json +16 -17
  30. package/dist/i18n/save/zh-TW.json +16 -17
  31. package/dist/index.js +2334 -2296
  32. package/dist/native.js +350 -0
  33. package/dist/src/delegate/BackgroundSavePanel.vue.d.ts +3 -0
  34. package/dist/src/delegate/BackgroundSaveSettings.vue.d.ts +42 -0
  35. package/dist/src/delegate/ExecutorSettings.vue.d.ts +1 -2
  36. package/dist/src/delegate/SaveOperations.vue.d.ts +23 -0
  37. package/dist/src/delegate/copy.d.ts +10 -6
  38. package/dist/src/delegate/executor-setup.d.ts +2 -0
  39. package/dist/src/delegate/save-copy.d.ts +33 -36
  40. package/dist/src/delegate/use-executor-setup.d.ts +5 -1
  41. package/dist/src/delegate/use-scope-approval.d.ts +50 -0
  42. package/dist/src/dsm/file-station.d.ts +1 -1
  43. package/dist/src/native/authorization-runtime.d.ts +2 -0
  44. package/dist/src/native/dsm-version.d.ts +6 -0
  45. package/dist/src/native/root-runtime.d.ts +34 -0
  46. package/dist/src/native.d.ts +2 -0
  47. package/dist/src/protocol/v1.d.ts +20 -2
  48. package/dist/src/shell/AppShell.vue.d.ts +3 -0
  49. package/dist/src/shell/PageActions.vue.d.ts +13 -0
  50. package/dist/src/shell/app-pages.d.ts +2 -0
  51. package/dist/src/shell/page-actions.d.ts +3 -0
  52. package/dist/src/vue.d.ts +3 -0
  53. package/dist/style.css +1 -1
  54. package/dist/vue.js +2128 -1809
  55. package/package.json +7 -3
  56. package/spec/protocol/v1/README.md +99 -5
  57. package/spec/protocol/v1/errors.json +24 -0
  58. package/spec/protocol/v1/timeouts.json +21 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synopackageland/sdk",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "description": "Frontend SDK for DSM packages built with synopkgland: headless client and Vue components",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/synopackageland/syno-pkg-land-sdk/tree/main/ts#readme",
@@ -26,6 +26,10 @@
26
26
  "import": "./dist/vue.js"
27
27
  },
28
28
  "./vue/style.css": "./dist/style.css",
29
+ "./native": {
30
+ "types": "./dist/src/native.d.ts",
31
+ "import": "./dist/native.js"
32
+ },
29
33
  "./i18n/*": "./dist/i18n/*"
30
34
  },
31
35
  "files": [
@@ -40,7 +44,7 @@
40
44
  },
41
45
  "peerDependencies": {
42
46
  "@lucide/vue": "^1.48.0",
43
- "@synopackageland/ui": "^0.9.4",
47
+ "@synopackageland/ui": "^0.9.5",
44
48
  "vue": "^3.5.0"
45
49
  },
46
50
  "peerDependenciesMeta": {
@@ -53,7 +57,7 @@
53
57
  },
54
58
  "devDependencies": {
55
59
  "@lucide/vue": "1.48.0",
56
- "@synopackageland/ui": "0.9.4",
60
+ "@synopackageland/ui": "0.9.6",
57
61
  "@types/node": "24.19.2",
58
62
  "@vitejs/plugin-vue": "6.0.9",
59
63
  "jsdom": "27.4.0",
@@ -15,6 +15,7 @@ the executor against the vectors here.
15
15
  | `schema/<op>.json` | JSON Schema (draft 2020-12) of the `params` of each op, with `since` |
16
16
  | `errors.json` | Every code: `code`, `kind`, `retryable`, `httpStatus`, `en`, `zh-TW`. The only source of codes; the Go constants are generated from it |
17
17
  | `vectors/*.jsonl` | One request per line: `{name, request, policy, state, expect}` |
18
+ | `timeouts.json` | The timeouts of the section Timeouts, in seconds; the SDK's constants and tests read it |
18
19
 
19
20
  ## Transport
20
21
 
@@ -27,6 +28,38 @@ the executor against the vectors here.
27
28
  4. The executor MUST answer one line of JSON ending in `\n` and close.
28
29
  5. The executor SHOULD close a connection that sends nothing for 15 seconds.
29
30
 
31
+ ## Timeouts
32
+
33
+ Since 0.10.3. Every layer between the browser and a root program waits
34
+ longer than the layer it calls, so the inner answer, or the inner refusal,
35
+ arrives before the outer layer gives up. The margin is 10 seconds between
36
+ the executor and its client and between the client and the request; the
37
+ browser waits 2 seconds past the request (`timeouts.json` holds the values).
38
+
39
+ | Layer | Waits for | Bound |
40
+ |---|---|---|
41
+ | Root program (`run.timeout_s`) | its own work | 1–120 s, default 20; the process group is then killed |
42
+ | Executor, `root.run` | the program, then its reply | answers within 130 s (120 + 10) |
43
+ | Executor, every other op | its DSM calls | answers within 30 s |
44
+ | Executor client (Go `delegate.Client`, the bridge runtime's `root.*` and `delegate.*`) | the executor | `root.run` 140 s (`delegate.RootRunTimeout`), every other op 40 s (`delegate.ExecutorTimeout`) |
45
+ | Request (`api.Timeout`, manifest `timeout_seconds`) | the App's backend | default 60 s (`api.DefaultRequestTimeout`), 1–3600 |
46
+ | Browser (`clientTimeout`, the CLI window's `call`) | the request | the request's deadline + 2 s |
47
+
48
+ - The request's deadline ends every inner wait: a client never waits past it.
49
+ An App whose backend awaits `root.run` therefore needs a deadline of at
50
+ least the program's `run.timeout_s` + 20 seconds (the executor's 10 and the
51
+ client's 10), so a 120-second program needs `timeout_seconds` 140; a build
52
+ tool SHOULD refuse less. The default 60 covers programs of up to 40 seconds.
53
+ - A client that gave up does not stop the work: `root.run` runs on (it cannot
54
+ be canceled), and `portal.register` and `portal.unregister` finish their
55
+ steps within 2 minutes. The client reads the result again (`status`,
56
+ `root.jobs.get`) instead of repeating the work.
57
+ - The start step (Package start step) is waited on by no request: while it
58
+ runs (at most 60 seconds) every op but `status` is refused at once with
59
+ `EXECUTOR_STARTING` (retryable). A window that waits for the executor to
60
+ become ready polls `status` for longer than 60 seconds before it reports
61
+ the start step as still running.
62
+
30
63
  ## Request
31
64
 
32
65
  ```json
@@ -70,6 +103,19 @@ the executor against the vectors here.
70
103
  as `EXECUTOR_PROTOCOL`, and an unreachable socket as
71
104
  `EXECUTOR_UNAVAILABLE`. Codes of kind `client` are never sent by the
72
105
  executor.
106
+ - A client that knows the package's lifecycle mailbox (`<data
107
+ dir>/executor/control`) answers an unreachable socket with `APP_STOPPED`
108
+ when its last request is `stop`; within 10 seconds of a `start` it waits
109
+ for the socket and ends with `APP_STARTING`. Neither sends a byte, so the
110
+ caller MAY repeat the request.
111
+ - Such a client answers `EXECUTOR_UNAVAILABLE` only for a package that runs
112
+ and was not started in the last 10 seconds, yet whose executor does not
113
+ listen: it is not approved, awaits approval after an upgrade, or failed.
114
+ `retryable` says that nothing was sent, not that waiting helps: a browser
115
+ client repeats `APP_STOPPED`, `APP_STARTING` and `EXECUTOR_STARTING` on its
116
+ own, but shows `EXECUTOR_UNAVAILABLE` as the approval state at once, since
117
+ only an administrator's approval (which also restarts the executor) changes
118
+ it.
73
119
 
74
120
  ## Status
75
121
 
@@ -78,7 +124,9 @@ and `policy_digest`. With `auth` (since 0.9.6) it also answers `allowed`:
78
124
  whether DSM's Application Privileges let the caller use the App and File
79
125
  Station from `remote_addr`, the check `delegate.create` makes; an invalid
80
126
  session is `AUTH_DENIED`. A CGI sends the caller's `auth` so an App the
81
- executor would refuse is never shown as ready. The executor MUST NOT report the SDK version; the binary
127
+ executor would refuse is never shown as ready. While a due start step runs
128
+ (see Package start step), `status` answers `ready: false` with `state`
129
+ `"starting"` and both digests. The executor MUST NOT report the SDK version; the binary
82
130
  digest MUST change only when the executor source changes.
83
131
 
84
132
  ## Application Portal
@@ -136,7 +184,7 @@ Every root program, whatever starts it:
136
184
  | Variable | Set for | Value |
137
185
  |---|---|---|
138
186
  | `SYNOPKGLAND_PACKAGE` | all | the package name |
139
- | `SYNOPKGLAND_ROOT_MODE` | all | `run`, `job`, `stop` or `purge` |
187
+ | `SYNOPKGLAND_ROOT_MODE` | all | `run`, `job`, `start`, `stop` or `purge` |
140
188
  | `SYNOPKGLAND_REQUESTED_BY` | run, job | the verified DSM user name |
141
189
  | `SYNOPKGLAND_REQUEST_ID` | run | 64 hex digits, unique per call |
142
190
  | `SYNOPKGLAND_JOB_ID` | job | the job's `job_id` |
@@ -155,11 +203,16 @@ Every root program, whatever starts it:
155
203
  - A program that exits, whatever its status, is a result: `request_id`,
156
204
  `exit_code`, `stderr` and either `output` (UTF-8, in a reply under 64 KiB)
157
205
  or `staging` and `size`, a package-owned staging file the client reads and
158
- removes. Past the timeout the process group is killed (`ROOT_TIMEOUT`);
206
+ removes. `staging` is a bare file name, `root-` and 32 lowercase hex
207
+ digits, never a path: the client joins it to the package staging folder,
208
+ `/var/packages/<package>/var/executor-staging`. The executor MUST create
209
+ that folder, owned by the package account with mode 0700, when it is
210
+ missing; a staging folder it cannot use is `ROOT_FAILED` with the message
211
+ `root output staging unavailable`. Past the timeout the process group is killed (`ROOT_TIMEOUT`);
159
212
  output past `max_output` is `limit-exceeded`; a full staging quota is
160
213
  `ROOT_STAGING_FULL`; two running programs make a third `ROOT_BUSY`.
161
214
  - A `root.run` request MAY be up to 1 MiB; the executor answers within 130
162
- seconds and a client SHOULD wait 140.
215
+ seconds and a client SHOULD wait 140 (Timeouts).
163
216
  - `root.run` cannot be canceled: a closed connection does not stop the
164
217
  program, which runs until it exits or its timeout. Work that may be stopped
165
218
  is a root job (`root.start`, `root.jobs.stop`).
@@ -250,7 +303,48 @@ use it), and `stop` otherwise; jobs are canceled with `upgrade` or `stop`
250
303
  accordingly. It runs for at most 30 seconds, only while the approval is live
251
304
  (as for the purge step), its exit and output go to the executor log, and a
252
305
  failure does not stop the stop. `root.run` and `root.start` refuse it with
253
- `POLICY_DENIED`.
306
+ `POLICY_DENIED`, so a policy whose stop or purge entry declares `run` or
307
+ `job` is invalid; the entry is a lifecycle step only, either
308
+ with neither member or as the shorthand digest. Session work takes another
309
+ entry, which may pin the same digest under another name.
310
+
311
+ ## Package start step
312
+
313
+ Since 0.10.3. A policy MAY carry `"start": "<name>"`, naming a `root` entry
314
+ the executor runs once after each install or upgrade, with no session:
315
+
316
+ - The executor MUST run it at the first start of a package version (the
317
+ `version` of the package INFO), after the pins matched. The socket opens first
318
+ and the step runs once the executor has read the
319
+ approval tasks back; until the step ends, `status` answers `ready: false`
320
+ and `state` `"starting"`, and every other request is refused with
321
+ `EXECUTOR_STARTING` (retryable), so no session reaches the App's root work
322
+ while the step runs. Its
323
+ arguments are `install` when the executor has recorded no earlier start,
324
+ and `upgrade` followed by the version recorded before otherwise. Every
325
+ start records its version, also for a policy without the step; a package
326
+ that adds the step in an upgrade therefore gets `upgrade`, except on the
327
+ first start under an executor that predates the record, which is `install`.
328
+ - It runs only while the approval is live (as for the purge step); otherwise
329
+ it MUST log `start root step skipped: not approved` and run at the next
330
+ start. A step cut short because the executor ended also runs again.
331
+ - It runs for at most 60 seconds; its exit and output go to the executor log,
332
+ and the executor MUST become ready whatever it answers. A failure is the result of
333
+ that version: the step does not run again until the next upgrade or
334
+ reinstall, so the program should be idempotent.
335
+ - `status` answers `start_step` for such a policy: `{"state": "pending"}`
336
+ until the step ran for the version being served, then `state` `ok` (exit
337
+ `0`) or `failed`, `reason` (`install` or `upgrade`), `previous_version` for
338
+ an upgrade, `exit` (an exit code, `timeout`, `signal` or `refused`),
339
+ `output` (at most 4 KiB, which the package account can read) and
340
+ `finished_at` (RFC 3339).
341
+ - As for stop and purge, `root.run` and `root.start` refuse it with
342
+ `POLICY_DENIED`, and an entry that declares `run` or `job` makes the policy
343
+ invalid.
344
+
345
+ Because DSM's package start only writes the start request, `postinst`,
346
+ `postupgrade` and `start` scripts run before or while the step runs; they
347
+ MUST NOT expect its result. The App reads it from `status`.
254
348
 
255
349
  ## Root state directory
256
350
 
@@ -106,6 +106,14 @@
106
106
  "en": "The executor is paused, for example while the package stops or upgrades.",
107
107
  "zh-TW": "executor 已暫停,例如套件停止或升級期間。"
108
108
  },
109
+ {
110
+ "code": "EXECUTOR_STARTING",
111
+ "kind": "refusal",
112
+ "retryable": true,
113
+ "httpStatus": 503,
114
+ "en": "The executor is running the App's start step after an install or upgrade; status answers state starting until it ends.",
115
+ "zh-TW": "executor 正在執行安裝或升級後的 App start 步驟;結束前 status 回報 state starting。"
116
+ },
109
117
  {
110
118
  "code": "STORAGE_ERROR",
111
119
  "kind": "refusal",
@@ -466,6 +474,22 @@
466
474
  "en": "The client could not connect to the executor socket.",
467
475
  "zh-TW": "用戶端無法連到 executor socket。"
468
476
  },
477
+ {
478
+ "code": "APP_STOPPED",
479
+ "kind": "client",
480
+ "retryable": true,
481
+ "httpStatus": 503,
482
+ "en": "The package is stopped: its lifecycle mailbox asks the executor to stop. The client sent nothing.",
483
+ "zh-TW": "套件已停止:生命週期信箱要求 executor 停止。用戶端沒有送出任何內容。"
484
+ },
485
+ {
486
+ "code": "APP_STARTING",
487
+ "kind": "client",
488
+ "retryable": true,
489
+ "httpStatus": 503,
490
+ "en": "The package was just started and its executor is not listening yet. The client sent nothing.",
491
+ "zh-TW": "套件剛啟動,executor 尚未開始接聽。用戶端沒有送出任何內容。"
492
+ },
469
493
  {
470
494
  "code": "EXECUTOR_TIMEOUT",
471
495
  "kind": "client",
@@ -0,0 +1,21 @@
1
+ {
2
+ "$comment": "Timeouts on the call chain to the executor, in seconds unless the name says ms. Each layer waits margin_s longer than the layer it calls, so the inner answer arrives first; README.md, Timeouts.",
3
+ "margin_s": 10,
4
+ "executor": {
5
+ "op_s": 30,
6
+ "root_run_program_default_s": 20,
7
+ "root_run_program_max_s": 120,
8
+ "root_run_answer_s": 130,
9
+ "start_step_s": 60
10
+ },
11
+ "client": {
12
+ "op_s": 40,
13
+ "root_run_s": 140
14
+ },
15
+ "request": {
16
+ "default_s": 60
17
+ },
18
+ "browser": {
19
+ "margin_ms": 2000
20
+ }
21
+ }