@mp-lb/mdkit 0.2.3-main.20.1 → 0.2.3-main.21.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 (40) hide show
  1. package/dist/core/checkpointPolicy.d.ts +25 -0
  2. package/dist/core/checkpointPolicy.js +45 -0
  3. package/dist/core/index.d.ts +2 -0
  4. package/dist/core/index.js +1 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +1 -0
  7. package/dist/server.d.ts +2 -0
  8. package/dist/server.js +1 -0
  9. package/dist/transport/backend.d.ts +29 -0
  10. package/dist/transport/backend.js +93 -0
  11. package/dist/transport/trpcClient.d.ts +29 -8
  12. package/dist/trpc/client.d.ts +1 -1
  13. package/dist/trpc/server.d.ts +2 -0
  14. package/dist/trpc/server.js +1 -0
  15. package/dist/trpc.d.ts +1 -1
  16. package/docs/.vitepress/cache/deps/@theme_index.js +275 -0
  17. package/docs/.vitepress/cache/deps/@theme_index.js.map +7 -0
  18. package/docs/.vitepress/cache/deps/_metadata.json +40 -0
  19. package/docs/.vitepress/cache/deps/chunk-PM3I3KHC.js +9719 -0
  20. package/docs/.vitepress/cache/deps/chunk-PM3I3KHC.js.map +7 -0
  21. package/docs/.vitepress/cache/deps/chunk-VSHFF4ZG.js +13018 -0
  22. package/docs/.vitepress/cache/deps/chunk-VSHFF4ZG.js.map +7 -0
  23. package/docs/.vitepress/cache/deps/package.json +3 -0
  24. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
  25. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  26. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +583 -0
  27. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  28. package/docs/.vitepress/cache/deps/vue.js +347 -0
  29. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  30. package/docs/.vitepress/config.ts +11 -0
  31. package/docs/api.md +153 -18
  32. package/docs/architecture.md +24 -9
  33. package/docs/collaboration-persistence.md +147 -0
  34. package/docs/index.md +139 -65
  35. package/docs/permissions.md +139 -0
  36. package/docs/rest.md +98 -0
  37. package/docs/shadcn.md +6 -3
  38. package/docs/styling.md +11 -10
  39. package/docs/use-cases.md +148 -0
  40. package/package.json +6 -1
package/docs/rest.md ADDED
@@ -0,0 +1,98 @@
1
+ # REST Backend
2
+
3
+ Use REST when you want the quick-start frontend without tRPC. The editor,
4
+ toolbar, conflict panel, checkpoint panel, and collaboration hook are the same.
5
+ The difference is the backend transport.
6
+
7
+ If your backend uses Fastify, mdkit can register the REST routes for you. If you
8
+ use another server framework, implement the same endpoint shape shown below.
9
+
10
+ ## Frontend Wiring
11
+
12
+ Use the connected frontend from the [Quick Start](./index.md#frontend-with-trpc).
13
+ Keep the same component structure, but change the transport-specific pieces:
14
+
15
+ - replace the tRPC adapter with `createMdKitRestAdapter`, using a REST base URL
16
+ such as `${apiUrl}/mdkit`
17
+ - point collaboration at `${apiUrl.replace(/^http/, "ws")}/mdkit/collaboration`
18
+ - point the restore callback at `POST /mdkit/versions/:versionId/restore`
19
+
20
+ `createMdKitRestAdapter` covers current-document reads, writes, resync,
21
+ checkpoint listing, and checkpoint detail reads. Restore is separate because it
22
+ is not part of `MdKitDocumentAdapter` yet.
23
+
24
+ ## Fastify Backend
25
+
26
+ ```ts
27
+ import cors from "@fastify/cors";
28
+ import websocket from "@fastify/websocket";
29
+ import { Database } from "@hocuspocus/extension-database";
30
+ import { Server } from "@hocuspocus/server";
31
+ import Fastify from "fastify";
32
+ import { CheckpointPolicy } from "@mp-lb/mdkit/core";
33
+ import {
34
+ createMdKitBackend,
35
+ type MdKitBackendStore,
36
+ } from "@mp-lb/mdkit/server";
37
+ import { registerMdKitFastify } from "@mp-lb/mdkit/fastify";
38
+
39
+ const app = Fastify();
40
+ const store: MdKitBackendStore = createYourDocumentStore();
41
+
42
+ const mdkit = createMdKitBackend({
43
+ store,
44
+ checkpointPolicy: CheckpointPolicy.smart(),
45
+ });
46
+
47
+ const collaboration = Server.configure({
48
+ extensions: [
49
+ new Database({
50
+ fetch: ({ documentName }) => mdkit.readCollaborationState(documentName),
51
+ store: ({ documentName, state }) =>
52
+ mdkit.writeCollaborationState(documentName, state),
53
+ }),
54
+ ],
55
+ });
56
+
57
+ await app.register(cors, { origin: true });
58
+ await app.register(websocket);
59
+
60
+ await registerMdKitFastify(app, {
61
+ prefix: "/mdkit",
62
+ store: mdkit,
63
+ });
64
+
65
+ app.get("/mdkit/collaboration", { websocket: true }, (socket, request) => {
66
+ collaboration.handleConnection(socket, request.raw, {});
67
+ });
68
+
69
+ app.addHook("onClose", async () => {
70
+ await collaboration.destroy();
71
+ });
72
+
73
+ await app.listen({ port: Number(process.env.PORT ?? 4312) });
74
+ ```
75
+
76
+ The store object is still your application boundary. It connects mdkit's REST
77
+ routes to your database and owns metadata, permissions, tenancy, and durable
78
+ Yjs storage. Mdkit applies the checkpoint policy and calls your store's
79
+ checkpoint creation method when needed. See
80
+ [`createMdKitBackend`](./api.md#createmdkitbackend).
81
+
82
+ ## Endpoint Shape
83
+
84
+ If you are not using Fastify, implement these routes with your server framework:
85
+
86
+ | Method | Path | Behavior |
87
+ | --- | --- | --- |
88
+ | `GET` | `/mdkit/documents?documentId=...` | Read the current document. |
89
+ | `PUT` | `/mdkit/documents?documentId=...` | Write current content with `baseVersion`. |
90
+ | `POST` | `/mdkit/documents/resync?documentId=...` | Force a fresh current-document read. |
91
+ | `GET` | `/mdkit/versions?documentId=...` | List checkpoints as `{ versions }`. |
92
+ | `GET` | `/mdkit/versions/:versionId?documentId=...` | Read one checkpoint. |
93
+ | `POST` | `/mdkit/versions/:versionId/restore?documentId=...` | Restore one checkpoint. |
94
+
95
+ The REST frontend adapter expects the same JSON shapes as
96
+ `MdKitDocumentAdapter`. Write conflicts should return the conflict body with
97
+ HTTP `409`; the adapter treats that as a successful mdkit response so the editor
98
+ can show the conflict workflow.
package/docs/shadcn.md CHANGED
@@ -20,10 +20,10 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
20
20
  import { Textarea } from "@/components/ui/textarea";
21
21
  ```
22
22
 
23
- That means the workflow component can own polished app UI: toolbar, version
23
+ That means the workflow component can own polished app UI: toolbar, checkpoint
24
24
  history dialog, conflict dialog, tabs, buttons, and layout. The underlying state
25
- still comes from the mdkit hooks. The recommended transport for this path is the
26
- tRPC adapter from `@mp-lb/mdkit/trpc/client`.
25
+ still comes from the mdkit hooks. The recommended transport for this path is
26
+ the tRPC adapter from `@mp-lb/mdkit/trpc/client`.
27
27
 
28
28
  ## Intended Shape
29
29
 
@@ -48,16 +48,19 @@ export function EditorScreen() {
48
48
  const adapter = createMdKitTrpcAdapter({ client });
49
49
  const document = useMdKitDocument({ adapter, documentId });
50
50
  const versions = useMdKitDocumentVersions({ adapter, documentId });
51
+
51
52
  const collaboration = useMdKitCollaboration({
52
53
  collaborator,
53
54
  documentId,
54
55
  endpoint: hocuspocusEndpoint,
55
56
  });
57
+
56
58
  const restoreVersion = async (version) => {
57
59
  await client.restoreDocumentVersion.mutate({
58
60
  documentId,
59
61
  versionId: version.id,
60
62
  });
63
+
61
64
  await document.resync();
62
65
  await versions.refresh();
63
66
  };
package/docs/styling.md CHANGED
@@ -196,7 +196,7 @@ Example:
196
196
  - `.mp-lb-mdkit-conflict-panel`: root element
197
197
  - `.mp-lb-mdkit-conflict-panel-content`: title, explanatory text, and metadata
198
198
  - `.mp-lb-mdkit-conflict-panel-error`: error text
199
- - `.mp-lb-mdkit-conflict-panel-meta`: remote version metadata
199
+ - `.mp-lb-mdkit-conflict-panel-meta`: remote revision metadata
200
200
  - `.mp-lb-mdkit-conflict-panel-preview`: preview area
201
201
  - `.mp-lb-mdkit-conflict-panel-tabs`: preview tab list
202
202
  - `.mp-lb-mdkit-conflict-panel-tab`: preview tab button
@@ -206,22 +206,23 @@ Example:
206
206
 
207
207
  The preview tabs also use `aria-selected` for state-aware styling.
208
208
 
209
- ### Version History Panel
209
+ ### Checkpoint History Panel
210
210
 
211
- `VersionHistoryPanel` renders a version list, selected version preview, restore
212
- action, and empty/error states.
211
+ `VersionHistoryPanel` renders checkpoint history: a checkpoint list, selected
212
+ checkpoint preview, restore action, and empty/error states. The component and
213
+ CSS class names keep `version-history` for current API compatibility.
213
214
 
214
215
  - `.mp-lb-mdkit-version-history-panel`: root element
215
216
  - `.mp-lb-mdkit-version-history-header`: panel header
216
217
  - `.mp-lb-mdkit-version-history-title`: panel title
217
218
  - `.mp-lb-mdkit-version-history-subtitle`: panel subtitle
218
219
  - `.mp-lb-mdkit-version-history-layout`: list and preview layout
219
- - `.mp-lb-mdkit-version-history-list`: version list
220
- - `.mp-lb-mdkit-version-history-item`: version list item button
221
- - `.mp-lb-mdkit-version-history-item-active`: selected version list item
220
+ - `.mp-lb-mdkit-version-history-list`: checkpoint list
221
+ - `.mp-lb-mdkit-version-history-item`: checkpoint list item button
222
+ - `.mp-lb-mdkit-version-history-item-active`: selected checkpoint list item
222
223
  - `.mp-lb-mdkit-version-history-item-title`: list item title
223
- - `.mp-lb-mdkit-version-history-item-meta`: list item or selected version metadata
224
- - `.mp-lb-mdkit-version-history-preview`: selected version preview area
224
+ - `.mp-lb-mdkit-version-history-item-meta`: list item or selected checkpoint metadata
225
+ - `.mp-lb-mdkit-version-history-preview`: selected checkpoint preview area
225
226
  - `.mp-lb-mdkit-version-history-preview-header`: preview header
226
227
  - `.mp-lb-mdkit-version-history-preview-title`: preview title
227
228
  - `.mp-lb-mdkit-version-history-code`: markdown preview code block
@@ -232,7 +233,7 @@ action, and empty/error states.
232
233
 
233
234
  ### Shared Panel Actions
234
235
 
235
- Conflict and version panels share generic action classes:
236
+ Conflict and checkpoint panels share generic action classes:
236
237
 
237
238
  - `.mp-lb-mdkit-panel-primary-action`: primary action button
238
239
  - `.mp-lb-mdkit-panel-secondary-action`: secondary action button
@@ -0,0 +1,148 @@
1
+ # Use Cases
2
+
3
+ MDKit is designed as independent layers. Use only the pieces your product
4
+ needs:
5
+
6
+ | Layers | Behavior |
7
+ | --- | --- |
8
+ | Editor only | Controlled markdown editor. No backend, checkpoints, or collaboration. |
9
+ | Editor + storage | Autosave, current-document reads/writes, and conflict handling. |
10
+ | Editor + storage + checkpoints | Autosave plus meaningful history and restore. |
11
+ | Editor + storage + collaboration | Live collaboration plus canonical markdown snapshots. |
12
+ | Full stack | Storage, checkpoints, restore, collaboration, and permissions. |
13
+
14
+ ## Core Model
15
+
16
+ MDKit treats historical document state as checkpoint history.
17
+
18
+ A checkpoint is an immutable markdown snapshot with metadata. Version-per-write
19
+ is not a separate architecture; it is the checkpoint policy where every
20
+ successful write creates a checkpoint. No history is the checkpoint
21
+ policy where checkpoint creation is disabled.
22
+
23
+ That gives MDKit one history abstraction:
24
+
25
+ - autosave writes the canonical current markdown document
26
+ - checkpoint rules decide when current content becomes user-facing history
27
+ - history UI lists, previews, and restores checkpoints
28
+
29
+ ## Checkpoint Policies
30
+
31
+ ### Never
32
+
33
+ The app stores one current markdown document. The document still has an opaque
34
+ revision token for conflict detection, but no user-facing history.
35
+
36
+ ### Always
37
+
38
+ Every successful write creates a checkpoint. This is useful for deliberate
39
+ manual-save products, but it is usually too noisy for autosave because
40
+ autosave writes can be tiny implementation details.
41
+
42
+ ### Manual
43
+
44
+ Manual checkpoints are created by explicit user or product actions such as Save
45
+ checkpoint, publish, approve, or mark milestone.
46
+
47
+ ### Smart
48
+
49
+ Autosave keeps the current document durable. A smart checkpoint policy decides
50
+ when a change is meaningful enough to become history. Practical policies use
51
+ values such as edit distance, elapsed time since the last checkpoint, author,
52
+ and write context.
53
+
54
+ ```ts
55
+ const policy = CheckpointPolicy.smart({
56
+ minEditDistance: 250,
57
+ minIntervalMs: 5 * 60_000,
58
+ });
59
+ ```
60
+
61
+ Use a custom function when the built-in policy is not enough:
62
+
63
+ ```ts
64
+ const policy = CheckpointPolicy.function(
65
+ ({
66
+ currentContent,
67
+ editDistance,
68
+ previousCheckpointContent,
69
+ timeSinceLastCheckpointMs,
70
+ }) =>
71
+ editDistance > 500 ||
72
+ timeSinceLastCheckpointMs > 10 * 60_000 ||
73
+ currentContent.startsWith("# Published") !==
74
+ previousCheckpointContent?.startsWith("# Published"),
75
+ );
76
+ ```
77
+
78
+ The function receives both computed values and raw document content, so products
79
+ can use mdkit's edit-distance calculation or compute their own comparison.
80
+
81
+ ## Canonical Data
82
+
83
+ The canonical current document is markdown plus metadata:
84
+
85
+ - `documentId`
86
+ - `content`
87
+ - `revision`
88
+ - `updatedAt`
89
+ - optional caller-owned metadata
90
+
91
+ `revision` is an opaque concurrency token. It is not the same thing as a
92
+ checkpoint id.
93
+
94
+ Checkpoints are immutable markdown snapshots:
95
+
96
+ - `checkpointId`
97
+ - `documentId`
98
+ - `content`
99
+ - `createdAt`
100
+ - `sourceRevision`
101
+ - optional caller-owned metadata
102
+
103
+ The application owns product metadata, authorship, permissions, tenancy, and
104
+ audit data. MDKit should pass that data through without inspecting it.
105
+
106
+ ## Restore
107
+
108
+ The safest restore flow preserves current work before replacing it:
109
+
110
+ - read the checkpoint being restored
111
+ - checkpoint the current document if it is not already represented
112
+ - update the canonical current document to the restored content
113
+ - create a new current revision
114
+ - reset collaboration state if collaboration is enabled
115
+
116
+ The restored checkpoint remains immutable. Products can choose whether restore
117
+ also creates a restore checkpoint at the top of history.
118
+
119
+ ## Collaboration
120
+
121
+ Yjs state is the live collaboration state. Markdown remains the canonical
122
+ snapshot format for current-document storage and checkpoint history.
123
+
124
+ The opinionated collaboration flow is:
125
+
126
+ - seed an empty collaboration room from canonical markdown
127
+ - persist Yjs state through application-owned durable storage connected to the
128
+ collaboration server
129
+ - snapshot active Yjs state to markdown before updating canonical storage or
130
+ creating a checkpoint
131
+ - on restore, replace canonical markdown and reset/reseed collaboration state
132
+
133
+ Correctness is more important than preserving cursor continuity. A restore may
134
+ close or reset active collaboration sessions.
135
+
136
+ ## API Direction
137
+
138
+ The current package already exposes the editor, storage hooks, checkpoint-list
139
+ hooks, base panels, tRPC/REST helpers, and markdown/Yjs conversion helpers.
140
+
141
+ Future backend helpers should add:
142
+
143
+ - checkpoint policy helpers for `never`, `always`, `smart`, and custom
144
+ functions
145
+ - first-class checkpoint creation
146
+ - restore as a frontend/backend workflow
147
+ - generic metadata/context passthrough
148
+ - collaboration helpers for markdown/Yjs seeding, snapshotting, and reset
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mp-lb/mdkit",
3
- "version": "0.2.3-main.20.1",
3
+ "version": "0.2.3-main.21.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -29,6 +29,11 @@
29
29
  "import": "./dist/fastify.js",
30
30
  "types": "./dist/fastify.d.ts"
31
31
  },
32
+ "./server": {
33
+ "source": "./src/server.ts",
34
+ "import": "./dist/server.js",
35
+ "types": "./dist/server.d.ts"
36
+ },
32
37
  "./trpc": {
33
38
  "source": "./src/trpc.ts",
34
39
  "import": "./dist/trpc.js",