@agent-native/toolkit 0.4.9 → 0.5.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.
Files changed (150) hide show
  1. package/README.md +17 -6
  2. package/dist/collab-ui/agent-identity.d.ts +9 -0
  3. package/dist/collab-ui/agent-identity.d.ts.map +1 -0
  4. package/dist/collab-ui/agent-identity.js +9 -0
  5. package/dist/collab-ui/agent-identity.js.map +1 -0
  6. package/dist/collab-ui/index.d.ts +2 -0
  7. package/dist/collab-ui/index.d.ts.map +1 -1
  8. package/dist/collab-ui/index.js +2 -0
  9. package/dist/collab-ui/index.js.map +1 -1
  10. package/dist/collab-ui/lead-client.d.ts +3 -0
  11. package/dist/collab-ui/lead-client.d.ts.map +1 -0
  12. package/dist/collab-ui/lead-client.js +29 -0
  13. package/dist/collab-ui/lead-client.js.map +1 -0
  14. package/dist/collab-ui/types.d.ts.map +1 -1
  15. package/dist/collab-ui/types.js +11 -2
  16. package/dist/collab-ui/types.js.map +1 -1
  17. package/dist/collab-ui/types.spec.d.ts +2 -0
  18. package/dist/collab-ui/types.spec.d.ts.map +1 -0
  19. package/dist/collab-ui/types.spec.js +15 -0
  20. package/dist/collab-ui/types.spec.js.map +1 -0
  21. package/dist/context-ui/ContextMeter.d.ts +10 -0
  22. package/dist/context-ui/ContextMeter.d.ts.map +1 -0
  23. package/dist/context-ui/ContextMeter.js +20 -0
  24. package/dist/context-ui/ContextMeter.js.map +1 -0
  25. package/dist/context-ui/ContextSegmentRow.d.ts +14 -0
  26. package/dist/context-ui/ContextSegmentRow.d.ts.map +1 -0
  27. package/dist/context-ui/ContextSegmentRow.js +25 -0
  28. package/dist/context-ui/ContextSegmentRow.js.map +1 -0
  29. package/dist/context-ui/ContextTreemap.d.ts +7 -0
  30. package/dist/context-ui/ContextTreemap.d.ts.map +1 -0
  31. package/dist/context-ui/ContextTreemap.js +55 -0
  32. package/dist/context-ui/ContextTreemap.js.map +1 -0
  33. package/dist/context-ui/ContextXRayPanel.d.ts +13 -0
  34. package/dist/context-ui/ContextXRayPanel.d.ts.map +1 -0
  35. package/dist/context-ui/ContextXRayPanel.js +120 -0
  36. package/dist/context-ui/ContextXRayPanel.js.map +1 -0
  37. package/dist/context-ui/format.d.ts +6 -0
  38. package/dist/context-ui/format.d.ts.map +1 -0
  39. package/dist/context-ui/format.js +58 -0
  40. package/dist/context-ui/format.js.map +1 -0
  41. package/dist/context-ui/index.d.ts +7 -0
  42. package/dist/context-ui/index.d.ts.map +1 -0
  43. package/dist/context-ui/index.js +6 -0
  44. package/dist/context-ui/index.js.map +1 -0
  45. package/dist/context-ui/types.d.ts +39 -0
  46. package/dist/context-ui/types.d.ts.map +1 -0
  47. package/dist/context-ui/types.js +2 -0
  48. package/dist/context-ui/types.js.map +1 -0
  49. package/dist/design-tweaks/index.d.ts +2 -0
  50. package/dist/design-tweaks/index.d.ts.map +1 -0
  51. package/dist/design-tweaks/index.js +2 -0
  52. package/dist/design-tweaks/index.js.map +1 -0
  53. package/dist/design-tweaks/visual-style-controls.d.ts +90 -0
  54. package/dist/design-tweaks/visual-style-controls.d.ts.map +1 -0
  55. package/dist/design-tweaks/visual-style-controls.js +499 -0
  56. package/dist/design-tweaks/visual-style-controls.js.map +1 -0
  57. package/dist/editor/BubbleToolbar.d.ts +37 -0
  58. package/dist/editor/BubbleToolbar.d.ts.map +1 -0
  59. package/dist/editor/BubbleToolbar.js +171 -0
  60. package/dist/editor/BubbleToolbar.js.map +1 -0
  61. package/dist/editor/CodeBlockNode.d.ts +49 -0
  62. package/dist/editor/CodeBlockNode.d.ts.map +1 -0
  63. package/dist/editor/CodeBlockNode.js +127 -0
  64. package/dist/editor/CodeBlockNode.js.map +1 -0
  65. package/dist/editor/DragHandle.d.ts +97 -0
  66. package/dist/editor/DragHandle.d.ts.map +1 -0
  67. package/dist/editor/DragHandle.js +1066 -0
  68. package/dist/editor/DragHandle.js.map +1 -0
  69. package/dist/editor/DragHandle.spec.d.ts +2 -0
  70. package/dist/editor/DragHandle.spec.d.ts.map +1 -0
  71. package/dist/editor/DragHandle.spec.js +407 -0
  72. package/dist/editor/DragHandle.spec.js.map +1 -0
  73. package/dist/editor/ImageExtension.d.ts +63 -0
  74. package/dist/editor/ImageExtension.d.ts.map +1 -0
  75. package/dist/editor/ImageExtension.js +243 -0
  76. package/dist/editor/ImageExtension.js.map +1 -0
  77. package/dist/editor/ImageExtension.roundtrip.spec.d.ts +2 -0
  78. package/dist/editor/ImageExtension.roundtrip.spec.d.ts.map +1 -0
  79. package/dist/editor/ImageExtension.roundtrip.spec.js +103 -0
  80. package/dist/editor/ImageExtension.roundtrip.spec.js.map +1 -0
  81. package/dist/editor/RichMarkdownEditor.collab.spec.d.ts +2 -0
  82. package/dist/editor/RichMarkdownEditor.collab.spec.d.ts.map +1 -0
  83. package/dist/editor/RichMarkdownEditor.collab.spec.js +65 -0
  84. package/dist/editor/RichMarkdownEditor.collab.spec.js.map +1 -0
  85. package/dist/editor/RichMarkdownEditor.d.ts +52 -0
  86. package/dist/editor/RichMarkdownEditor.d.ts.map +1 -0
  87. package/dist/editor/RichMarkdownEditor.js +38 -0
  88. package/dist/editor/RichMarkdownEditor.js.map +1 -0
  89. package/dist/editor/RichMarkdownEditor.roundtrip.spec.d.ts +2 -0
  90. package/dist/editor/RichMarkdownEditor.roundtrip.spec.d.ts.map +1 -0
  91. package/dist/editor/RichMarkdownEditor.roundtrip.spec.js +186 -0
  92. package/dist/editor/RichMarkdownEditor.roundtrip.spec.js.map +1 -0
  93. package/dist/editor/RunId.d.ts +28 -0
  94. package/dist/editor/RunId.d.ts.map +1 -0
  95. package/dist/editor/RunId.js +60 -0
  96. package/dist/editor/RunId.js.map +1 -0
  97. package/dist/editor/SharedRichEditor.d.ts +110 -0
  98. package/dist/editor/SharedRichEditor.d.ts.map +1 -0
  99. package/dist/editor/SharedRichEditor.js +144 -0
  100. package/dist/editor/SharedRichEditor.js.map +1 -0
  101. package/dist/editor/SlashCommandMenu.d.ts +41 -0
  102. package/dist/editor/SlashCommandMenu.d.ts.map +1 -0
  103. package/dist/editor/SlashCommandMenu.js +221 -0
  104. package/dist/editor/SlashCommandMenu.js.map +1 -0
  105. package/dist/editor/disableHistory.spec.d.ts +2 -0
  106. package/dist/editor/disableHistory.spec.d.ts.map +1 -0
  107. package/dist/editor/disableHistory.spec.js +73 -0
  108. package/dist/editor/disableHistory.spec.js.map +1 -0
  109. package/dist/editor/extensions.d.ts +178 -0
  110. package/dist/editor/extensions.d.ts.map +1 -0
  111. package/dist/editor/extensions.js +224 -0
  112. package/dist/editor/extensions.js.map +1 -0
  113. package/dist/editor/gfmDoc.d.ts +24 -0
  114. package/dist/editor/gfmDoc.d.ts.map +1 -0
  115. package/dist/editor/gfmDoc.js +83 -0
  116. package/dist/editor/gfmDoc.js.map +1 -0
  117. package/dist/editor/gfmDoc.spec.d.ts +2 -0
  118. package/dist/editor/gfmDoc.spec.d.ts.map +1 -0
  119. package/dist/editor/gfmDoc.spec.js +194 -0
  120. package/dist/editor/gfmDoc.spec.js.map +1 -0
  121. package/dist/editor/index.d.ts +13 -0
  122. package/dist/editor/index.d.ts.map +1 -0
  123. package/dist/editor/index.js +13 -0
  124. package/dist/editor/index.js.map +1 -0
  125. package/dist/editor/structuralReorderUndo.spec.d.ts +2 -0
  126. package/dist/editor/structuralReorderUndo.spec.d.ts.map +1 -0
  127. package/dist/editor/structuralReorderUndo.spec.js +120 -0
  128. package/dist/editor/structuralReorderUndo.spec.js.map +1 -0
  129. package/dist/editor/surgical-apply.d.ts +66 -0
  130. package/dist/editor/surgical-apply.d.ts.map +1 -0
  131. package/dist/editor/surgical-apply.js +147 -0
  132. package/dist/editor/surgical-apply.js.map +1 -0
  133. package/dist/editor/surgical-apply.spec.d.ts +2 -0
  134. package/dist/editor/surgical-apply.spec.d.ts.map +1 -0
  135. package/dist/editor/surgical-apply.spec.js +257 -0
  136. package/dist/editor/surgical-apply.spec.js.map +1 -0
  137. package/dist/editor/useCollabReconcile.concurrent.spec.d.ts +2 -0
  138. package/dist/editor/useCollabReconcile.concurrent.spec.d.ts.map +1 -0
  139. package/dist/editor/useCollabReconcile.concurrent.spec.js +329 -0
  140. package/dist/editor/useCollabReconcile.concurrent.spec.js.map +1 -0
  141. package/dist/editor/useCollabReconcile.d.ts +110 -0
  142. package/dist/editor/useCollabReconcile.d.ts.map +1 -0
  143. package/dist/editor/useCollabReconcile.idempotent.spec.d.ts +2 -0
  144. package/dist/editor/useCollabReconcile.idempotent.spec.d.ts.map +1 -0
  145. package/dist/editor/useCollabReconcile.idempotent.spec.js +248 -0
  146. package/dist/editor/useCollabReconcile.idempotent.spec.js.map +1 -0
  147. package/dist/editor/useCollabReconcile.js +440 -0
  148. package/dist/editor/useCollabReconcile.js.map +1 -0
  149. package/dist/editor.css +510 -0
  150. package/package.json +63 -9
@@ -0,0 +1,329 @@
1
+ // @vitest-environment happy-dom
2
+ import { useEditor } from "@tiptap/react";
3
+ import React, { act } from "react";
4
+ import { createRoot } from "react-dom/client";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+ import { createRichMarkdownExtensions } from "./RichMarkdownEditor.js";
7
+ import { useCollabReconcile, getEditorMarkdown } from "./useCollabReconcile.js";
8
+ /**
9
+ * Concurrent-edit / lost-update coverage for the reconcile hook (non-collab
10
+ * controlled-value path — the same guards run there, and it's deterministic
11
+ * without a live Yjs peer). The idempotent spec covers the escalation loop;
12
+ * these cover the OTHER lost-update hazards the hook guards against:
13
+ *
14
+ * - A deliberate revert-to-a-previous-value AFTER a local edit must still land
15
+ * (it must not be swallowed as "our own echo").
16
+ * - registerEmitted must refuse to persist an empty doc in collab mode (so a
17
+ * pre-seed empty editor never writes "" over real stored content).
18
+ *
19
+ * NOTE: the "stale poll arrives WHILE the user is actively typing" guard is
20
+ * gated on `editor.isFocused`, which is always false under happy-dom (no real
21
+ * DOM focus). That path is verified in the browser E2E pass instead.
22
+ */
23
+ let container;
24
+ let root;
25
+ beforeEach(() => {
26
+ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
27
+ container = document.createElement("div");
28
+ document.body.appendChild(container);
29
+ root = createRoot(container);
30
+ });
31
+ afterEach(() => {
32
+ act(() => root.unmount());
33
+ container.remove();
34
+ });
35
+ function makeHarness() {
36
+ const captured = { editor: null, emitted: [], setContentCalls: 0 };
37
+ function Harness({ value, contentUpdatedAt }) {
38
+ const guardsRef = React.useRef(null);
39
+ const editor = useEditor({
40
+ extensions: createRichMarkdownExtensions({ dialect: "gfm" }),
41
+ content: value,
42
+ onUpdate: ({ editor, transaction }) => {
43
+ const guards = guardsRef.current;
44
+ if (!guards || guards.shouldIgnoreUpdate(transaction))
45
+ return;
46
+ const markdown = getEditorMarkdown(editor);
47
+ if (!guards.registerEmitted(markdown))
48
+ return;
49
+ captured.emitted.push(markdown);
50
+ },
51
+ });
52
+ captured.editor = editor;
53
+ const guards = useCollabReconcile({
54
+ editor,
55
+ value,
56
+ contentUpdatedAt,
57
+ editable: true,
58
+ getMarkdown: getEditorMarkdown,
59
+ setContent: (ed, v, options) => {
60
+ captured.setContentCalls += 1;
61
+ if (options.addToHistory === false) {
62
+ ed.chain()
63
+ .command(({ tr }) => {
64
+ tr.setMeta("addToHistory", false);
65
+ return true;
66
+ })
67
+ .setContent(v, { emitUpdate: options.emitUpdate })
68
+ .run();
69
+ return;
70
+ }
71
+ ed.commands.setContent(v);
72
+ },
73
+ });
74
+ guardsRef.current = guards;
75
+ captured.registerEmitted = guards.registerEmitted;
76
+ return React.createElement("div", null);
77
+ }
78
+ return { captured, Harness };
79
+ }
80
+ function makeCollabSeedHarness(initialContent = "") {
81
+ const captured = { editor: null, emitted: [], setContentCalls: 0 };
82
+ function Harness({ collabSynced, fragmentLength }) {
83
+ const guardsRef = React.useRef(null);
84
+ const fragmentLengthRef = React.useRef(fragmentLength);
85
+ fragmentLengthRef.current = fragmentLength;
86
+ const fakeYdoc = React.useMemo(() => ({
87
+ clientID: 1,
88
+ getXmlFragment: () => ({ length: fragmentLengthRef.current }),
89
+ }), []);
90
+ const editor = useEditor({
91
+ extensions: createRichMarkdownExtensions({ dialect: "gfm" }),
92
+ content: initialContent,
93
+ onUpdate: ({ editor, transaction }) => {
94
+ const guards = guardsRef.current;
95
+ if (!guards || guards.shouldIgnoreUpdate(transaction))
96
+ return;
97
+ const markdown = getEditorMarkdown(editor);
98
+ if (!guards.registerEmitted(markdown))
99
+ return;
100
+ captured.emitted.push(markdown);
101
+ },
102
+ });
103
+ captured.editor = editor;
104
+ const guards = useCollabReconcile({
105
+ editor,
106
+ ydoc: fakeYdoc,
107
+ collabSynced,
108
+ value: "seeded content",
109
+ contentUpdatedAt: "2024-01-01T00:00:01.000Z",
110
+ editable: true,
111
+ getMarkdown: getEditorMarkdown,
112
+ setContent: (ed, v) => {
113
+ captured.setContentCalls += 1;
114
+ ed.commands.setContent(v);
115
+ },
116
+ });
117
+ guardsRef.current = guards;
118
+ return React.createElement("div", null);
119
+ }
120
+ return { captured, Harness };
121
+ }
122
+ async function flush() {
123
+ await act(async () => {
124
+ await Promise.resolve();
125
+ await new Promise((resolve) => setTimeout(resolve, 0));
126
+ await Promise.resolve();
127
+ });
128
+ }
129
+ function render(root, Harness, props) {
130
+ act(() => {
131
+ root.render(React.createElement(Harness, props));
132
+ });
133
+ }
134
+ describe("useCollabReconcile — concurrent edit / lost-update guards", () => {
135
+ it("does not seed until initial collab sync has completed", async () => {
136
+ const { captured, Harness } = makeCollabSeedHarness();
137
+ act(() => {
138
+ root.render(React.createElement(Harness, {
139
+ collabSynced: false,
140
+ fragmentLength: 0,
141
+ }));
142
+ });
143
+ await flush();
144
+ expect(captured.setContentCalls).toBe(0);
145
+ act(() => {
146
+ root.render(React.createElement(Harness, {
147
+ collabSynced: true,
148
+ fragmentLength: 0,
149
+ }));
150
+ });
151
+ await flush();
152
+ expect(captured.setContentCalls).toBe(1);
153
+ expect(getEditorMarkdown(captured.editor)).toBe("seeded content");
154
+ });
155
+ it("does not seed after initial collab sync reveals existing canonical content", async () => {
156
+ const { captured, Harness } = makeCollabSeedHarness("seeded content");
157
+ act(() => {
158
+ root.render(React.createElement(Harness, {
159
+ collabSynced: false,
160
+ fragmentLength: 0,
161
+ }));
162
+ });
163
+ await flush();
164
+ act(() => {
165
+ root.render(React.createElement(Harness, {
166
+ collabSynced: true,
167
+ fragmentLength: 1,
168
+ }));
169
+ });
170
+ await flush();
171
+ expect(captured.setContentCalls).toBe(0);
172
+ expect(getEditorMarkdown(captured.editor)).toBe("seeded content");
173
+ });
174
+ it("applies a deliberate REVERT to a previously-applied value after a local edit (not swallowed as echo)", async () => {
175
+ // Regression for the revert-safety carve-out: the doc-equivalence echo
176
+ // guards (value === lastAppliedValueRef) only fire when the editor is
177
+ // UNCHANGED since the last apply. If the user has since edited, an external
178
+ // snapshot equal to a previously-applied value is a REAL revert (e.g. the
179
+ // agent restored an earlier version) and must land, not be skipped.
180
+ const { captured, Harness } = makeHarness();
181
+ // 1. Agent applies V1.
182
+ render(root, Harness, {
183
+ value: "# V1 content",
184
+ contentUpdatedAt: "2024-01-01T00:00:01.000Z",
185
+ });
186
+ await flush();
187
+ expect(getEditorMarkdown(captured.editor)).toBe("# V1 content");
188
+ // 2. Agent applies V2 (newer). Now lastApplied tracks V2.
189
+ render(root, Harness, {
190
+ value: "# V2 content",
191
+ contentUpdatedAt: "2024-01-01T00:00:02.000Z",
192
+ });
193
+ await flush();
194
+ expect(getEditorMarkdown(captured.editor)).toBe("# V2 content");
195
+ // 3. The agent REVERTS back to the V1 content with a NEWER timestamp (a
196
+ // genuine "undo my last change" external edit). Even though "# V1 content"
197
+ // was applied before, it must re-apply — the newer timestamp makes it a real
198
+ // external change, and the editor currently shows V2 (not V1).
199
+ render(root, Harness, {
200
+ value: "# V1 content",
201
+ contentUpdatedAt: "2024-01-01T00:00:03.000Z",
202
+ });
203
+ await flush();
204
+ expect(getEditorMarkdown(captured.editor)).toBe("# V1 content");
205
+ });
206
+ it("applies a newer authoritative revert that matches a prior mount-time emission", async () => {
207
+ const { captured, Harness } = makeHarness();
208
+ render(root, Harness, {
209
+ value: "# V1 content",
210
+ contentUpdatedAt: "2024-01-01T00:00:01.000Z",
211
+ });
212
+ await flush();
213
+ render(root, Harness, {
214
+ value: "# V2 content",
215
+ contentUpdatedAt: "2024-01-01T00:00:02.000Z",
216
+ });
217
+ await flush();
218
+ expect(getEditorMarkdown(captured.editor)).toBe("# V2 content");
219
+ // A collab mount/schema-normalization transaction can emit the old V1
220
+ // bytes even though the authoritative apply has already moved the editor
221
+ // to V2. Record that echo without focusing/typing in the editor.
222
+ expect(captured.registerEmitted?.("# V1 content")).toBe(true);
223
+ render(root, Harness, {
224
+ value: "# V1 content",
225
+ contentUpdatedAt: "2024-01-01T00:00:03.000Z",
226
+ });
227
+ await flush();
228
+ expect(getEditorMarkdown(captured.editor)).toBe("# V1 content");
229
+ });
230
+ it("ignores local-looking editor updates until collaborative seeding completes", async () => {
231
+ const results = [];
232
+ function Probe() {
233
+ const editor = useEditor({
234
+ extensions: createRichMarkdownExtensions({ dialect: "gfm" }),
235
+ content: "",
236
+ });
237
+ const fakeYdoc = { clientID: 1, getXmlFragment: () => ({ length: 0 }) };
238
+ const guards = useCollabReconcile({
239
+ editor,
240
+ ydoc: fakeYdoc,
241
+ collabSynced: false,
242
+ value: "authoritative content",
243
+ contentUpdatedAt: "2024-01-01T00:00:01.000Z",
244
+ editable: true,
245
+ });
246
+ if (editor && results.length === 0) {
247
+ results.push(guards.shouldIgnoreUpdate(editor.state.tr));
248
+ }
249
+ return React.createElement("div", null);
250
+ }
251
+ act(() => root.render(React.createElement(Probe)));
252
+ await flush();
253
+ expect(results).toEqual([true]);
254
+ });
255
+ it("refuses to persist an empty doc in collab mode (registerEmitted guard)", async () => {
256
+ // Directly exercise the guard contract: in collab mode an empty markdown
257
+ // string must not be registered/persisted (would clobber stored content
258
+ // before the shared Y.Doc seeds).
259
+ const results = [];
260
+ function Probe() {
261
+ const editor = useEditor({
262
+ extensions: createRichMarkdownExtensions({ dialect: "gfm" }),
263
+ content: "",
264
+ });
265
+ const fakeYdoc = { clientID: 1, getXmlFragment: () => ({ length: 0 }) };
266
+ const guards = useCollabReconcile({
267
+ editor,
268
+ ydoc: fakeYdoc,
269
+ value: "seeded content",
270
+ contentUpdatedAt: "2024-01-01T00:00:01.000Z",
271
+ editable: true,
272
+ });
273
+ if (editor && results.length === 0) {
274
+ results.push(guards.registerEmitted(" ")); // whitespace-only → empty
275
+ results.push(guards.registerEmitted("real text")); // non-empty
276
+ }
277
+ return React.createElement("div", null);
278
+ }
279
+ act(() => root.render(React.createElement(Probe)));
280
+ await flush();
281
+ expect(results[0]).toBe(false); // empty in collab mode → refused
282
+ expect(results[1]).toBe(true); // real content → accepted
283
+ });
284
+ it("defers collab seed setContent to a cancellable timer task", async () => {
285
+ const setContentValues = [];
286
+ function Probe({ value }) {
287
+ const editor = useEditor({
288
+ extensions: createRichMarkdownExtensions({ dialect: "gfm" }),
289
+ content: "",
290
+ });
291
+ const fakeYdoc = { clientID: 1, getXmlFragment: () => ({ length: 0 }) };
292
+ useCollabReconcile({
293
+ editor,
294
+ ydoc: fakeYdoc,
295
+ value,
296
+ contentUpdatedAt: "2024-01-01T00:00:01.000Z",
297
+ editable: true,
298
+ setContent: (ed, v) => {
299
+ setContentValues.push(v);
300
+ ed.commands.setContent(v);
301
+ },
302
+ });
303
+ return React.createElement("div", null);
304
+ }
305
+ act(() => root.render(React.createElement(Probe, { value: "first seed" })));
306
+ expect(setContentValues).toEqual([]);
307
+ act(() => root.render(React.createElement(Probe, { value: "second seed" })));
308
+ expect(setContentValues).toEqual([]);
309
+ await flush();
310
+ expect(setContentValues).toEqual(["second seed"]);
311
+ });
312
+ it("applies a genuinely newer external value once the user is no longer focused", async () => {
313
+ const { captured, Harness } = makeHarness();
314
+ render(root, Harness, {
315
+ value: "# Doc",
316
+ contentUpdatedAt: "2024-01-01T00:00:01.000Z",
317
+ });
318
+ await flush();
319
+ // Blur the editor so the typing/focus guard does not defer.
320
+ act(() => captured.editor.commands.blur());
321
+ render(root, Harness, {
322
+ value: "# Doc updated by agent",
323
+ contentUpdatedAt: "2024-01-01T00:00:05.000Z",
324
+ });
325
+ await flush();
326
+ expect(getEditorMarkdown(captured.editor)).toBe("# Doc updated by agent");
327
+ });
328
+ });
329
+ //# sourceMappingURL=useCollabReconcile.concurrent.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCollabReconcile.concurrent.spec.js","sourceRoot":"","sources":["../../src/editor/useCollabReconcile.concurrent.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
2
+ import type { Transaction } from "@tiptap/pm/state";
3
+ import type { Editor } from "@tiptap/react";
4
+ import { type MutableRefObject } from "react";
5
+ import type { Awareness } from "y-protocols/awareness";
6
+ import type { Doc as YDoc } from "yjs";
7
+ import { RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION } from "./surgical-apply.js";
8
+ export { RICH_MARKDOWN_PROGRAMMATIC_TRANSACTION };
9
+ /** Reads the current markdown out of the tiptap-markdown storage. */
10
+ export declare function getEditorMarkdown(editor: Editor): string;
11
+ export interface UseCollabReconcileOptions {
12
+ /** The live editor, or null until it mounts. */
13
+ editor: Editor | null;
14
+ /** Shared Y.Doc when collaborating; null disables all collab paths. */
15
+ ydoc?: YDoc | null;
16
+ /** True after the collab provider has loaded the persisted initial Y.Doc state. */
17
+ collabSynced?: boolean;
18
+ /** Shared awareness; null keeps the sole-client lead path. */
19
+ awareness?: Awareness | null;
20
+ /** Authoritative markdown value (SQL source of truth). */
21
+ value: string;
22
+ /** Timestamp of the authoritative value; gates newer-than reconcile. */
23
+ contentUpdatedAt?: string | null;
24
+ /** Whether the editor accepts edits. Reconcile/seed only run for the live editor. */
25
+ editable: boolean;
26
+ /**
27
+ * Reads the current markdown from the editor. Injected so a dialect could
28
+ * swap serializers; defaults to the tiptap-markdown storage reader. For an app
29
+ * with a custom serializer (e.g. Content's `docToNfm(editor.getJSON())`), pass
30
+ * it here so the seed/reconcile equality checks compare like-for-like.
31
+ */
32
+ getMarkdown?: (editor: Editor) => string;
33
+ /**
34
+ * Applies the authoritative `value` into the editor. Defaults to passing the
35
+ * raw markdown string to `editor.commands.setContent`. Apps whose serializer
36
+ * is NOT tiptap-markdown (Content parses `nfmToDoc(value)` into a PM doc)
37
+ * override this so seed + reconcile write the correct content shape. The
38
+ * supplied `options` carry the history/whitespace flags the default path uses;
39
+ * a custom implementation should forward them when relevant.
40
+ */
41
+ setContent?: (editor: Editor, value: string, options: {
42
+ emitUpdate?: boolean;
43
+ addToHistory?: boolean;
44
+ }) => void;
45
+ /**
46
+ * Parses the authoritative `value` into a full ProseMirror document for the
47
+ * SURGICAL reconcile path: instead of a whole-document `setContent` (which
48
+ * under Collaboration rewrites the entire Y.XmlFragment and tears down every
49
+ * block NodeView), the reconcile diffs the parsed doc against the live doc
50
+ * and replaces only the changed top-level run. Return null to skip the
51
+ * surgical path for a given value (falls back to `setContent`).
52
+ *
53
+ * Defaults to a best-effort tiptap-markdown parse; apps with their own
54
+ * serializers (Content's NFM, Plan's blocks[] doc) should supply the exact
55
+ * doc their `setContent` would write. Pass `false` to disable surgical
56
+ * application entirely.
57
+ */
58
+ parseValue?: ((editor: Editor, value: string) => ProseMirrorNode | null) | false;
59
+ /**
60
+ * Normalizes the authoritative `value` to the canonical markdown the editor
61
+ * would emit, so the "already in sync / our own echo" equality checks match a
62
+ * serializer that re-canonicalizes (Content's `canonicalizeNfm`). Defaults to
63
+ * identity (GFM already round-trips byte-stably).
64
+ */
65
+ normalizeValue?: (value: string) => string;
66
+ /**
67
+ * Decides whether the empty-doc seed should run for the current shared
68
+ * fragment. Defaults to "fragment has no nodes, or the editor holds no
69
+ * semantic markdown". Apps with sentinel-empty content (Content's
70
+ * `<empty-block/>` filler) override this. Receives the live fragment length
71
+ * and the editor's current markdown.
72
+ */
73
+ shouldSeed?: (info: {
74
+ value: string;
75
+ currentMarkdown: string;
76
+ fragmentLength: number;
77
+ }) => boolean;
78
+ /**
79
+ * The initial "applied" watermark. Default mirrors `contentUpdatedAt`, so a
80
+ * fresh mount whose Y.Doc already matches SQL doesn't re-apply. Pass `null`
81
+ * to force the first reconcile pass to adopt authoritative SQL even at the
82
+ * same timestamp — Content does this so a stale persisted Y.Doc (an agent that
83
+ * edited the CLOSED doc) is corrected on open. The editor is keyed per
84
+ * document upstream, so this only affects the first mount of each doc.
85
+ */
86
+ initialAppliedUpdatedAt?: string | null;
87
+ }
88
+ export interface UseCollabReconcileResult {
89
+ /** True when a Y.Doc is bound (collaborative editing active). */
90
+ collab: boolean;
91
+ /**
92
+ * Set true around any programmatic `setContent` so the editor's `onUpdate`
93
+ * can ignore the resulting transaction (it isn't a user edit).
94
+ */
95
+ isSettingContentRef: MutableRefObject<boolean>;
96
+ /**
97
+ * Call from `onUpdate` BEFORE serializing. Returns true when the update must
98
+ * be ignored: editor not editable, mid-programmatic-setContent, or (in collab
99
+ * mode) a remote-origin transaction. Also records the local typing time.
100
+ */
101
+ shouldIgnoreUpdate: (transaction: Transaction) => boolean;
102
+ /**
103
+ * Call from `onUpdate` AFTER computing the markdown to emit. Returns false
104
+ * when the value must NOT be persisted yet (an empty collab doc before the
105
+ * seed has run); records it as the last-emitted value otherwise.
106
+ */
107
+ registerEmitted: (markdown: string) => boolean;
108
+ }
109
+ export declare function useCollabReconcile({ editor, ydoc, collabSynced, awareness, value, contentUpdatedAt, editable, getMarkdown, setContent, parseValue, normalizeValue, shouldSeed, initialAppliedUpdatedAt, }: UseCollabReconcileOptions): UseCollabReconcileResult;
110
+ //# sourceMappingURL=useCollabReconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCollabReconcile.d.ts","sourceRoot":"","sources":["../../src/editor/useCollabReconcile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAA+B,KAAK,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,GAAG,IAAI,IAAI,EAAE,MAAM,KAAK,CAAC;AAGvC,OAAO,EACL,sCAAsC,EAGvC,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,sCAAsC,EAAE,CAAC;AAElD,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKxD;AAqBD,MAAM,WAAW,yBAAyB;IACxC,gDAAgD;IAChD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,uEAAuE;IACvE,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,mFAAmF;IACnF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,qFAAqF;IACrF,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CACX,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,KACtD,IAAI,CAAC;IACV;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EACP,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,eAAe,GAAG,IAAI,CAAC,GAC3D,KAAK,CAAC;IACV;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;KACxB,KAAK,OAAO,CAAC;IACd;;;;;;;OAOG;IACH,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,wBAAwB;IACvC,iEAAiE;IACjE,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,mBAAmB,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC/C;;;;OAIG;IACH,kBAAkB,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC;IAC1D;;;;OAIG;IACH,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;CAChD;AAoED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,IAAW,EACX,YAAmB,EACnB,SAAgB,EAChB,KAAK,EACL,gBAAgB,EAChB,QAAQ,EACR,WAA+B,EAC/B,UAA8B,EAC9B,UAAU,EACV,cAAyB,EACzB,UAA8B,EAC9B,uBAAuB,GACxB,EAAE,yBAAyB,GAAG,wBAAwB,CAyWtD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useCollabReconcile.idempotent.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCollabReconcile.idempotent.spec.d.ts","sourceRoot":"","sources":["../../src/editor/useCollabReconcile.idempotent.spec.ts"],"names":[],"mappings":""}