mindoodb-app-sdk 0.0.19 → 0.0.20

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
@@ -772,7 +772,126 @@ Like the text buffer, the rich-text handle always sends the original `baseHeads`
772
772
 
773
773
  #### End-to-end sample
774
774
 
775
- The Word/.docx mode in [`mindoodb-app-teamedit`](https://github.com/klehmann/mindoodb-app-teamedit) wires `MindooDBRichTextHandle` to an `@eigenpal/docx-editor-vue` editor and is the recommended starting point for building your own collaborative rich-text app.
775
+ The Word/.docx mode in [`mindoodb-app-teamedit`](https://github.com/klehmann/mindoodb-app-teamedit) is the **only supported in-repo use case** for the Automerge binary sync API below — it needs a local replica and binary flush because `set`/`unset` and the JSON patch APIs are not sufficient for that editor. For span-only rich-text apps, use `createMindooDBRichTextHandle` instead.
776
+
777
+ ### Automerge binary sync (advanced)
778
+
779
+ > **Avoid these APIs unless you have no alternative.** For normal app editing, use `documents.update({ set })`, `documents.update({ unset })`, and the JSON patch operations (`text`, `richText`, `json`) documented above. `getAutomergeSnapshot` and `applyAutomergeChanges` were added as an **escape hatch** for the one case where those APIs are not enough: TeamEdit's Word/.docx mode, which hosts a local `@automerge/automerge` replica and flushes raw change bytes on save. Do not adopt binary sync for new features unless you have the same constraint — you take on an Automerge dependency, manual replica lifecycle, and a much harder integration path.
780
+
781
+ If you must use binary sync, Haven decrypts the canonical document, merges incoming change batches with `Automerge.applyChanges`, and persists the result. Your app never sends encrypted blobs or sync metadata; it only sends the same binary change format Automerge produces locally.
782
+
783
+ Typical flow:
784
+
785
+ ```
786
+ ┌────────────────────────────────────────────────────┐
787
+ open ──► │ getAutomergeSnapshot → load local replica │
788
+ └─────────────────────────┬──────────────────────────┘
789
+ │
790
+ edit ──► │ Local Automerge doc (or span edits applied locally) │
791
+ └─────────────────────────┬──────────────────────────┘
792
+ │ getChangesSince(baseHeads)
793
+ ▼
794
+ ┌────────────────────────────────────────────────────┐
795
+ save ──► │ applyAutomergeChanges({ baseHeads, replicaHeads, │
796
+ │ changes }) │
797
+ └─────────────────────────┬──────────────────────────┘
798
+ │ Haven merges + persists
799
+ ▼
800
+ ┌────────────────────────────────────────────────────┐
801
+ │ Apply result.changesSince locally (or skip if empty) │
802
+ └────────────────────────────────────────────────────┘
803
+ ```
804
+
805
+ Bridge RPCs: `documents.automerge.getSnapshot` and `documents.automerge.applyChanges`.
806
+
807
+ #### `getAutomergeSnapshot`
808
+
809
+ Export the full internal Automerge document as a binary snapshot plus the current document heads:
810
+
811
+ ```ts
812
+ const snapshot = await db.documents.getAutomergeSnapshot(docId);
813
+ // snapshot = { binary: Uint8Array, heads: string[] }
814
+
815
+ const localDoc = Automerge.load(snapshot.binary);
816
+ const baseHeads = [...snapshot.heads];
817
+ ```
818
+
819
+ Options:
820
+
821
+ ```ts
822
+ interface MindooDBAppAutomergeGetOptions {
823
+ revisionId?: MindooDBAppDocumentRevisionId; // historical read via documents.listHistory()
824
+ }
825
+ ```
826
+
827
+ Only call this when binary sync is unavoidable — e.g. opening a local replica, refreshing after `applyAutomergeChanges`, or read-only historical preview at a `revisionId`. For normal reads, use `getRichText` or `documents.get`.
828
+
829
+ #### `applyAutomergeChanges`
830
+
831
+ Merge a batch of raw Automerge change bytes into the canonical document on Haven:
832
+
833
+ ```ts
834
+ const changes = Automerge.getChangesSince(localDoc, baseHeads as Automerge.Heads);
835
+ const replicaHeads = Automerge.getHeads(localDoc);
836
+
837
+ const result = await db.documents.applyAutomergeChanges(docId, {
838
+ baseHeads, // optional metadata: heads when the local batch was authored
839
+ replicaHeads, // local heads after authoring; enables incremental catch-up in the response
840
+ changes: changes.map((change) => new Uint8Array(change)),
841
+ });
842
+
843
+ // result.document — updated MindooDBAppDocument snapshot (includes merged data + heads)
844
+ // result.heads — new Automerge heads after the merge
845
+ // result.changesSince — incremental bytes to reconcile the local replica (when replicaHeads was sent)
846
+ if (result.changesSince?.changes.length) {
847
+ [localDoc] = Automerge.applyChanges(
848
+ localDoc,
849
+ result.changesSince.changes.map((change) => new Uint8Array(change)),
850
+ );
851
+ }
852
+ baseHeads = [...result.heads];
853
+ ```
854
+
855
+ Patch and result types:
856
+
857
+ ```ts
858
+ interface MindooDBAppAutomergeChangesPatch {
859
+ baseHeads?: string[]; // correlation only; merge is not rejected when Haven moved on
860
+ replicaHeads?: string[]; // local heads after authoring `changes`; enables `changesSince` in the response
861
+ changes: Uint8Array[]; // from Automerge.getChangesSince (or equivalent)
862
+ }
863
+
864
+ interface MindooDBAppAutomergeChangesSince {
865
+ sinceHeads: string[]; // echo of `replicaHeads`
866
+ changes: Uint8Array[]; // apply locally with Automerge.applyChanges
867
+ }
868
+
869
+ interface MindooDBAppAutomergePatchResult {
870
+ document: MindooDBAppDocument;
871
+ heads: string[];
872
+ changesSince?: MindooDBAppAutomergeChangesSince;
873
+ }
874
+ ```
875
+
876
+ Haven applies `changes` with `Automerge.applyChanges` against its **current** document, so concurrent edits from other clients are merged by Automerge's CRDT logic rather than rejected. `baseHeads` is optional logging metadata — it does not gate the merge.
877
+
878
+ When you include `replicaHeads` (the local replica's heads after authoring your batch), the response includes `changesSince`: the incremental change bytes your replica still needs after the merge. Apply them locally with `Automerge.applyChanges` and set `baseHeads = result.heads`. When there was no concurrent edit, `changesSince.changes` is empty and your local doc is already up to date — no full snapshot download needed. Omit `replicaHeads` only if you plan to reload via `getAutomergeSnapshot` instead.
879
+
880
+ #### When to use binary sync vs JSON patches
881
+
882
+ | Approach | App sends | When to use |
883
+ | -------- | --------- | ----------- |
884
+ | `documents.update({ set })` / `{ unset }` | Field paths | **Default** for structured document data |
885
+ | `documents.update({ richText })` | JSON span snapshots | **Default** for rich-text fields |
886
+ | `documents.update({ text })` | Text splices | Plain markdown / string fields |
887
+ | `documents.update({ json })` | JSON Patch (RFC 6902) | Arbitrary nested JSON paths |
888
+ | `applyAutomergeChanges` | Binary change bytes | **Last resort only** — TeamEdit Word/.docx with a local Automerge replica |
889
+
890
+ Requires the `update` capability (same as other write operations). For historical reads, prefer `getRichText(..., { revisionId })`; only use `getAutomergeSnapshot(..., { revisionId })` when you truly need the full binary at a revision.
891
+
892
+ #### Reference implementation (not a template)
893
+
894
+ TeamEdit's Word/.docx mode is why these RPCs exist — see `wordAutomergeHandle.ts` in [`mindoodb-app-teamedit`](https://github.com/klehmann/mindoodb-app-teamedit). Treat it as a reference for an unsupported edge case, not as a pattern to copy into new apps.
776
895
 
777
896
  ### Incremental sync
778
897
 
@@ -1208,6 +1327,8 @@ Connect options: `launchId?`, `targetOrigin?`, `connectTimeoutMs?`.
1208
1327
  | `list(query?)` | `Promise<MindooDBAppDocumentListResult>` |
1209
1328
  | `get(docId)` | `Promise<MindooDBAppDocument \| null>` |
1210
1329
  | `getRichText(docId, path, opts?)` | `Promise<MindooDBAppRichTextSnapshot>` |
1330
+ | `getAutomergeSnapshot(docId, opts?)` | `Promise<MindooDBAppAutomergeSnapshot>` |
1331
+ | `applyAutomergeChanges(docId, patch)` | `Promise<MindooDBAppAutomergePatchResult>` |
1211
1332
  | `create(input)` | `Promise<MindooDBAppDocument>` |
1212
1333
  | `update(docId, patch)` | `Promise<MindooDBAppDocument>` |
1213
1334
  | `delete(docId)` | `Promise<{ ok: true }>` |
@@ -1216,6 +1337,8 @@ Connect options: `launchId?`, `targetOrigin?`, `connectTimeoutMs?`.
1216
1337
  | `getAtTimestamp(docId, timestamp)` | `Promise<MindooDBAppHistoricalDocument>` |
1217
1338
  | `getAtRevision(docId, revisionId)` | `Promise<MindooDBAppHistoricalDocument>` |
1218
1339
 
1340
+ `getAutomergeSnapshot` and `applyAutomergeChanges` are **discouraged** escape-hatch APIs for binary Automerge sync. Prefer `set`/`unset` and JSON patches (`text`, `richText`, `json`) instead. See [Automerge binary sync (advanced)](#automerge-binary-sync-advanced).
1341
+
1219
1342
  `list(query?)` accepts the changefeed query options documented above. The `cursor` value is an opaque checkpoint string managed by Haven and should be stored and passed back unchanged.
1220
1343
 
1221
1344
  For `create(input)`, use `MindooDBAppCreateDocumentInput` with shape `{ set: Record<string, unknown>; decryptionKeyId?: string; id?: string }`. The optional `id` lets the app pick the document id instead of letting MindooDB generate a UUID7; when provided it must match `/^[A-Za-z][A-Za-z0-9_]*$/` and existing live documents with that id are returned as-is (idempotent create-if-missing). If an existing custom-id document is deleted, `create({ id })` undeletes it and preserves the previous document body. Documents created with the same custom id on different replicas converge correctly when synced.
@@ -0,0 +1,37 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
13
+ var __commonJS = (cb, mod) => function __require2() {
14
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ export {
34
+ __require,
35
+ __commonJS,
36
+ __toESM
37
+ };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppBridge, b as MindooDBAppDatabase, c as MindooDBAppDocument, d as MindooDBAppRichTextSpan, e as MindooDBAppRichTextSnapshot } from './types-nFt-aryL.js';
2
- export { f as MindooDBAppAttachmentApi, g as MindooDBAppAttachmentChunk, h as MindooDBAppAttachmentInfo, i as MindooDBAppAttachmentPreviewOptions, j as MindooDBAppAttachmentPreviewSession, k as MindooDBAppBridgeConnectMessage, l as MindooDBAppBridgeConnectOptions, m as MindooDBAppBridgeConnectedMessage, n as MindooDBAppBridgeErrorPayload, o as MindooDBAppBridgeHandshakeErrorMessage, p as MindooDBAppBridgePortMessage, q as MindooDBAppBridgeRpcError, r as MindooDBAppBridgeRpcMessage, s as MindooDBAppBridgeRpcRequest, t as MindooDBAppBridgeRpcSuccess, u as MindooDBAppBridgeStreamAbortRequest, v as MindooDBAppBridgeStreamAck, w as MindooDBAppBridgeStreamCloseRequest, x as MindooDBAppBridgeStreamError, y as MindooDBAppBridgeStreamMessage, z as MindooDBAppBridgeStreamOpenResult, A as MindooDBAppBridgeStreamReadRequest, B as MindooDBAppBridgeStreamWriteRequest, C as MindooDBAppBridgeThemeChangedMessage, D as MindooDBAppBridgeUiPreferencesChangedMessage, E as MindooDBAppBridgeViewportChangedMessage, F as MindooDBAppCapability, G as MindooDBAppConfiguredViewCategorizationStyle, H as MindooDBAppConfiguredViewColumn, I as MindooDBAppConfiguredViewColumnRole, J as MindooDBAppConfiguredViewExpressionMode, K as MindooDBAppConfiguredViewFieldExpression, L as MindooDBAppConfiguredViewFilterDefinition, N as MindooDBAppConfiguredViewFilterMode, O as MindooDBAppConfiguredViewFilterRule, P as MindooDBAppConfiguredViewFormulaExpression, Q as MindooDBAppConfiguredViewFormulaFilterDefinition, R as MindooDBAppConfiguredViewPreviewMode, S as MindooDBAppConfiguredViewRuleFilterDefinition, T as MindooDBAppConfiguredViewRuleMatchMode, U as MindooDBAppConfiguredViewRuleOperator, V as MindooDBAppConfiguredViewValueExpression, W as MindooDBAppCreateDocumentInput, X as MindooDBAppCreateViewInput, Y as MindooDBAppCreateViewNavigatorInput, Z as MindooDBAppDatabaseInfo, _ as MindooDBAppDocumentApi, $ as MindooDBAppDocumentHeadCursorResult, a0 as MindooDBAppDocumentHistoryEntry, a1 as MindooDBAppDocumentListQuery, a2 as MindooDBAppDocumentListResult, a3 as MindooDBAppDocumentRevisionId, a4 as MindooDBAppDocumentScanPreset, a5 as MindooDBAppDocumentSummary, a6 as MindooDBAppHistoricalDocument, a7 as MindooDBAppHistoryQuery, a8 as MindooDBAppHostTheme, a9 as MindooDBAppJsonListDeletePatch, aa as MindooDBAppJsonListInsertPatch, ab as MindooDBAppJsonPatch, ac as MindooDBAppJsonSetPatch, ad as MindooDBAppJsonUnsetPatch, ae as MindooDBAppLaunchContext, af as MindooDBAppMenuAnchor, ag as MindooDBAppMenuApi, ah as MindooDBAppMenuCommandItem, ai as MindooDBAppMenuDismissReason, aj as MindooDBAppMenuDismissedResult, ak as MindooDBAppMenuItem, al as MindooDBAppMenuKind, am as MindooDBAppMenuPlacement, an as MindooDBAppMenuPointAnchor, ao as MindooDBAppMenuRect, ap as MindooDBAppMenuRectAnchor, aq as MindooDBAppMenuSelectionResult, ar as MindooDBAppMenuSeparatorItem, as as MindooDBAppReadableAttachmentStream, at as MindooDBAppResolvedViewDefinition, au as MindooDBAppResolvedViewSource, av as MindooDBAppRichTextBlockSpan, aw as MindooDBAppRichTextGetOptions, ax as MindooDBAppRichTextImmutableString, ay as MindooDBAppRichTextMaterializeValue, az as MindooDBAppRichTextPatch, aA as MindooDBAppRichTextScalar, aB as MindooDBAppRichTextTextSpan, aC as MindooDBAppRuntime, aD as MindooDBAppScanAttachmentOptions, aE as MindooDBAppScanAttachmentResult, aF as MindooDBAppScopedDocId, aG as MindooDBAppScopedDocumentSummary, aH as MindooDBAppSession, aI as MindooDBAppShowMenuInput, aJ as MindooDBAppShowMenuResult, aK as MindooDBAppTextEdit, aL as MindooDBAppTextPatch, aM as MindooDBAppThemeMode, aN as MindooDBAppUiPreferences, aO as MindooDBAppUpdateDocumentInput, aP as MindooDBAppViewCursorDocumentListResult, aQ as MindooDBAppViewCursorResult, aR as MindooDBAppViewEntry, aS as MindooDBAppViewEntryKind, aT as MindooDBAppViewNavigator, aU as MindooDBAppViewNavigatorExpansionState, aV as MindooDBAppViewNavigatorOpenOptions, aW as MindooDBAppViewNavigatorPageOptions, aX as MindooDBAppViewNavigatorPageResult, aY as MindooDBAppViewNavigatorRangeQuery, aZ as MindooDBAppViewNavigatorSelectionState, a_ as MindooDBAppViewport, a$ as MindooDBAppWritableAttachmentStream } from './types-nFt-aryL.js';
1
+ import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppBridge, b as MindooDBAppDatabase, c as MindooDBAppDocument, d as MindooDBAppRichTextSpan, e as MindooDBAppRichTextSnapshot } from './types-CQt2ObMu.js';
2
+ export { f as MindooDBAppAttachmentApi, g as MindooDBAppAttachmentChunk, h as MindooDBAppAttachmentInfo, i as MindooDBAppAttachmentPreviewOptions, j as MindooDBAppAttachmentPreviewSession, k as MindooDBAppAutomergeChangesPatch, l as MindooDBAppAutomergeChangesSince, m as MindooDBAppAutomergeGetOptions, n as MindooDBAppAutomergePatchResult, o as MindooDBAppAutomergeSnapshot, p as MindooDBAppBridgeConnectMessage, q as MindooDBAppBridgeConnectOptions, r as MindooDBAppBridgeConnectedMessage, s as MindooDBAppBridgeErrorPayload, t as MindooDBAppBridgeHandshakeErrorMessage, u as MindooDBAppBridgePortMessage, v as MindooDBAppBridgeRpcError, w as MindooDBAppBridgeRpcMessage, x as MindooDBAppBridgeRpcRequest, y as MindooDBAppBridgeRpcSuccess, z as MindooDBAppBridgeStreamAbortRequest, A as MindooDBAppBridgeStreamAck, B as MindooDBAppBridgeStreamCloseRequest, C as MindooDBAppBridgeStreamError, D as MindooDBAppBridgeStreamMessage, E as MindooDBAppBridgeStreamOpenResult, F as MindooDBAppBridgeStreamReadRequest, G as MindooDBAppBridgeStreamWriteRequest, H as MindooDBAppBridgeThemeChangedMessage, I as MindooDBAppBridgeUiPreferencesChangedMessage, J as MindooDBAppBridgeViewportChangedMessage, K as MindooDBAppCapability, L as MindooDBAppConfiguredViewCategorizationStyle, N as MindooDBAppConfiguredViewColumn, O as MindooDBAppConfiguredViewColumnRole, P as MindooDBAppConfiguredViewExpressionMode, Q as MindooDBAppConfiguredViewFieldExpression, R as MindooDBAppConfiguredViewFilterDefinition, S as MindooDBAppConfiguredViewFilterMode, T as MindooDBAppConfiguredViewFilterRule, U as MindooDBAppConfiguredViewFormulaExpression, V as MindooDBAppConfiguredViewFormulaFilterDefinition, W as MindooDBAppConfiguredViewPreviewMode, X as MindooDBAppConfiguredViewRuleFilterDefinition, Y as MindooDBAppConfiguredViewRuleMatchMode, Z as MindooDBAppConfiguredViewRuleOperator, _ as MindooDBAppConfiguredViewValueExpression, $ as MindooDBAppCreateDocumentInput, a0 as MindooDBAppCreateViewInput, a1 as MindooDBAppCreateViewNavigatorInput, a2 as MindooDBAppDatabaseInfo, a3 as MindooDBAppDocumentApi, a4 as MindooDBAppDocumentHeadCursorResult, a5 as MindooDBAppDocumentHistoryEntry, a6 as MindooDBAppDocumentListQuery, a7 as MindooDBAppDocumentListResult, a8 as MindooDBAppDocumentRevisionId, a9 as MindooDBAppDocumentScanPreset, aa as MindooDBAppDocumentSummary, ab as MindooDBAppHistoricalDocument, ac as MindooDBAppHistoryQuery, ad as MindooDBAppHostTheme, ae as MindooDBAppJsonListDeletePatch, af as MindooDBAppJsonListInsertPatch, ag as MindooDBAppJsonPatch, ah as MindooDBAppJsonSetPatch, ai as MindooDBAppJsonTextMarkPatch, aj as MindooDBAppJsonTextSplicePatch, ak as MindooDBAppJsonTextUnmarkPatch, al as MindooDBAppJsonUnsetPatch, am as MindooDBAppLaunchContext, an as MindooDBAppMenuAnchor, ao as MindooDBAppMenuApi, ap as MindooDBAppMenuCommandItem, aq as MindooDBAppMenuDismissReason, ar as MindooDBAppMenuDismissedResult, as as MindooDBAppMenuItem, at as MindooDBAppMenuKind, au as MindooDBAppMenuPlacement, av as MindooDBAppMenuPointAnchor, aw as MindooDBAppMenuRect, ax as MindooDBAppMenuRectAnchor, ay as MindooDBAppMenuSelectionResult, az as MindooDBAppMenuSeparatorItem, aA as MindooDBAppReadableAttachmentStream, aB as MindooDBAppResolvedViewDefinition, aC as MindooDBAppResolvedViewSource, aD as MindooDBAppRichTextBlockSpan, aE as MindooDBAppRichTextGetOptions, aF as MindooDBAppRichTextImmutableString, aG as MindooDBAppRichTextMarkRange, aH as MindooDBAppRichTextMaterializeValue, aI as MindooDBAppRichTextPatch, aJ as MindooDBAppRichTextScalar, aK as MindooDBAppRichTextSpliceStep, aL as MindooDBAppRichTextStep, aM as MindooDBAppRichTextStepPatch, aN as MindooDBAppRichTextTextSpan, aO as MindooDBAppRuntime, aP as MindooDBAppScanAttachmentOptions, aQ as MindooDBAppScanAttachmentResult, aR as MindooDBAppScopedDocId, aS as MindooDBAppScopedDocumentSummary, aT as MindooDBAppSession, aU as MindooDBAppShowMenuInput, aV as MindooDBAppShowMenuResult, aW as MindooDBAppTextEdit, aX as MindooDBAppTextPatch, aY as MindooDBAppThemeMode, aZ as MindooDBAppUiPreferences, a_ as MindooDBAppUpdateDocumentInput, a$ as MindooDBAppViewCursorDocumentListResult, b0 as MindooDBAppViewCursorResult, b1 as MindooDBAppViewEntry, b2 as MindooDBAppViewEntryKind, b3 as MindooDBAppViewNavigator, b4 as MindooDBAppViewNavigatorExpansionState, b5 as MindooDBAppViewNavigatorOpenOptions, b6 as MindooDBAppViewNavigatorPageOptions, b7 as MindooDBAppViewNavigatorPageResult, b8 as MindooDBAppViewNavigatorRangeQuery, b9 as MindooDBAppViewNavigatorSelectionState, ba as MindooDBAppViewport, bb as MindooDBAppWritableAttachmentStream } from './types-CQt2ObMu.js';
3
3
  export { MindooDBAppBooleanExpression, MindooDBAppExpression, MindooDBAppFilterDefinition, MindooDBAppViewCategoryChildrenPageRequest, MindooDBAppViewColumn, MindooDBAppViewColumnRole, MindooDBAppViewDefinition, MindooDBAppViewExpansionState, MindooDBAppViewExpressionBase, MindooDBAppViewExpressionDatePart, MindooDBAppViewExpressionOperation, MindooDBAppViewFieldExpression, MindooDBAppViewIfExpression, MindooDBAppViewLetExpression, MindooDBAppViewLiteralExpression, MindooDBAppViewLookupByPath, MindooDBAppViewOperationExpression, MindooDBAppViewOriginExpression, MindooDBAppViewPageRequest, MindooDBAppViewPageResult, MindooDBAppViewRow, MindooDBAppViewSortDirection, MindooDBAppViewTotalMode, MindooDBAppViewValueExpressionRef, MindooDBAppViewVariableExpression, createViewLanguage } from 'mindoodb-view-language';
4
4
 
5
5
  /**
@@ -53,13 +53,15 @@ type MindooDBRichTextHandleChangeListener = (snapshot: MindooDBAppRichTextSnapsh
53
53
  /**
54
54
  * Local rich-text span buffer for SDK apps.
55
55
  *
56
- * The helper deliberately mirrors the causal shape of `MindooDBTextBuffer`:
57
- * local editor code replaces the current span snapshot, then `flush()` sends a
58
- * separate `richText` patch with the document heads the snapshot was based on.
56
+ * Mirrors `MindooDBTextBuffer`: track edits against a base snapshot, then flush
57
+ * with causal `baseHeads`. Text edits prefer positional `richTextSteps` so
58
+ * concurrent saves merge like plain-text splices; formatting-only or structural
59
+ * changes fall back to full `richText` span snapshots.
59
60
  */
60
61
  declare class MindooDBRichTextHandle {
61
62
  private readonly options;
62
63
  private spansInternal;
64
+ private baseMaterializedText;
63
65
  private heads;
64
66
  private dirtyInternal;
65
67
  private listeners;
@@ -77,6 +79,7 @@ declare class MindooDBRichTextHandle {
77
79
  refresh(): Promise<MindooDBAppRichTextSnapshot>;
78
80
  pollOnce(): Promise<boolean>;
79
81
  flush(updateSpansConfig?: Record<string, unknown>): Promise<MindooDBRichTextHandleFlushResult>;
82
+ private flushTextSteps;
80
83
  private emitChange;
81
84
  }
82
85
  declare function createMindooDBRichTextHandle(options: CreateMindooDBRichTextHandleOptions): MindooDBRichTextHandle;
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ import "./chunk-QGM4M3NI.js";
2
+
1
3
  // src/attachmentPreview.ts
2
4
  function canPreviewAttachment(fileName, mimeType) {
3
5
  const normalizedMimeType = mimeType.toLowerCase();
@@ -732,6 +734,16 @@ var MindooDBAppDatabaseImpl = class {
732
734
  path,
733
735
  revisionId: options?.revisionId
734
736
  }),
737
+ getAutomergeSnapshot: async (docId, options) => await this.rpc.call("documents.automerge.getSnapshot", {
738
+ databaseId: this.databaseId,
739
+ docId,
740
+ revisionId: options?.revisionId
741
+ }),
742
+ applyAutomergeChanges: async (docId, patch) => await this.rpc.call("documents.automerge.applyChanges", {
743
+ databaseId: this.databaseId,
744
+ docId,
745
+ patch
746
+ }),
735
747
  create: async (input) => await this.rpc.call("documents.create", {
736
748
  databaseId: this.databaseId,
737
749
  input
@@ -997,11 +1009,18 @@ function createMindooDBAppBridge() {
997
1009
  var MindooDBRichTextHandle = class {
998
1010
  constructor(options) {
999
1011
  this.options = options;
1000
- this.spansInternal = cloneSpans(options.spans ?? []);
1012
+ const initialSpans = cloneSpans(options.spans ?? []);
1013
+ this.spansInternal = initialSpans;
1014
+ this.baseMaterializedText = readMaterializedRichTextText(
1015
+ options.document.data,
1016
+ options.path,
1017
+ initialSpans
1018
+ );
1001
1019
  this.heads = options.document.heads ? [...options.document.heads] : [];
1002
1020
  }
1003
1021
  options;
1004
1022
  spansInternal;
1023
+ baseMaterializedText;
1005
1024
  heads;
1006
1025
  dirtyInternal = false;
1007
1026
  listeners = /* @__PURE__ */ new Set();
@@ -1041,6 +1060,7 @@ var MindooDBRichTextHandle = class {
1041
1060
  reconcile(document, snapshot) {
1042
1061
  const previous = JSON.stringify(this.spansInternal);
1043
1062
  this.spansInternal = cloneSpans(snapshot.spans);
1063
+ this.baseMaterializedText = spansToPlainText(snapshot.spans);
1044
1064
  this.heads = snapshot.heads ?? document.heads ?? [];
1045
1065
  this.dirtyInternal = false;
1046
1066
  const changed = JSON.stringify(this.spansInternal) !== previous;
@@ -1081,14 +1101,16 @@ var MindooDBRichTextHandle = class {
1081
1101
  reconciled: false
1082
1102
  };
1083
1103
  }
1084
- const localSpansAtFlush = JSON.stringify(this.spansInternal);
1085
- const document = await this.options.database.documents.update(
1104
+ const localSpansAtFlush = cloneSpans(this.spansInternal);
1105
+ const localTextAtFlush = spansToPlainText(localSpansAtFlush);
1106
+ const textChanged = localTextAtFlush !== this.baseMaterializedText;
1107
+ const document = textChanged ? await this.flushTextSteps(localTextAtFlush) : await this.options.database.documents.update(
1086
1108
  this.options.document.id,
1087
1109
  {
1088
1110
  richText: [{
1089
1111
  path: this.options.path,
1090
1112
  baseHeads: this.heads,
1091
- spans: cloneSpans(this.spansInternal),
1113
+ spans: localSpansAtFlush,
1092
1114
  updateSpansConfig
1093
1115
  }]
1094
1116
  }
@@ -1097,8 +1119,9 @@ var MindooDBRichTextHandle = class {
1097
1119
  this.options.document.id,
1098
1120
  this.options.path
1099
1121
  );
1100
- const reconciled = JSON.stringify(snapshot.spans) !== localSpansAtFlush;
1122
+ const reconciled = JSON.stringify(snapshot.spans) !== JSON.stringify(localSpansAtFlush);
1101
1123
  this.spansInternal = cloneSpans(snapshot.spans);
1124
+ this.baseMaterializedText = spansToPlainText(snapshot.spans);
1102
1125
  this.heads = snapshot.heads ?? document.heads ?? [];
1103
1126
  this.dirtyInternal = false;
1104
1127
  if (reconciled) {
@@ -1110,6 +1133,21 @@ var MindooDBRichTextHandle = class {
1110
1133
  reconciled
1111
1134
  };
1112
1135
  }
1136
+ async flushTextSteps(localTextAtFlush) {
1137
+ const edit = computeSingleSplice(this.baseMaterializedText, localTextAtFlush);
1138
+ return this.options.database.documents.update(this.options.document.id, {
1139
+ richTextSteps: [{
1140
+ path: this.options.path,
1141
+ baseHeads: this.heads,
1142
+ steps: [{
1143
+ type: "splice",
1144
+ index: edit.index,
1145
+ deleteCount: edit.deleteCount,
1146
+ insert: edit.insert ?? ""
1147
+ }]
1148
+ }]
1149
+ });
1150
+ }
1113
1151
  emitChange() {
1114
1152
  const snapshot = {
1115
1153
  path: [...this.options.path],
@@ -1127,6 +1165,44 @@ function createMindooDBRichTextHandle(options) {
1127
1165
  function cloneSpans(spans) {
1128
1166
  return structuredClone(spans);
1129
1167
  }
1168
+ function spansToPlainText(spans) {
1169
+ return spans.filter((span) => span.type === "text").map((span) => span.type === "text" ? span.value : "").join("");
1170
+ }
1171
+ function readMaterializedRichTextText(data, path, fallbackSpans) {
1172
+ let value = data;
1173
+ for (const segment of path) {
1174
+ if (value == null || typeof value !== "object") {
1175
+ return spansToPlainText(fallbackSpans);
1176
+ }
1177
+ value = value[segment];
1178
+ }
1179
+ if (typeof value === "string") {
1180
+ return value.replace(/\uFFFC/g, "");
1181
+ }
1182
+ if (Array.isArray(value)) {
1183
+ return spansToPlainText(value);
1184
+ }
1185
+ return spansToPlainText(fallbackSpans);
1186
+ }
1187
+ function computeSingleSplice(previous, next) {
1188
+ let prefixLength = 0;
1189
+ const maxPrefix = Math.min(previous.length, next.length);
1190
+ while (prefixLength < maxPrefix && previous[prefixLength] === next[prefixLength]) {
1191
+ prefixLength += 1;
1192
+ }
1193
+ let suffixLength = 0;
1194
+ const previousRemaining = previous.length - prefixLength;
1195
+ const nextRemaining = next.length - prefixLength;
1196
+ const maxSuffix = Math.min(previousRemaining, nextRemaining);
1197
+ while (suffixLength < maxSuffix && previous[previous.length - 1 - suffixLength] === next[next.length - 1 - suffixLength]) {
1198
+ suffixLength += 1;
1199
+ }
1200
+ return {
1201
+ index: prefixLength,
1202
+ deleteCount: previous.length - prefixLength - suffixLength,
1203
+ insert: next.slice(prefixLength, next.length - suffixLength)
1204
+ };
1205
+ }
1130
1206
 
1131
1207
  // src/textBuffer.ts
1132
1208
  var MindooDBTextBuffer = class {
@@ -1181,7 +1257,7 @@ var MindooDBTextBuffer = class {
1181
1257
  if (nextValue === this.valueInternal) {
1182
1258
  return;
1183
1259
  }
1184
- const edit = computeSingleSplice(this.valueInternal, nextValue);
1260
+ const edit = computeSingleSplice2(this.valueInternal, nextValue);
1185
1261
  this.splice(edit.index, edit.deleteCount, edit.insert ?? "");
1186
1262
  }
1187
1263
  /**
@@ -1248,7 +1324,7 @@ function readTextAtPath(data, path) {
1248
1324
  }
1249
1325
  return typeof value === "string" ? value : "";
1250
1326
  }
1251
- function computeSingleSplice(previous, next) {
1327
+ function computeSingleSplice2(previous, next) {
1252
1328
  let prefixLength = 0;
1253
1329
  const maxPrefix = Math.min(previous.length, next.length);
1254
1330
  while (prefixLength < maxPrefix && previous[prefixLength] === next[prefixLength]) {
@@ -1,4 +1,4 @@
1
- import { ae as MindooDBAppLaunchContext, Z as MindooDBAppDatabaseInfo, _ as MindooDBAppDocumentApi, Y as MindooDBAppCreateViewNavigatorInput, aT as MindooDBAppViewNavigator, aV as MindooDBAppViewNavigatorOpenOptions, f as MindooDBAppAttachmentApi, a as MindooDBAppBridge, aH as MindooDBAppSession, s as MindooDBAppBridgeRpcRequest, a8 as MindooDBAppHostTheme, a_ as MindooDBAppViewport, aN as MindooDBAppUiPreferences, p as MindooDBAppBridgePortMessage } from '../types-nFt-aryL.js';
1
+ import { am as MindooDBAppLaunchContext, a2 as MindooDBAppDatabaseInfo, a3 as MindooDBAppDocumentApi, a1 as MindooDBAppCreateViewNavigatorInput, b3 as MindooDBAppViewNavigator, b5 as MindooDBAppViewNavigatorOpenOptions, f as MindooDBAppAttachmentApi, a as MindooDBAppBridge, aT as MindooDBAppSession, x as MindooDBAppBridgeRpcRequest, ad as MindooDBAppHostTheme, ba as MindooDBAppViewport, aZ as MindooDBAppUiPreferences, u as MindooDBAppBridgePortMessage } from '../types-CQt2ObMu.js';
2
2
  import 'mindoodb-view-language';
3
3
 
4
4
  type MaybePromise<T> = T | Promise<T>;