@synopackageland/sdk 0.50.0 → 0.50.1
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.
- package/README.md +27 -12
- package/dist/index.js +709 -668
- package/dist/src/client.d.ts +12 -0
- package/dist/src/dsm/https.d.ts +6 -0
- package/dist/src/dsm/session.d.ts +2 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/vue.js +11 -10
- package/executor-manifest.json +1 -1
- package/package.json +1 -1
- package/spec/protocol/v1/README.md +17 -17
package/dist/src/client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CallOptions } from './context';
|
|
2
|
+
import type { createDsmSession } from './dsm/session.js';
|
|
2
3
|
export interface BatchCall {
|
|
3
4
|
method: string;
|
|
4
5
|
params?: Record<string, unknown>;
|
|
@@ -14,12 +15,23 @@ export type BatchResult<T = unknown> = {
|
|
|
14
15
|
};
|
|
15
16
|
};
|
|
16
17
|
export type Batch = <T = unknown>(calls: readonly BatchCall[], options?: CallOptions) => Promise<BatchResult<T>[]>;
|
|
18
|
+
/** Trusted App metadata, never inferred from method names or request params.
|
|
19
|
+
* Copy effect from the operation registry; classify AI and streaming explicitly. */
|
|
20
|
+
export interface SessionRetryOperation {
|
|
21
|
+
effect: 'read' | 'write' | 'destructive';
|
|
22
|
+
kind: 'rpc' | 'ai' | 'stream';
|
|
23
|
+
}
|
|
24
|
+
export interface SessionRetryOptions {
|
|
25
|
+
session: ReturnType<typeof createDsmSession>;
|
|
26
|
+
operations: Readonly<Record<string, SessionRetryOperation>>;
|
|
27
|
+
}
|
|
17
28
|
export interface ClientOptions {
|
|
18
29
|
endpoint: string;
|
|
19
30
|
token?: () => string | undefined;
|
|
20
31
|
ready?: () => Promise<unknown>;
|
|
21
32
|
fetch?: typeof globalThis.fetch;
|
|
22
33
|
requestTimeout?: number;
|
|
34
|
+
sessionRetry?: SessionRetryOptions;
|
|
23
35
|
}
|
|
24
36
|
/** A same-origin JSON client. Batch results stay independent and ordered. */
|
|
25
37
|
export declare function createClient(options: ClientOptions): {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Context } from '../context';
|
|
2
|
+
/** Optional link for an App's https_required page. PortInfo is administrator
|
|
3
|
+
* only: unknown and ordinary subjects never start discovery. The result opens
|
|
4
|
+
* DSM, not an App route; no query, fragment or credentials are carried across.
|
|
5
|
+
* No result means show instructions, never guess a configured port. */
|
|
6
|
+
export declare function readDsmHttpsURL(ctx: Pick<Context, 'user' | 'files' | 'webApi' | 'requestTimeout'>, pageURL: string, signal?: AbortSignal): Promise<string | undefined>;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* This plain JavaScript factory is also embedded by the CLI into DSM's
|
|
4
4
|
* generated window, so Go-only Apps need no frontend build toolchain.
|
|
5
5
|
* @param {{read: () => string | undefined, write?: (token: string) => void, fetch: typeof globalThis.fetch}} options
|
|
6
|
-
* @returns {{token: () => string | undefined, ready: () => Promise<string | undefined>}}
|
|
6
|
+
* @returns {{token: () => string | undefined, ready: () => Promise<string | undefined>, refresh: (rejected?: string) => Promise<string | undefined>}}
|
|
7
7
|
*/
|
|
8
8
|
export function createDsmSession(options: {
|
|
9
9
|
read: () => string | undefined;
|
|
@@ -12,4 +12,5 @@ export function createDsmSession(options: {
|
|
|
12
12
|
}): {
|
|
13
13
|
token: () => string | undefined;
|
|
14
14
|
ready: () => Promise<string | undefined>;
|
|
15
|
+
refresh: (rejected?: string) => Promise<string | undefined>;
|
|
15
16
|
};
|
package/dist/src/index.d.ts
CHANGED
|
@@ -38,5 +38,6 @@ export * from './protocol/v1';
|
|
|
38
38
|
export { encodeRequest, decodeResponse, type ProtocolAuth, type ProtocolResponse } from './protocol/codec';
|
|
39
39
|
export { appDenial, appRefusal, type AppDenial } from './authorization/refusal';
|
|
40
40
|
export { createEntryCheck, type EntryCheck, type EntryFailure, type EntryMode } from './entry/check';
|
|
41
|
-
export { createClient, type Batch, type BatchCall, type BatchResult, type ClientOptions } from './client';
|
|
41
|
+
export { createClient, type Batch, type BatchCall, type BatchResult, type ClientOptions, type SessionRetryOptions, type SessionRetryOperation } from './client';
|
|
42
42
|
export { readDsmPorts, type DsmPort, type DsmPortRange } from './dsm/service-ports';
|
|
43
|
+
export { readDsmHttpsURL } from './dsm/https';
|
package/dist/vue.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { D as dt, i as Ba } from "./context-DWEbBTIr.js";
|
|
2
2
|
import { c as So } from "./context-DWEbBTIr.js";
|
|
3
3
|
import { appRefusal as va, appDenial as He, delegateCopy as Ue, createDsmFileStation as ct, appLifecycle as Pe, lifecycleRetryDelay as Ca, joinSentences as Oa, lifecycleCopy as Fe, shellCopy as oa, uiLocale as Fa, format as Ge, nasCopy as Ve, nasErrorCopy as qa, saveCopy as $a, saveError as ia, createNasProvider as Ma, labelSeparator as Sa, identityCopy as Ka, backgroundCopy as vt, createBackgroundPickerProvider as ft, backgroundErrorCopy as pt, requestKey as _a, lifecycleRefusal as mt, errorCopy as yt, scopedPicker as bt, authorizationCopy as Ha, createEntryCheck as gt } from "./index.js";
|
|
4
|
-
import { FILE_STATION_APP as Po, LIFECYCLE_RETRY_MAX_MS as To, LIFECYCLE_STARTING_RETRY_MAX_MS as Ao, MAX_LAUNCH_ROUTE as zo, activePage as Ro, authorizationCatalogs as Io, backgroundCatalogs as Uo, bridgeCatalogs as Do, bridgeErrorCopy as Lo, catalogs as No, createBackgroundSaveFacade as Vo, createClient as Bo, createDsmSession as Oo, createFileTransfers as Fo, createPortalAccess as qo, createSharedFolderAccess as Mo, createSharedFolderPermission as Ko, createStandaloneContext as Ho, createStandaloneHost as Xo, decodeResponse as Go, delegateCatalogs as Wo, dsmLaunchURL as Jo, encodeRequest as Yo, fileStationPath as Qo, followLaunchRoute as Zo, identityCatalogs as jo, launchRoute as ei, mergeCatalogs as ai, nasCatalogs as ti, openFileInFileStation as li, openFolderInFileStation as ni, portalCatalogs as si, portalMessages as oi, protocolCodes as ii, protocolOps as ui, protocolSchemas as ri,
|
|
4
|
+
import { FILE_STATION_APP as Po, LIFECYCLE_RETRY_MAX_MS as To, LIFECYCLE_STARTING_RETRY_MAX_MS as Ao, MAX_LAUNCH_ROUTE as zo, activePage as Ro, authorizationCatalogs as Io, backgroundCatalogs as Uo, bridgeCatalogs as Do, bridgeErrorCopy as Lo, catalogs as No, createBackgroundSaveFacade as Vo, createClient as Bo, createDsmSession as Oo, createFileTransfers as Fo, createPortalAccess as qo, createSharedFolderAccess as Mo, createSharedFolderPermission as Ko, createStandaloneContext as Ho, createStandaloneHost as Xo, decodeResponse as Go, delegateCatalogs as Wo, dsmLaunchURL as Jo, encodeRequest as Yo, fileStationPath as Qo, followLaunchRoute as Zo, identityCatalogs as jo, launchRoute as ei, mergeCatalogs as ai, nasCatalogs as ti, openFileInFileStation as li, openFolderInFileStation as ni, portalCatalogs as si, portalMessages as oi, protocolCodes as ii, protocolOps as ui, protocolSchemas as ri, readDsmHttpsURL as di, readDsmPorts as ci, saveCatalogs as vi, sharedFolderAccessFor as fi, sharedFolderCatalogs as pi, sharedFolderMessages as mi, sharedFolderPermissionMessage as yi, shellCatalogs as bi, shellPages as gi, uiLocales as hi } from "./index.js";
|
|
5
5
|
import { inject as ze, ref as y, computed as x, onBeforeUnmount as ke, Comment as ht, Text as kt, Fragment as ee, watch as We, onMounted as xe, defineComponent as ve, openBlock as n, createElementBlock as w, createElementVNode as $, toDisplayString as o, createCommentVNode as b, renderList as me, normalizeClass as Re, createVNode as p, unref as e, createTextVNode as h, createBlock as g, renderSlot as ge, withCtx as s, resolveDynamicComponent as je, normalizeProps as ua, mergeProps as Ea, withModifiers as Je, isRef as ra, provide as Xe, useTemplateRef as Ne, watchEffect as la, useSlots as Xa, guardReactiveProps as za, createSlots as fa, Teleport as Ga, markRaw as _t, h as wt, useId as xt, shallowRef as Ct, onUnmounted as Wa, nextTick as $t } from "vue";
|
|
6
6
|
import { Timer as St, Info as Et, ShieldCheck as Ja, ChevronRight as Ya, LogOut as Pt, ChevronLeft as Tt, RotateCw as At } from "@lucide/vue";
|
|
7
7
|
import { SettingsSection as we, Callout as j, Button as N, SettingsRow as $e, Skeleton as Be, Badge as ea, PathDisplay as Oe, Form as Ye, FormItem as Te, Select as Pa, Input as Ie, Dialog as qe, ensureDeviceViewport as zt, AppRoot as Rt, ConfigProvider as It, PageContent as Ra, PageHeader as Ia, AppLayout as Ut, LoadingArea as Qa, AppSidebar as Dt, AppSidebarUser as Lt, IconButton as sa, AppToolbar as Nt, InfoTip as Za, FileTypeIcon as ha, Breadcrumb as Vt, FilePicker as Bt, TreeView as Ot, DataGrid as Ft, Link as wa, FormActions as pa, Card as Ua, Checkbox as qt, ListItem as Da } from "@synopackageland/ui";
|
|
@@ -4359,21 +4359,22 @@ export {
|
|
|
4359
4359
|
ii as protocolCodes,
|
|
4360
4360
|
ui as protocolOps,
|
|
4361
4361
|
ri as protocolSchemas,
|
|
4362
|
-
di as
|
|
4362
|
+
di as readDsmHttpsURL,
|
|
4363
|
+
ci as readDsmPorts,
|
|
4363
4364
|
_a as requestKey,
|
|
4364
|
-
|
|
4365
|
+
vi as saveCatalogs,
|
|
4365
4366
|
$a as saveCopy,
|
|
4366
4367
|
ia as saveError,
|
|
4367
4368
|
bt as scopedPicker,
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4369
|
+
fi as sharedFolderAccessFor,
|
|
4370
|
+
pi as sharedFolderCatalogs,
|
|
4371
|
+
mi as sharedFolderMessages,
|
|
4372
|
+
yi as sharedFolderPermissionMessage,
|
|
4373
|
+
bi as shellCatalogs,
|
|
4373
4374
|
oa as shellCopy,
|
|
4374
|
-
|
|
4375
|
+
gi as shellPages,
|
|
4375
4376
|
Fa as uiLocale,
|
|
4376
|
-
|
|
4377
|
+
hi as uiLocales,
|
|
4377
4378
|
Gs as useAuthorization,
|
|
4378
4379
|
Mt as useExecutorPreload,
|
|
4379
4380
|
et as useExecutorSetup,
|
package/executor-manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/sdk",
|
|
3
|
-
"version": "0.50.
|
|
3
|
+
"version": "0.50.1",
|
|
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",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Executor protocol v1
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD,
|
|
4
4
|
SHOULD NOT, RECOMMENDED, MAY and OPTIONAL are to be interpreted as described in
|
|
5
5
|
RFC 2119.
|
|
6
6
|
|
|
@@ -30,7 +30,7 @@ the executor against the vectors here.
|
|
|
30
30
|
|
|
31
31
|
## Timeouts
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Every layer between the browser and a root program waits
|
|
34
34
|
longer than the layer it calls, so the inner answer, or the inner refusal,
|
|
35
35
|
arrives before the outer layer gives up. The margin is 10 seconds between
|
|
36
36
|
the executor and its client and between the client and the request; the
|
|
@@ -61,13 +61,13 @@ reasons are recorded in `scripts/timeout-allowlist.json`.
|
|
|
61
61
|
- `op` MUST be one of the ops with a schema in `schema/`. An unknown op is
|
|
62
62
|
`UNKNOWN_OP`; an op outside the approved policy is `POLICY_DENIED`.
|
|
63
63
|
- `auth` is OPTIONAL. When present it MUST contain only `dsm_cookie`,
|
|
64
|
-
`dsm_synotoken` and `remote_addr
|
|
64
|
+
`dsm_synotoken` and `remote_addr`, the browser's address
|
|
65
65
|
(REMOTE_ADDR). DSM's Application Privileges are evaluated for that address;
|
|
66
66
|
an op that checks them MUST be refused with `APP_DENIED` when a present
|
|
67
67
|
`auth` has no usable `remote_addr`. A grant records the `remote_addr` of the
|
|
68
68
|
`delegate.create` that made it (creating it again records the new one), and
|
|
69
|
-
an operation records the address of its `files.moveFromStaging
|
|
70
|
-
|
|
69
|
+
an operation records the address of its `files.moveFromStaging`. A request
|
|
70
|
+
without `auth` under a grant, and the operation's
|
|
71
71
|
background revalidation, are checked from that recorded address; work with no
|
|
72
72
|
recorded address is checked as coming from 127.0.0.1. A present `auth` is
|
|
73
73
|
always treated as caller authentication, never ignored, even when empty. Ops whose schema says
|
|
@@ -112,7 +112,7 @@ reasons are recorded in `scripts/timeout-allowlist.json`.
|
|
|
112
112
|
## Status
|
|
113
113
|
|
|
114
114
|
`status` answers `version` (`"1"`), `ready`, `disabled`, `executor_digest`
|
|
115
|
-
and `policy_digest`. With `auth`
|
|
115
|
+
and `policy_digest`. With `auth` it also answers `allowed`:
|
|
116
116
|
whether DSM's Application Privileges let the caller use the App and File
|
|
117
117
|
Station from `remote_addr`, the check `delegate.create` makes; an invalid
|
|
118
118
|
session is `AUTH_DENIED`. A CGI sends the caller's `auth` so an App the
|
|
@@ -136,7 +136,7 @@ the tasks back itself.
|
|
|
136
136
|
|
|
137
137
|
## Application Portal
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
A policy MAY carry `"portal": {"application": "<display name>",
|
|
140
140
|
"alias": "<default alias>"}` together with both `portal.register` and
|
|
141
141
|
`portal.unregister`; a policy with only some of the three is invalid. The
|
|
142
142
|
executor then registers the App's Application Portal entry the way DSM's
|
|
@@ -169,7 +169,7 @@ packages.
|
|
|
169
169
|
|
|
170
170
|
## Root programs
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
Each `root` entry pins a program by its SHA-256 digest; a bare
|
|
173
173
|
digest is a script `root.run` may run with the defaults. The object form is
|
|
174
174
|
`{"digest", "kind", "schema", "run"}`: `kind` `script` (`root/<name>.sh`) or
|
|
175
175
|
`binary` (`root/<name>`), `schema` a closed JSON Schema subset for its params,
|
|
@@ -223,7 +223,7 @@ Every root program, whatever starts it:
|
|
|
223
223
|
|
|
224
224
|
## Root jobs
|
|
225
225
|
|
|
226
|
-
|
|
226
|
+
`root.start`, `root.jobs.list`, `root.jobs.get` and
|
|
227
227
|
`root.jobs.stop` come together in `operations`. Each requires an administrator
|
|
228
228
|
session whose Application Privileges allow the App, like `root.run`; any such
|
|
229
229
|
administrator sees and stops every job of the package.
|
|
@@ -299,7 +299,7 @@ The job reports on fd 5 and is told to stop on fd 4; both are pipes.
|
|
|
299
299
|
|
|
300
300
|
## Package stop step
|
|
301
301
|
|
|
302
|
-
|
|
302
|
+
A policy MAY carry `"stop": "<name>"`, naming a `root` entry the
|
|
303
303
|
executor runs when the package stops, after its jobs ended, with no session.
|
|
304
304
|
Its argument is `prepare-upgrade` when the package account wrote `upgrade`
|
|
305
305
|
to `var/executor/stop-reason` before the stop request (the
|
|
@@ -315,7 +315,7 @@ entry, which may pin the same digest under another name.
|
|
|
315
315
|
|
|
316
316
|
## Package start step
|
|
317
317
|
|
|
318
|
-
|
|
318
|
+
A policy MAY carry `"start": "<name>"`, naming a `root` entry
|
|
319
319
|
the executor runs once after each install or upgrade, with no session:
|
|
320
320
|
|
|
321
321
|
- The executor MUST run it at the first start of a package version (the
|
|
@@ -353,7 +353,7 @@ MUST NOT expect its result. The App reads it from `status`.
|
|
|
353
353
|
|
|
354
354
|
## Root state directory
|
|
355
355
|
|
|
356
|
-
|
|
356
|
+
A policy with `"root_state": true` gives its root programs a
|
|
357
357
|
directory only root can read: `/volumeN/@synopkgland/<package>`, root:root
|
|
358
358
|
0700, on the volume that holds the package's `var` (DSM's
|
|
359
359
|
`/volumeN/@appdata/<package>`); `/volumeN/@synopkgland` is root:root 0755.
|
|
@@ -366,7 +366,7 @@ the step the executor deletes it for `delete-state` and keeps it for
|
|
|
366
366
|
|
|
367
367
|
## Uninstall purge step
|
|
368
368
|
|
|
369
|
-
|
|
369
|
+
A policy MAY carry `"purge": "<name>"`, naming one of its `root`
|
|
370
370
|
ops as the App's root step at uninstall; any other value makes the policy
|
|
371
371
|
invalid. Approving that policy is the administrator's consent that the op
|
|
372
372
|
runs as root at uninstall, with no session.
|
|
@@ -398,8 +398,8 @@ runs as root at uninstall, with no session.
|
|
|
398
398
|
Application Privileges, scope, directory identity and write permission
|
|
399
399
|
against DSM. A failure the user or an administrator can undo MUST fail only
|
|
400
400
|
that operation and MUST keep the grant: `PERMISSION_DENIED` (the ACL refuses
|
|
401
|
-
the write), `not-found` (the granted folder is not at its path) and
|
|
402
|
-
|
|
401
|
+
the write), `not-found` (the granted folder is not at its path) and
|
|
402
|
+
`APP_DENIED` (an Application Privileges rule refuses the account from
|
|
403
403
|
the checked address). Once the cause is fixed, a new operation under the same
|
|
404
404
|
grant succeeds. Any other revalidation failure (`DELEGATION_DENIED`,
|
|
405
405
|
`INELIGIBLE`, `SCOPE_DENIED`, including a different folder at the granted
|
|
@@ -448,7 +448,7 @@ administrator). Their `dsm_cookie` is the user name and `dsm_synotoken` is
|
|
|
448
448
|
New ops and members are added with a `since` of the SDK release. The protocol
|
|
449
449
|
`v` changes only for an incompatible envelope change.
|
|
450
450
|
|
|
451
|
-
## JSON WebAPI grants
|
|
451
|
+
## JSON WebAPI grants
|
|
452
452
|
|
|
453
453
|
`webapi.call` MUST execute only an exact API/method/version in the grant's named
|
|
454
454
|
`webapi` policy profile, with `runner` fixed to its owner. A profile has `purpose`
|
|
@@ -475,7 +475,7 @@ cannot be confirmed MUST answer `WEBAPI_UNCERTAIN` (nonretryable); client
|
|
|
475
475
|
transport failure MAY also hide a completed operation. Binary/streaming replies
|
|
476
476
|
MUST be refused. These bounds and semantics also apply to until-revoked grants.
|
|
477
477
|
|
|
478
|
-
## Raw WebAPI extension
|
|
478
|
+
## Raw WebAPI extension
|
|
479
479
|
|
|
480
480
|
The JSON-only restriction above applies to the default response mode. An explicit
|
|
481
481
|
`response_type:"raw"` MUST require a positive, approved profile `raw_max_bytes`
|