@manifest-editor/server-vault 2.2.1-cdn.1.2412bf12 → 2.2.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.
Files changed (2) hide show
  1. package/README.md +89 -97
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,136 +1,128 @@
1
- # Vault
1
+ <p align="center">
2
+ <a href="https://github.com/digirati-co-uk/iiif-manifest-editor"><img src="https://raw.githubusercontent.com/digirati-co-uk/iiif-manifest-editor/main/apps/docs/content/img/logo.svg" width="360" alt="Manifest Editor"></a>
3
+ </p>
4
+ <p align="center">
5
+ <a href="https://www.npmjs.com/package/@manifest-editor/server-vault"><img src="https://img.shields.io/npm/v/%40manifest-editor%2Fserver-vault" alt="npm version"></a>
6
+ <a href="https://github.com/digirati-co-uk/iiif-manifest-editor/actions/workflows/build-test.yml"><img src="https://img.shields.io/github/actions/workflow/status/digirati-co-uk/iiif-manifest-editor/build-test.yml?branch=main&amp;label=build" alt="Build status"></a>
7
+ <a href="https://manifest-editor-docs.netlify.app/"><img src="https://img.shields.io/badge/docs-Manifest_Editor-blue" alt="Documentation"></a>
8
+ </p>
2
9
 
10
+ # @manifest-editor/server-vault
3
11
 
12
+ ## Getting started with Manifest Editor
4
13
 
5
- **.vaultfile**
6
- ```
7
- {
8
- "source": { "id": "https://example.org/manifest", "type": "Manifest" },
9
- "resources": {
10
- "https://example.org/manifest": "./manifest.json",
11
- }
12
- }
14
+ For the complete editor, start with [`manifest-editor`](https://www.npmjs.com/package/manifest-editor) and its [installation and integration guide](https://github.com/digirati-co-uk/iiif-manifest-editor/tree/main/packages/manifest-editor#readme). It combines the editor UI, presets, creators, and editing APIs. This package is one part of that workspace.
15
+
16
+ ## About
17
+
18
+ Experimental Node.js WebSocket service for sharing in-memory Vault state between clients.
19
+
20
+ ## Quick start
21
+
22
+ ```sh
23
+ npm install @manifest-editor/server-vault
13
24
  ```
14
25
 
26
+ ```ts
27
+ import { MultiVaultServer } from "@manifest-editor/server-vault";
15
28
 
16
- The server vault will take this optional config and use it to load the manifest from the file system. The instance of
17
- vault will live on the server for a period of time and can be stopped or started.
29
+ const server = new MultiVaultServer();
30
+ server.listen(8081, "127.0.0.1");
31
+ // Clients connect to ws://localhost:8081/vault/demo.
32
+ ```
18
33
 
19
- Multiple clients can then connect to the vault and use the manifest. They can connect as a read-only user or as a
20
- read-write user. The read-write user can make changes to the manifest and save it back to the vault. These changes will
21
- be reflected in the vault and will be available to all users. The changes will also be reflected in the file system
22
- where the manifest is stored.
34
+ This implementation keeps state in memory and does not implement the authentication, durable storage, or GitHub integration described in earlier design notes. Keep this example local; a deployed host must supply its own access controls and persistence.
23
35
 
24
- Vault communicates using atomic actions. These actions are sent to the vault and the vault will respond with the result
25
- of the action. The vault will also broadcast the action to all connected clients. The clients can then update their
26
- state based on the action. If the actions are applied in the same order on all clients then the state of the clients
27
- will be the same.
36
+ ## Architecture and lifecycle
28
37
 
29
- Each action will have a unique id. This id will be used to ensure that the actions are applied in the same order on all
30
- clients. Clients are required to send the previous action id with each action. The vault will then check that the
31
- previous action id matches the last action id that was applied to the vault. If the previous action id does not match
32
- then the action will be rejected. The client will then need to update its state to match the vault and then try again.
38
+ A `MultiVaultServer` owns an HTTP server and a map of named `ServerVault` instances. Each `ServerVault` contains a normal `@iiif/helpers` Vault plus a WebSocket server. The browser uses [`@manifest-editor/client-vault`](../client-vault) to receive the initial state and exchange Vault actions.
33
39
 
34
- ## Post Message communication
40
+ 1. A client connects to `/vault/<id>`.
41
+ 2. The server looks up that ID and creates an empty in-memory Vault if necessary.
42
+ 3. The server sends an `init-response` containing its current IIIF store.
43
+ 4. Clients send atomic Vault actions; the server applies them and broadcasts them to other clients.
44
+ 5. The originating client receives an acknowledgement, or a rejection if applying the action throws.
35
45
 
36
- The server will also host a webpage that can be used to communicate with the vault. This webpage will be loaded in an
37
- iframe on the client. The client will then be able to connect to the vault and send actions to the vault. The vault
38
- will then broadcast the actions to all connected clients. The client will then update its state based on the actions.
46
+ `GET /vault` returns the IDs currently in the server's map. There is no project database or user-specific project listing behind that route.
39
47
 
40
- This allows the client to be a static webpage that can be hosted on any server. The client will not need to be hosted
41
- on the same server as the vault. However, the server will need to allow cross-origin requests from the client, and will
42
- ensure that only select hosts are allowed to connect to the vault.
48
+ ## Start with an existing manifest
43
49
 
44
- For post-message you have the server iframe, communicating to the server via web-sockets and the client application
45
- that has the server in an iframe. When an event originates from the client, the following happens:
50
+ For a local demonstration, seed the server's Vault before clients connect:
46
51
 
47
- - The client sends a message to the server iframe via post-message
48
- - The server iframe sends a message to the server via web-sockets
49
- - The server broadcasts the message to all connected clients via web-sockets
50
- - The server iframe receives the message from the server via web-sockets
51
- - The server iframe sends the message to the other clients via post-message
52
+ ```ts
53
+ import { MultiVaultServer, ServerVault } from "@manifest-editor/server-vault";
52
54
 
53
- When an event originates from the server, the following happens:
54
- - The server sends a message to the server iframe via web-sockets
55
- - The server iframe sends the message to the other clients via post-message
55
+ const server = new MultiVaultServer();
56
+ const shared = new ServerVault();
57
+ await shared.vault.loadManifest("https://wellcomelibrary.org/iiif/b18035723/manifest");
58
+ server.vaults.set("demo", shared);
59
+ server.listen(8081, "127.0.0.1");
60
+ ```
56
61
 
62
+ In a separate browser application:
57
63
 
58
- - ClientPostMessageVault.dispatch() -> sends message to server iframe
59
- - ServerPostMessageVault.dispatch() -> sends message to server
60
- - ServerWebSocketVault.dispatch() -> sends message to all clients
64
+ ```ts
65
+ import { createClientVault } from "@manifest-editor/client-vault";
61
66
 
67
+ const vault = await createClientVault("ws://localhost:8081/vault/demo");
68
+ // Pass this Vault to ManifestEditor or a VaultProvider.
69
+ ```
62
70
 
71
+ The client factory waits for initial state. It does not load a manifest from disk or create a project record on the server. The underlying `shared.vault` is available for server-side loading and serialization, but the server's broadcasts are driven by incoming client messages; do not assume arbitrary server-side Vault mutations are automatically broadcast.
63
72
 
64
- ## GitHub integration
73
+ ## Wire protocol
65
74
 
66
- On the server there will be a GitHub integration. This integration will allow the vault to be connected to a GitHub
67
- repository. The vault will then be able to load the manifest from the GitHub repository. The vault will also be able
68
- to save the manifest to the GitHub repository.
75
+ Messages are JSON. Action messages carry `_id`, `_type`, `_lastActionId`, and `action`; initialisation messages carry the complete IIIF store in `data`.
69
76
 
70
- As changes are made to the manifest the vault will commit the changes to the GitHub repository. The server will also
71
- create a pull request for the changes.
77
+ | Message | Direction | Behavior |
78
+ | --- | --- | --- |
79
+ | `init-request` | Client → server | Request current state. |
80
+ | `init-response` | Server → client | Send the normalised store and action position. |
81
+ | `vault-action` | Client → server → other clients | Apply and distribute a Vault action or batch. |
82
+ | `vault-action-confirmation` | Server → originating client | Acknowledge the action. |
83
+ | `vault-action-rejection` | Server → originating client | Report an action the server could not apply. |
72
84
 
73
- When a client requests a vault instance, the server will create a new branch in the GitHub repository. The vault will
74
- then load the manifest from the new branch. The client will then be able to make changes to the manifest. Alternatively
75
- the client can request a read-only instance of the vault. The client will then be able to view the manifest but will
76
- not be able to make changes to the manifest.
85
+ The older design proposed rejecting actions whose `_lastActionId` does not match the server's current position. The implementation carries that field but **does not enforce this conflict check**. It is not a conflict-resolution protocol or a CRDT. Likewise, the exported `initialise-with-resource`/`empty-vault-response` types should not be read as proof of a complete server-side initialisation flow: the handler currently processes `init-request` and `vault-action`.
77
86
 
78
- Clients can also request an existing branch. The vault will then load the manifest from the existing branch. The client
79
- will then be able to make changes to the manifest. The client will also be able to save the changes to the existing
80
- branch. If other clients are also connected to the vault then they will be able to see the changes that the client has
81
- made.
87
+ ## Connections and cleanup
82
88
 
83
- ## Authentication
89
+ `ServerVaultOptions.pingTimeout` controls the heartbeat interval in milliseconds (default 30,000). Unresponsive clients are terminated. `onClose` runs when the WebSocket server closes, and `await shared.close()` closes that server and clears its timer. Close connected clients and the HTTP server as part of host shutdown too.
84
90
 
85
- On the client the user will be able to login to GitHub through the server. This will be done by opening a popup window served by the server. The user will then be able to login to GitHub and grant the server access to their GitHub account.
86
- Initially this will only be for authentication and will grant access to manifests hosted in SQLite on the server. Eventually
87
- this will also allow the server to access manifests hosted in GitHub repositories.
91
+ Do not rely on the last client disconnecting to persist or automatically dispose of a named Vault. A host should explicitly decide retention, cleanup, and storage policy.
88
92
 
89
- Once logged in the server will redirect back to the client. The client will then be able to use the access token to
90
- create an iFrame that can be used to communicate with the vault.
93
+ ## Iframes and MessagePort previews
91
94
 
92
- ## Listing projects
95
+ The older README described a server-hosted iframe proxying messages between a parent page and WebSockets. That complete transport/proxy service is not implemented here.
93
96
 
94
- Before a client can connect to a vault it will need to know the id of the vault. The client will be able to request a
95
- list of vaults from the server. This is also done using a post message. The server will then respond with a list of
96
- vaults that the user has access to. The client will then be able to connect to the vault.
97
+ There is now a separate browser-side preview path: the shell exports `createIframeVaultBridge(vault, port)`, and client-vault exports `MessagePortClientVault`. The shell bridge sends initial state and host updates but rejects actions from the preview, making it a read-only preview bridge. It returns a cleanup function. The embedding host still has to create/transfer the MessagePort and establish the iframe relationship.
97
98
 
99
+ ## Persistence and hosted collaboration: design notes
98
100
 
99
- ## Server responsibilities and routes
101
+ The original direction remains useful for hosts extending this package, but these features are **not provided by the current server**:
100
102
 
101
- - [ ] Request login status of the user using a post message
102
- - [ ] Request a list of vaults using a post message
103
- - [ ] Request a vault instance using a post message
104
- - [ ] Login via Github in a popup
105
- - [ ] Create a new vault instance
103
+ - A `.vaultfile` mapping a source manifest to files, periodic snapshots, and loading/saving to disk.
104
+ - Authentication, allowed-origin checks, project ownership, and distinct read-only/read-write permissions.
105
+ - Durable action history, reconnect/replay, and rejection/reconciliation of stale edits.
106
+ - GitHub login, repository-backed manifests, editing branches, commits, and pull requests.
107
+ - A user-scoped project API and authenticated iframe bootstrap.
106
108
 
109
+ One proposed file mapping looked like this (a design example, **not** a configuration file this package reads):
107
110
 
108
- 2 new types of Vault instance
111
+ ```json
112
+ {
113
+ "source": { "id": "https://example.org/manifest", "type": "Manifest" },
114
+ "resources": { "https://example.org/manifest": "./manifest.json" }
115
+ }
116
+ ```
109
117
 
110
- - Server vault
111
- - Client vault
118
+ For durable storage, a host could serialize `shared.vault.toPresentation3(reference)` and restore it on startup. For GitHub-backed work, that serialization would become the input to the host's commit/PR workflow. These are integration responsibilities, not automatic behavior of `MultiVaultServer`.
112
119
 
113
- **Server vault**
114
- 1. Creates normal internal vault instance
115
- 2. Loads manifest from file system
116
- 3. Handles client opening and closing connections
117
- 4. Accepts client actions
118
- - Applies action to internal vault instance
119
- - Responds to client with result of action
120
- - Broadcasts action to all connected clients
121
- 5. Saves manifest to file system periodically
120
+ The current implementation accepts Vault actions from connected clients without authentication. Bind a development instance to loopback, as shown above; deploying a collaborative service requires implementing the access and validation boundaries described here.
122
121
 
122
+ ## API overview
123
123
 
124
- **Client vault**
125
- 1. Connects to server vault
126
- - Opens connection
127
- - Loads initial state from server vault, including last action id
128
- 2. Sends actions to server vault
129
- - Includes last action id
130
- - Waits for response from server vault
131
- - Updates state based on response from server vault
132
- - If response is an error then update state to match server vault
133
- - May retry action if response is a conflict
134
- 3. Receives actions from server vault
135
- 4. Applies actions to internal vault instance
124
+ - `MultiVaultServer`: HTTP server, `/vault` listing, and WebSocket upgrades under `/vault/<id>`.
125
+ - `ServerVault`: one shared Vault, action broadcasting, connection heartbeat, and `close()`.
126
+ - `ServerVaultOptions`, `ClientAction`, and `ServerAction`: configuration and message types.
136
127
 
128
+ See the [source exports](https://github.com/digirati-co-uk/iiif-manifest-editor/tree/main/packages/server-vault/src) for the complete API and TypeScript definitions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manifest-editor/server-vault",
3
- "version": "2.2.1-cdn.1.2412bf12",
3
+ "version": "2.2.1",
4
4
  "type": "module",
5
5
  "bugs": "https://github.com/digirati-co-uk/iiif-manifest-editor/issues",
6
6
  "repository": {
@@ -57,5 +57,5 @@
57
57
  "publishConfig": {
58
58
  "access": "public"
59
59
  },
60
- "gitHead": "2412bf12476cf583d14bccf34444dbf8741145b2"
60
+ "gitHead": "903673e7c35feed673fc100cb0efe34733057c91"
61
61
  }