@verentis/sdk 0.2.4 → 0.2.5
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 +138 -11
- package/dist/index.cjs +594 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +621 -88
- package/dist/index.d.ts +621 -88
- package/dist/index.js +582 -66
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,41 @@ npm install @verentis/sdk
|
|
|
10
10
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
|
+
### Consented Marketplace installation graphs
|
|
14
|
+
|
|
15
|
+
Installation administration uses a **workspace-bound user token**, not an iframe's delegated
|
|
16
|
+
app token or an API key. The token needs `marketplace.install.create` for preview/install and
|
|
17
|
+
`marketplace.install.read` for outcomes, plus the Node/Resource installer scopes documented by
|
|
18
|
+
Marketplace. Explicit recovery also needs `marketplace.install.update` and `node.file.delete`.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
const preview = await client.installations.preview(invoicingPackageId, {
|
|
22
|
+
packageVersion: '1.0.0',
|
|
23
|
+
branch: 'main',
|
|
24
|
+
})
|
|
25
|
+
// Display ALL preview.packages: publisher, version, treeDigest, permissions,
|
|
26
|
+
// manifestYaml, installMode, branch, installPaths, reuse/recovery IDs.
|
|
27
|
+
// Only after the user explicitly agrees to this exact displayed preview:
|
|
28
|
+
const result = await client.installations.install(preview, true)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`preview()` does not install or grant capability authority. Dependencies use canonical
|
|
32
|
+
`publisher/package-id` identities and exact SemVer pins; optional CRM is never implicit.
|
|
33
|
+
`install()` consumes the exact stored fingerprint once. Stale graphs, changed live package
|
|
34
|
+
content/permissions/signing or withdrawn eligibility are rejected, never silently expanded.
|
|
35
|
+
HTTP failures propagate as the existing `ApiError`, including their response body.
|
|
36
|
+
|
|
37
|
+
After a failure or lost response, inspect
|
|
38
|
+
`await client.installations.graphResult(preview.operationId)` instead of repeating `install()`.
|
|
39
|
+
The durable result includes the exact package baseline and per-package outcomes/ledger IDs.
|
|
40
|
+
Installation is not atomic: installed/shared dependencies and retained data are not rolled back.
|
|
41
|
+
A Failed exact target needs a **new** preview and explicit recovery consent; uncertain
|
|
42
|
+
Installing/Updating targets require ledger/operator investigation.
|
|
43
|
+
Dependency-free `update()` / `uninstall()` remain available; updates cannot bypass declared
|
|
44
|
+
dependency consent. WOPI, hosted services and transactional email retain their separate
|
|
45
|
+
verified capability-consent flows. A graph checkbox or unsigned Canvas document is not
|
|
46
|
+
signature proof or financial/email authority.
|
|
47
|
+
|
|
13
48
|
### Hosted header actions (SDK 0.2)
|
|
14
49
|
|
|
15
50
|
Applications register buttons after `await client.whenReady()`. The workspace owns their
|
|
@@ -53,6 +88,34 @@ Migrated actions are hosted only: there is no legacy-host or standalone-toolbar
|
|
|
53
88
|
Fullscreen apps can hide the host header only when they register no actions. Keep specialized
|
|
54
89
|
controls (zoom, editing modes, contextual forms) within the app.
|
|
55
90
|
|
|
91
|
+
### Host messages (agent → open app)
|
|
92
|
+
|
|
93
|
+
An agent acting for the user can send structured messages to an app the user has open (the
|
|
94
|
+
`app_send_message` AI tool). Declare each channel in the manifest so agents can discover it and the
|
|
95
|
+
host forwards nothing else:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
spec:
|
|
99
|
+
messages:
|
|
100
|
+
- channel: select-record # ^[a-z0-9][a-z0-9._-]{0,63}$
|
|
101
|
+
description: Selects a CRM record by id.
|
|
102
|
+
schema: { type: object, properties: { id: { type: string } }, required: [id] }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
const stop = client.bridge!.onHostMessage('select-record', async (payload) => {
|
|
107
|
+
const { id } = payload as { id: string }
|
|
108
|
+
await selectRecord(id)
|
|
109
|
+
return { selected: id } // the reply the agent receives (keep it small JSON)
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Treat payloads as untrusted input and validate them against your schema. Throw to report a
|
|
114
|
+
failure. The protocol uses session-bound `verentis:host:message` / `verentis:host:reply` messages
|
|
115
|
+
with a correlation `requestId`; replays are ignored and undeclared or unhandled channels get an error
|
|
116
|
+
reply. Messages are only delivered while the user has "Follow agent" on or accepts the suggestion,
|
|
117
|
+
and the host waits about 15 seconds for a reply.
|
|
118
|
+
|
|
56
119
|
Release the 0.2 SDK before deploying apps that require `^0.2.0`, together with the matching host.
|
|
57
120
|
Local sibling-repository development can link the built SDK; published applications must resolve
|
|
58
121
|
the released SDK from npm.
|
|
@@ -77,9 +140,44 @@ control IDs from authenticated `/derived`; it does not reconstruct a launch,
|
|
|
77
140
|
including after signing-key rotation. Keep the initial launch/form separate from
|
|
78
141
|
active document metadata, retain CODE's iframe and existing token, and preserve
|
|
79
142
|
unverified edits until a matching target save receipt arrives.
|
|
80
|
-
These methods do not replace
|
|
81
|
-
|
|
82
|
-
|
|
143
|
+
These methods do not replace ordinary OAuth authentication for apps whose
|
|
144
|
+
backend needs workspace APIs. WOPI-only packages need no per-editor OAuth
|
|
145
|
+
client secret.
|
|
146
|
+
|
|
147
|
+
### App backends (OAuth 2.0 Token Exchange)
|
|
148
|
+
|
|
149
|
+
An installed app's backend is an ordinary confidential OAuth client. The iframe
|
|
150
|
+
forwards the user's current, file-scoped access token to its own backend; the
|
|
151
|
+
backend exchanges it on behalf of the user (RFC 8693) at Security's token
|
|
152
|
+
endpoint. The installation's approved permissions are the consent: the exchange
|
|
153
|
+
is refused for a backend client the workspace has not approved, and it can
|
|
154
|
+
never widen the user's scopes or resource.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
// iframe
|
|
158
|
+
const authorization = await client.getAuthorizationHeader()
|
|
159
|
+
await fetch('https://backend.example.com/convert', {
|
|
160
|
+
method: 'POST',
|
|
161
|
+
headers: { Authorization: authorization! },
|
|
162
|
+
body: JSON.stringify({ nodeId: client.context.file?.nodeId }),
|
|
163
|
+
})
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```http
|
|
167
|
+
POST /connect/token
|
|
168
|
+
Authorization: Basic base64(client_id:client_secret)
|
|
169
|
+
Content-Type: application/x-www-form-urlencoded
|
|
170
|
+
|
|
171
|
+
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
|
|
172
|
+
&subject_token=<forwarded access token>
|
|
173
|
+
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
|
|
174
|
+
&scope=node.file.read
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The issued token carries an `act` claim naming the backend client. Add
|
|
178
|
+
`offline_access` (or `requested_token_type=urn:ietf:params:oauth:token-type:refresh_token`)
|
|
179
|
+
when the backend must keep working after the user leaves; every refresh is
|
|
180
|
+
re-authorized against the installation's live consent.
|
|
83
181
|
|
|
84
182
|
### Standalone mode (local development)
|
|
85
183
|
|
|
@@ -150,6 +248,36 @@ credentials and `workspaceId` yourself.
|
|
|
150
248
|
|
|
151
249
|
## API Overview
|
|
152
250
|
|
|
251
|
+
### Revision-safe node content
|
|
252
|
+
|
|
253
|
+
Use stable node IDs and an explicit branch for editing existing records. Read bytes and their
|
|
254
|
+
strong revision together; submit that revision and a caller-owned idempotency key when saving:
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
const snapshot = await client.files.readNodeContent(nodeId, { branch: 'main' })
|
|
258
|
+
const next = await client.files.writeNodeContent(nodeId, {
|
|
259
|
+
branch: 'main',
|
|
260
|
+
revision: snapshot.revision,
|
|
261
|
+
idempotencyKey: crypto.randomUUID(),
|
|
262
|
+
content: editedJson,
|
|
263
|
+
})
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
`getNode(nodeId, { branch })` returns stable metadata, including its unquoted `etag`, which
|
|
267
|
+
`writeNodeContent` also accepts. Node-content writes replace bytes only; they do not create files,
|
|
268
|
+
move paths or change MIME types. Keep the same revision, bytes and operation key for an identical
|
|
269
|
+
retry; a new edit needs a new key. The SDK does not automatically retry or report a stale save as
|
|
270
|
+
successful. `ApiError` is a runtime export and exposes `status`, `detail`, optional `title` and the
|
|
271
|
+
platform's optional machine-readable `code` (for example `revision_mismatch`).
|
|
272
|
+
|
|
273
|
+
Path deletion uses `remove({ path, branch, headStamp?, idempotencyKey?, mode? })` with the routed
|
|
274
|
+
file API. `headStamp` is a **path-binding head stamp**, not the quoted node-content revision.
|
|
275
|
+
The default mode is shallow; request `deep` explicitly for recursive deletion. These options
|
|
276
|
+
do not bypass server authorization or mutation guards and do not introduce financial transactions.
|
|
277
|
+
|
|
278
|
+
Deploy only with a platform release providing the conditional node-content routes. New app
|
|
279
|
+
contracts must not assume a locally present feature-branch API is already deployed.
|
|
280
|
+
|
|
153
281
|
| Export | Description |
|
|
154
282
|
| --- | --- |
|
|
155
283
|
| `createVerentisClient(options?)` | Factory function — creates a configured `VerentisClient` |
|
|
@@ -202,15 +330,14 @@ npm run typecheck
|
|
|
202
330
|
|
|
203
331
|
## Versioning
|
|
204
332
|
|
|
205
|
-
|
|
333
|
+
The release workflow publishes the exact stable version in `package.json` after changes
|
|
334
|
+
merge to `main`. Update both `package.json` and `package-lock.json` when preparing a new
|
|
335
|
+
version; npm versions are immutable.
|
|
206
336
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
- `+semver: feature` or `+semver: minor` — minor bump
|
|
212
|
-
- `+semver: fix` or `+semver: patch` — patch bump (default)
|
|
213
|
-
- `+semver: none` or `+semver: skip` — no bump
|
|
337
|
+
A version older than the current npm `latest` is published under `version-<version>`
|
|
338
|
+
without moving `latest` backwards. Consumers of such a release must install its exact
|
|
339
|
+
version (for example, `npm install @verentis/sdk@0.2.0 --save-exact`), not a caret range
|
|
340
|
+
that can resolve to a different release.
|
|
214
341
|
|
|
215
342
|
## License
|
|
216
343
|
|