@verentis/sdk 0.1.1 → 0.2.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.
package/README.md CHANGED
@@ -10,6 +10,112 @@ 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
+
48
+ ### Hosted header actions (SDK 0.2)
49
+
50
+ Applications register buttons after `await client.whenReady()`. The workspace owns their
51
+ presentation; handlers execute inside the application with its existing delegated token.
52
+
53
+ ```ts
54
+ const save = client.bridge!.registerAction({
55
+ id: 'document.save',
56
+ label: 'Save',
57
+ icon: 'lucide:save',
58
+ variant: 'default',
59
+ scopes: ['node.file.read', 'node.node.create', 'node.node.update', 'node.journal.create'],
60
+ enabled: false,
61
+ }, async () => {
62
+ await persistDocument()
63
+ })
64
+
65
+ // Pass the complete descriptor when document state changes.
66
+ save.update({ id: 'document.save', label: 'Save', scopes: [
67
+ 'node.file.read', 'node.node.create', 'node.node.update', 'node.journal.create',
68
+ ], enabled: true })
69
+ save.dispose()
70
+ ```
71
+
72
+ Use stable app-local IDs, up to 16 actions, Lucide icon identifiers, and explicit `scopes`
73
+ (`[]` for client-only operations). `enabled`, `visible`, `busy`, and `disabledReason` communicate
74
+ state without serializing handlers. The host checks required scopes against the delegated grant;
75
+ registration never expands permissions. Throw on failure so the host can display it.
76
+
77
+ For clipboard actions, set `kind: 'clipboard'` and return `{ clipboardText: source }`. The host starts
78
+ the clipboard write in the user's click gesture while awaiting the text, preserving browser
79
+ user-activation requirements. For operations that navigate after completion, return
80
+ `{ navigate: { path: '/applications', newTab: false } }` instead of navigating before the result.
81
+
82
+ The protocol uses session-bound `verentis:actions:set`, `verentis:action:invoke`, and
83
+ `verentis:action:result` messages. Reload/navigation disposes pending work; an unanswered invocation
84
+ times out as **outcome unknown**, never an automatic retry. App handlers must not report successful
85
+ completion before their mutation finishes.
86
+
87
+ Migrated actions are hosted only: there is no legacy-host or standalone-toolbar fallback.
88
+ Fullscreen apps can hide the host header only when they register no actions. Keep specialized
89
+ controls (zoom, editing modes, contextual forms) within the app.
90
+
91
+ Release the 0.2 SDK before deploying apps that require `^0.2.0`, together with the matching host.
92
+ Local sibling-repository development can link the built SDK; published applications must resolve
93
+ the released SDK from npm.
94
+
95
+ ### WOPI editor launch
96
+
97
+ Signed WOPI applications use `Bridge.requestWopiLaunch()` after `waitForInit()`.
98
+ The authenticated workspace parent chooses the installed editor, document,
99
+ branch and action; the child cannot request arbitrary document identities.
100
+ The returned token is scoped to WOPI and is not a normal workspace API token.
101
+ Submit it using a form POST to the validated discovery action, never a URL.
102
+
103
+ `requestWopiSave(generation)`, `getWopiStatus()` and `closeWopiSession()` use the
104
+ same exact-parent, origin/session/request-correlated bridge. A matching durable
105
+ save receipt—not a CODE postMessage alone—is required before clearing dirty state.
106
+ When status reports `continuationAvailable`, `requestWopiContinuation()` asks
107
+ the parent to bind the target of a completed server-owned Save As operation.
108
+ It accepts no document or acquisition IDs. Its `WopiContinuation` result contains
109
+ only document metadata and the persisted target `accessTokenTtl`, not a token,
110
+ action URL or private control credential. The parent obtains the exact existing
111
+ control IDs from authenticated `/derived`; it does not reconstruct a launch,
112
+ including after signing-key rotation. Keep the initial launch/form separate from
113
+ active document metadata, retain CODE's iframe and existing token, and preserve
114
+ unverified edits until a matching target save receipt arrives.
115
+ These methods do not replace `requestBackendCredential()` or ordinary OAuth
116
+ authentication for apps that need workspace APIs. WOPI-only packages need no
117
+ per-editor OAuth client secret.
118
+
13
119
  ### Standalone mode (local development)
14
120
 
15
121
  ```ts
@@ -79,6 +185,36 @@ credentials and `workspaceId` yourself.
79
185
 
80
186
  ## API Overview
81
187
 
188
+ ### Revision-safe node content
189
+
190
+ Use stable node IDs and an explicit branch for editing existing records. Read bytes and their
191
+ strong revision together; submit that revision and a caller-owned idempotency key when saving:
192
+
193
+ ```ts
194
+ const snapshot = await client.files.readNodeContent(nodeId, { branch: 'main' })
195
+ const next = await client.files.writeNodeContent(nodeId, {
196
+ branch: 'main',
197
+ revision: snapshot.revision,
198
+ idempotencyKey: crypto.randomUUID(),
199
+ content: editedJson,
200
+ })
201
+ ```
202
+
203
+ `getNode(nodeId, { branch })` returns stable metadata, including its unquoted `etag`, which
204
+ `writeNodeContent` also accepts. Node-content writes replace bytes only; they do not create files,
205
+ move paths or change MIME types. Keep the same revision, bytes and operation key for an identical
206
+ retry; a new edit needs a new key. The SDK does not automatically retry or report a stale save as
207
+ successful. `ApiError` is a runtime export and exposes `status`, `detail`, optional `title` and the
208
+ platform's optional machine-readable `code` (for example `revision_mismatch`).
209
+
210
+ Path deletion uses `remove({ path, branch, headStamp?, idempotencyKey?, mode? })` with the routed
211
+ file API. `headStamp` is a **path-binding head stamp**, not the quoted node-content revision.
212
+ The default mode is shallow; request `deep` explicitly for recursive deletion. These options
213
+ do not bypass server authorization or mutation guards and do not introduce financial transactions.
214
+
215
+ Deploy only with a platform release providing the conditional node-content routes. New app
216
+ contracts must not assume a locally present feature-branch API is already deployed.
217
+
82
218
  | Export | Description |
83
219
  | --- | --- |
84
220
  | `createVerentisClient(options?)` | Factory function — creates a configured `VerentisClient` |
@@ -131,15 +267,14 @@ npm run typecheck
131
267
 
132
268
  ## Versioning
133
269
 
134
- This project uses [GitVersion](https://gitversion.net/) for automatic semantic versioning:
270
+ The release workflow publishes the exact stable version in `package.json` after changes
271
+ merge to `main`. Update both `package.json` and `package-lock.json` when preparing a new
272
+ version; npm versions are immutable.
135
273
 
136
- - Commits to `main` produce clean versions (e.g., `0.1.1`, `0.1.2`)
137
- - Feature branches produce pre-release versions (e.g., `0.2.0-my-feature.1`)
138
- - Use commit message tags to control version bumps:
139
- - `+semver: breaking` or `+semver: major` — major bump
140
- - `+semver: feature` or `+semver: minor` — minor bump
141
- - `+semver: fix` or `+semver: patch` — patch bump (default)
142
- - `+semver: none` or `+semver: skip` — no bump
274
+ A version older than the current npm `latest` is published under `version-<version>`
275
+ without moving `latest` backwards. Consumers of such a release must install its exact
276
+ version (for example, `npm install @verentis/sdk@0.2.0 --save-exact`), not a caret range
277
+ that can resolve to a different release.
143
278
 
144
279
  ## License
145
280