@synopackageland/sdk 0.10.2 → 0.10.3

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 (47) hide show
  1. package/README.md +77 -5
  2. package/dist/i18n/background/zh-CN.json +6 -6
  3. package/dist/i18n/delegate/de.json +5 -3
  4. package/dist/i18n/delegate/en.json +5 -3
  5. package/dist/i18n/delegate/es.json +5 -3
  6. package/dist/i18n/delegate/fr.json +5 -3
  7. package/dist/i18n/delegate/it.json +5 -3
  8. package/dist/i18n/delegate/ja.json +5 -3
  9. package/dist/i18n/delegate/ko.json +5 -3
  10. package/dist/i18n/delegate/zh-CN.json +5 -3
  11. package/dist/i18n/delegate/zh-TW.json +5 -3
  12. package/dist/i18n/identity/zh-CN.json +5 -5
  13. package/dist/i18n/save/de.json +15 -17
  14. package/dist/i18n/save/en.json +15 -17
  15. package/dist/i18n/save/es.json +15 -17
  16. package/dist/i18n/save/fr.json +15 -17
  17. package/dist/i18n/save/it.json +15 -17
  18. package/dist/i18n/save/ja.json +15 -17
  19. package/dist/i18n/save/ko.json +15 -17
  20. package/dist/i18n/save/zh-CN.json +15 -17
  21. package/dist/i18n/save/zh-TW.json +15 -17
  22. package/dist/index.js +2355 -2348
  23. package/dist/native.js +350 -0
  24. package/dist/src/delegate/BackgroundSavePanel.vue.d.ts +3 -0
  25. package/dist/src/delegate/BackgroundSaveSettings.vue.d.ts +29 -0
  26. package/dist/src/delegate/ExecutorSettings.vue.d.ts +1 -2
  27. package/dist/src/delegate/copy.d.ts +10 -6
  28. package/dist/src/delegate/executor-setup.d.ts +2 -0
  29. package/dist/src/delegate/save-copy.d.ts +30 -36
  30. package/dist/src/delegate/use-executor-setup.d.ts +5 -1
  31. package/dist/src/delegate/use-scope-approval.d.ts +50 -0
  32. package/dist/src/dsm/file-station.d.ts +1 -1
  33. package/dist/src/native/authorization-runtime.d.ts +2 -0
  34. package/dist/src/native/dsm-version.d.ts +6 -0
  35. package/dist/src/native/root-runtime.d.ts +34 -0
  36. package/dist/src/native.d.ts +2 -0
  37. package/dist/src/protocol/v1.d.ts +7 -1
  38. package/dist/src/shell/PageActions.vue.d.ts +13 -0
  39. package/dist/src/shell/app-pages.d.ts +2 -0
  40. package/dist/src/shell/page-actions.d.ts +3 -0
  41. package/dist/src/vue.d.ts +2 -0
  42. package/dist/style.css +1 -1
  43. package/dist/vue.js +1998 -1735
  44. package/package.json +7 -3
  45. package/spec/protocol/v1/README.md +86 -5
  46. package/spec/protocol/v1/errors.json +8 -0
  47. 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.3",
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.5",
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
@@ -78,7 +111,9 @@ and `policy_digest`. With `auth` (since 0.9.6) it also answers `allowed`:
78
111
  whether DSM's Application Privileges let the caller use the App and File
79
112
  Station from `remote_addr`, the check `delegate.create` makes; an invalid
80
113
  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
114
+ executor would refuse is never shown as ready. While a due start step runs
115
+ (see Package start step), `status` answers `ready: false` with `state`
116
+ `"starting"` and both digests. The executor MUST NOT report the SDK version; the binary
82
117
  digest MUST change only when the executor source changes.
83
118
 
84
119
  ## Application Portal
@@ -136,7 +171,7 @@ Every root program, whatever starts it:
136
171
  | Variable | Set for | Value |
137
172
  |---|---|---|
138
173
  | `SYNOPKGLAND_PACKAGE` | all | the package name |
139
- | `SYNOPKGLAND_ROOT_MODE` | all | `run`, `job`, `stop` or `purge` |
174
+ | `SYNOPKGLAND_ROOT_MODE` | all | `run`, `job`, `start`, `stop` or `purge` |
140
175
  | `SYNOPKGLAND_REQUESTED_BY` | run, job | the verified DSM user name |
141
176
  | `SYNOPKGLAND_REQUEST_ID` | run | 64 hex digits, unique per call |
142
177
  | `SYNOPKGLAND_JOB_ID` | job | the job's `job_id` |
@@ -155,11 +190,16 @@ Every root program, whatever starts it:
155
190
  - A program that exits, whatever its status, is a result: `request_id`,
156
191
  `exit_code`, `stderr` and either `output` (UTF-8, in a reply under 64 KiB)
157
192
  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`);
193
+ removes. `staging` is a bare file name, `root-` and 32 lowercase hex
194
+ digits, never a path: the client joins it to the package staging folder,
195
+ `/var/packages/<package>/var/executor-staging`. The executor MUST create
196
+ that folder, owned by the package account with mode 0700, when it is
197
+ missing; a staging folder it cannot use is `ROOT_FAILED` with the message
198
+ `root output staging unavailable`. Past the timeout the process group is killed (`ROOT_TIMEOUT`);
159
199
  output past `max_output` is `limit-exceeded`; a full staging quota is
160
200
  `ROOT_STAGING_FULL`; two running programs make a third `ROOT_BUSY`.
161
201
  - A `root.run` request MAY be up to 1 MiB; the executor answers within 130
162
- seconds and a client SHOULD wait 140.
202
+ seconds and a client SHOULD wait 140 (Timeouts).
163
203
  - `root.run` cannot be canceled: a closed connection does not stop the
164
204
  program, which runs until it exits or its timeout. Work that may be stopped
165
205
  is a root job (`root.start`, `root.jobs.stop`).
@@ -250,7 +290,48 @@ use it), and `stop` otherwise; jobs are canceled with `upgrade` or `stop`
250
290
  accordingly. It runs for at most 30 seconds, only while the approval is live
251
291
  (as for the purge step), its exit and output go to the executor log, and a
252
292
  failure does not stop the stop. `root.run` and `root.start` refuse it with
253
- `POLICY_DENIED`.
293
+ `POLICY_DENIED`, so a policy whose stop or purge entry declares `run` or
294
+ `job` is invalid; the entry is a lifecycle step only, either
295
+ with neither member or as the shorthand digest. Session work takes another
296
+ entry, which may pin the same digest under another name.
297
+
298
+ ## Package start step
299
+
300
+ Since 0.10.3. A policy MAY carry `"start": "<name>"`, naming a `root` entry
301
+ the executor runs once after each install or upgrade, with no session:
302
+
303
+ - The executor MUST run it at the first start of a package version (the
304
+ `version` of the package INFO), after the pins matched. The socket opens first
305
+ and the step runs once the executor has read the
306
+ approval tasks back; until the step ends, `status` answers `ready: false`
307
+ and `state` `"starting"`, and every other request is refused with
308
+ `EXECUTOR_STARTING` (retryable), so no session reaches the App's root work
309
+ while the step runs. Its
310
+ arguments are `install` when the executor has recorded no earlier start,
311
+ and `upgrade` followed by the version recorded before otherwise. Every
312
+ start records its version, also for a policy without the step; a package
313
+ that adds the step in an upgrade therefore gets `upgrade`, except on the
314
+ first start under an executor that predates the record, which is `install`.
315
+ - It runs only while the approval is live (as for the purge step); otherwise
316
+ it MUST log `start root step skipped: not approved` and run at the next
317
+ start. A step cut short because the executor ended also runs again.
318
+ - It runs for at most 60 seconds; its exit and output go to the executor log,
319
+ and the executor MUST become ready whatever it answers. A failure is the result of
320
+ that version: the step does not run again until the next upgrade or
321
+ reinstall, so the program should be idempotent.
322
+ - `status` answers `start_step` for such a policy: `{"state": "pending"}`
323
+ until the step ran for the version being served, then `state` `ok` (exit
324
+ `0`) or `failed`, `reason` (`install` or `upgrade`), `previous_version` for
325
+ an upgrade, `exit` (an exit code, `timeout`, `signal` or `refused`),
326
+ `output` (at most 4 KiB, which the package account can read) and
327
+ `finished_at` (RFC 3339).
328
+ - As for stop and purge, `root.run` and `root.start` refuse it with
329
+ `POLICY_DENIED`, and an entry that declares `run` or `job` makes the policy
330
+ invalid.
331
+
332
+ Because DSM's package start only writes the start request, `postinst`,
333
+ `postupgrade` and `start` scripts run before or while the step runs; they
334
+ MUST NOT expect its result. The App reads it from `status`.
254
335
 
255
336
  ## Root state directory
256
337
 
@@ -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",
@@ -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
+ }