mindoodb-app-sdk 0.0.14 → 0.0.17
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 +410 -132
- package/dist/index.d.ts +97 -4
- package/dist/index.js +367 -55
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +300 -40
- package/dist/{types-B1iKRIuy.d.ts → types-Dw6YRApH.d.ts} +135 -9
- package/package.json +13 -11
package/dist/index.js
CHANGED
|
@@ -142,6 +142,7 @@ var PortRpcClient = class {
|
|
|
142
142
|
this.port.addEventListener("message", this.handleMessage);
|
|
143
143
|
this.port.start();
|
|
144
144
|
}
|
|
145
|
+
port;
|
|
145
146
|
pending = /* @__PURE__ */ new Map();
|
|
146
147
|
listeners = /* @__PURE__ */ new Set();
|
|
147
148
|
requestCounter = 0;
|
|
@@ -232,7 +233,10 @@ var PortRpcClient = class {
|
|
|
232
233
|
var PROTOCOL2 = "mindoodb-app-bridge";
|
|
233
234
|
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
234
235
|
function toTransferableArrayBuffer(chunk) {
|
|
235
|
-
return chunk.buffer.slice(
|
|
236
|
+
return chunk.buffer.slice(
|
|
237
|
+
chunk.byteOffset,
|
|
238
|
+
chunk.byteOffset + chunk.byteLength
|
|
239
|
+
);
|
|
236
240
|
}
|
|
237
241
|
function isStreamChunkFor(streamId, message) {
|
|
238
242
|
return message.kind === "stream-chunk" && message.streamId === streamId;
|
|
@@ -262,7 +266,9 @@ function resolveLaunchId(options) {
|
|
|
262
266
|
return options.launchId;
|
|
263
267
|
}
|
|
264
268
|
if (typeof window === "undefined") {
|
|
265
|
-
throw new Error(
|
|
269
|
+
throw new Error(
|
|
270
|
+
"A launchId must be provided when connecting outside the browser."
|
|
271
|
+
);
|
|
266
272
|
}
|
|
267
273
|
const search = new URLSearchParams(window.location.search);
|
|
268
274
|
const launchId = search.get("mindoodbAppLaunchId");
|
|
@@ -271,9 +277,17 @@ function resolveLaunchId(options) {
|
|
|
271
277
|
}
|
|
272
278
|
return launchId;
|
|
273
279
|
}
|
|
280
|
+
function shouldUseWindowedHostTab() {
|
|
281
|
+
if (typeof window === "undefined") {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
return window.parent === window && Boolean(window.opener);
|
|
285
|
+
}
|
|
274
286
|
function resolveTargetWindow() {
|
|
275
287
|
if (typeof window === "undefined") {
|
|
276
|
-
throw new Error(
|
|
288
|
+
throw new Error(
|
|
289
|
+
"The MindooDB app bridge is only available in the browser."
|
|
290
|
+
);
|
|
277
291
|
}
|
|
278
292
|
if (window.parent && window.parent !== window) {
|
|
279
293
|
return window.parent;
|
|
@@ -281,7 +295,7 @@ function resolveTargetWindow() {
|
|
|
281
295
|
if (window.opener) {
|
|
282
296
|
return window.opener;
|
|
283
297
|
}
|
|
284
|
-
throw new Error("Could not find a MindooDB
|
|
298
|
+
throw new Error("Could not find a MindooDB Haven host window.");
|
|
285
299
|
}
|
|
286
300
|
function waitForConnectedPort(options, launchId) {
|
|
287
301
|
const targetWindow = resolveTargetWindow();
|
|
@@ -294,20 +308,36 @@ function waitForConnectedPort(options, launchId) {
|
|
|
294
308
|
if (timeoutId !== null) {
|
|
295
309
|
window.clearTimeout(timeoutId);
|
|
296
310
|
}
|
|
297
|
-
channel.port1.removeEventListener(
|
|
311
|
+
channel.port1.removeEventListener(
|
|
312
|
+
"message",
|
|
313
|
+
handleMessage
|
|
314
|
+
);
|
|
298
315
|
};
|
|
299
316
|
const handleMessage = (event) => {
|
|
300
317
|
const payload = event.data;
|
|
301
|
-
if (!payload || payload.protocol !== PROTOCOL2
|
|
318
|
+
if (!payload || payload.protocol !== PROTOCOL2) {
|
|
302
319
|
return;
|
|
303
320
|
}
|
|
304
|
-
|
|
305
|
-
|
|
321
|
+
if (payload.type === "mindoodb-app:connected") {
|
|
322
|
+
cleanup();
|
|
323
|
+
resolve(channel.port1);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (payload.type === "mindoodb-app:error") {
|
|
327
|
+
cleanup();
|
|
328
|
+
channel.port1.close();
|
|
329
|
+
const message2 = typeof payload.error === "string" && payload.error.trim() ? payload.error : "MindooDB Haven bridge connection failed.";
|
|
330
|
+
reject(new Error(message2));
|
|
331
|
+
}
|
|
306
332
|
};
|
|
307
333
|
timeoutId = window.setTimeout(() => {
|
|
308
334
|
cleanup();
|
|
309
335
|
channel.port1.close();
|
|
310
|
-
reject(
|
|
336
|
+
reject(
|
|
337
|
+
new Error(
|
|
338
|
+
`Timed out while connecting to the MindooDB Haven bridge for launch ${launchId}.`
|
|
339
|
+
)
|
|
340
|
+
);
|
|
311
341
|
}, timeoutMs);
|
|
312
342
|
channel.port1.addEventListener("message", handleMessage);
|
|
313
343
|
channel.port1.start();
|
|
@@ -325,6 +355,9 @@ var MindooDBAppViewNavigatorImpl = class {
|
|
|
325
355
|
this.navigatorId = navigatorId;
|
|
326
356
|
this.viewCursor = viewCursor;
|
|
327
357
|
}
|
|
358
|
+
rpc;
|
|
359
|
+
navigatorId;
|
|
360
|
+
viewCursor;
|
|
328
361
|
/** Shorthand: call an RPC method with the navigator ID automatically injected. */
|
|
329
362
|
async call(method, params = {}) {
|
|
330
363
|
return await this.rpc.call(method, {
|
|
@@ -339,7 +372,9 @@ var MindooDBAppViewNavigatorImpl = class {
|
|
|
339
372
|
return this.viewCursor;
|
|
340
373
|
}
|
|
341
374
|
async refresh() {
|
|
342
|
-
const result = await this.call(
|
|
375
|
+
const result = await this.call(
|
|
376
|
+
"viewNavigators.refresh"
|
|
377
|
+
);
|
|
343
378
|
this.viewCursor = result.viewCursor;
|
|
344
379
|
return this.viewCursor;
|
|
345
380
|
}
|
|
@@ -383,10 +418,14 @@ var MindooDBAppViewNavigatorImpl = class {
|
|
|
383
418
|
return await this.call("viewNavigators.category.findByParts", { parts });
|
|
384
419
|
}
|
|
385
420
|
async entriesForward(options) {
|
|
386
|
-
return await this.call("viewNavigators.entries.forward", {
|
|
421
|
+
return await this.call("viewNavigators.entries.forward", {
|
|
422
|
+
options: options ?? {}
|
|
423
|
+
});
|
|
387
424
|
}
|
|
388
425
|
async entriesBackward(options) {
|
|
389
|
-
return await this.call("viewNavigators.entries.backward", {
|
|
426
|
+
return await this.call("viewNavigators.entries.backward", {
|
|
427
|
+
options: options ?? {}
|
|
428
|
+
});
|
|
390
429
|
}
|
|
391
430
|
async gotoNextSelected() {
|
|
392
431
|
return await this.call("viewNavigators.goto.nextSelected");
|
|
@@ -411,7 +450,10 @@ var MindooDBAppViewNavigatorImpl = class {
|
|
|
411
450
|
await this.call("viewNavigators.selection.deselectAll");
|
|
412
451
|
}
|
|
413
452
|
async isSelected(origin, docId) {
|
|
414
|
-
return await this.call("viewNavigators.selection.isSelected", {
|
|
453
|
+
return await this.call("viewNavigators.selection.isSelected", {
|
|
454
|
+
origin,
|
|
455
|
+
docId
|
|
456
|
+
});
|
|
415
457
|
}
|
|
416
458
|
async getSelectionState() {
|
|
417
459
|
return await this.call("viewNavigators.selection.get");
|
|
@@ -444,13 +486,22 @@ var MindooDBAppViewNavigatorImpl = class {
|
|
|
444
486
|
await this.call("viewNavigators.expansion.set", { state });
|
|
445
487
|
}
|
|
446
488
|
async childEntries(entryKey, descending) {
|
|
447
|
-
return await this.call("viewNavigators.children.entries", {
|
|
489
|
+
return await this.call("viewNavigators.children.entries", {
|
|
490
|
+
entryKey,
|
|
491
|
+
descending
|
|
492
|
+
});
|
|
448
493
|
}
|
|
449
494
|
async childCategories(entryKey, descending) {
|
|
450
|
-
return await this.call("viewNavigators.children.categories", {
|
|
495
|
+
return await this.call("viewNavigators.children.categories", {
|
|
496
|
+
entryKey,
|
|
497
|
+
descending
|
|
498
|
+
});
|
|
451
499
|
}
|
|
452
500
|
async childDocuments(entryKey, descending) {
|
|
453
|
-
return await this.call("viewNavigators.children.documents", {
|
|
501
|
+
return await this.call("viewNavigators.children.documents", {
|
|
502
|
+
entryKey,
|
|
503
|
+
descending
|
|
504
|
+
});
|
|
454
505
|
}
|
|
455
506
|
async childCategoriesByKey(entryKey, key, exact, descending) {
|
|
456
507
|
return await this.call("viewNavigators.children.categoriesByKey", {
|
|
@@ -469,16 +520,28 @@ var MindooDBAppViewNavigatorImpl = class {
|
|
|
469
520
|
});
|
|
470
521
|
}
|
|
471
522
|
async childCategoriesBetween(entryKey, range) {
|
|
472
|
-
return await this.call("viewNavigators.children.categoriesBetween", {
|
|
523
|
+
return await this.call("viewNavigators.children.categoriesBetween", {
|
|
524
|
+
entryKey,
|
|
525
|
+
range
|
|
526
|
+
});
|
|
473
527
|
}
|
|
474
528
|
async childDocumentsBetween(entryKey, range) {
|
|
475
|
-
return await this.call("viewNavigators.children.documentsBetween", {
|
|
529
|
+
return await this.call("viewNavigators.children.documentsBetween", {
|
|
530
|
+
entryKey,
|
|
531
|
+
range
|
|
532
|
+
});
|
|
476
533
|
}
|
|
477
534
|
async getSortedDocIds(descending) {
|
|
478
|
-
return await this.call(
|
|
535
|
+
return await this.call(
|
|
536
|
+
"viewNavigators.sortedDocIds.get",
|
|
537
|
+
{ descending }
|
|
538
|
+
);
|
|
479
539
|
}
|
|
480
540
|
async getSortedDocIdsScoped(entryKey, descending) {
|
|
481
|
-
return await this.call(
|
|
541
|
+
return await this.call(
|
|
542
|
+
"viewNavigators.sortedDocIds.scoped",
|
|
543
|
+
{ entryKey, descending }
|
|
544
|
+
);
|
|
482
545
|
}
|
|
483
546
|
async dispose() {
|
|
484
547
|
await this.call("viewNavigators.dispose");
|
|
@@ -495,7 +558,9 @@ var MindooDBAppReadableAttachmentStreamImpl = class {
|
|
|
495
558
|
if (!pending) {
|
|
496
559
|
return;
|
|
497
560
|
}
|
|
498
|
-
pending.resolve(
|
|
561
|
+
pending.resolve(
|
|
562
|
+
message.done ? null : new Uint8Array(message.chunk ?? new ArrayBuffer(0))
|
|
563
|
+
);
|
|
499
564
|
if (message.done) {
|
|
500
565
|
this.closed = true;
|
|
501
566
|
this.unsubscribe();
|
|
@@ -511,6 +576,8 @@ var MindooDBAppReadableAttachmentStreamImpl = class {
|
|
|
511
576
|
}
|
|
512
577
|
});
|
|
513
578
|
}
|
|
579
|
+
rpc;
|
|
580
|
+
streamId;
|
|
514
581
|
unsubscribe;
|
|
515
582
|
closed = false;
|
|
516
583
|
pendingRead = null;
|
|
@@ -520,7 +587,9 @@ var MindooDBAppReadableAttachmentStreamImpl = class {
|
|
|
520
587
|
return null;
|
|
521
588
|
}
|
|
522
589
|
if (this.pendingRead) {
|
|
523
|
-
throw new Error(
|
|
590
|
+
throw new Error(
|
|
591
|
+
"A read() call is already in progress for this attachment stream."
|
|
592
|
+
);
|
|
524
593
|
}
|
|
525
594
|
return await new Promise((resolve, reject) => {
|
|
526
595
|
this.pendingRead = { resolve, reject };
|
|
@@ -567,6 +636,8 @@ var MindooDBAppWritableAttachmentStreamImpl = class {
|
|
|
567
636
|
}
|
|
568
637
|
});
|
|
569
638
|
}
|
|
639
|
+
rpc;
|
|
640
|
+
streamId;
|
|
570
641
|
unsubscribe;
|
|
571
642
|
closed = false;
|
|
572
643
|
inflight = null;
|
|
@@ -592,12 +663,15 @@ var MindooDBAppWritableAttachmentStreamImpl = class {
|
|
|
592
663
|
return await this.enqueue(async () => {
|
|
593
664
|
const buffer = toTransferableArrayBuffer(chunk);
|
|
594
665
|
await this.waitForAck(() => {
|
|
595
|
-
this.rpc.postMessage(
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
666
|
+
this.rpc.postMessage(
|
|
667
|
+
{
|
|
668
|
+
protocol: PROTOCOL2,
|
|
669
|
+
kind: "stream-write",
|
|
670
|
+
streamId: this.streamId,
|
|
671
|
+
chunk: buffer
|
|
672
|
+
},
|
|
673
|
+
[buffer]
|
|
674
|
+
);
|
|
601
675
|
});
|
|
602
676
|
});
|
|
603
677
|
}
|
|
@@ -665,6 +739,10 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
665
739
|
databaseId: this.databaseId,
|
|
666
740
|
docId
|
|
667
741
|
}),
|
|
742
|
+
undelete: async (docId) => await this.rpc.call("documents.undelete", {
|
|
743
|
+
databaseId: this.databaseId,
|
|
744
|
+
docId
|
|
745
|
+
}),
|
|
668
746
|
listHistory: async (docId) => await this.rpc.call("documents.history.list", {
|
|
669
747
|
databaseId: this.databaseId,
|
|
670
748
|
docId
|
|
@@ -673,49 +751,130 @@ var MindooDBAppDatabaseImpl = class {
|
|
|
673
751
|
databaseId: this.databaseId,
|
|
674
752
|
docId,
|
|
675
753
|
timestamp
|
|
754
|
+
}),
|
|
755
|
+
getAtRevision: async (docId, revisionId) => await this.rpc.call("documents.history.getAtRevision", {
|
|
756
|
+
databaseId: this.databaseId,
|
|
757
|
+
docId,
|
|
758
|
+
revisionId
|
|
676
759
|
})
|
|
677
760
|
};
|
|
678
761
|
this.attachments = {
|
|
679
|
-
list: async (docId) => await this.rpc.call("attachments.list", {
|
|
762
|
+
list: async (docId, options) => await this.rpc.call("attachments.list", {
|
|
680
763
|
databaseId: this.databaseId,
|
|
681
|
-
docId
|
|
764
|
+
docId,
|
|
765
|
+
timestamp: options?.timestamp,
|
|
766
|
+
revisionId: options?.revisionId
|
|
682
767
|
}),
|
|
683
768
|
remove: async (docId, attachmentName) => await this.rpc.call("attachments.remove", {
|
|
684
769
|
databaseId: this.databaseId,
|
|
685
770
|
docId,
|
|
686
771
|
attachmentName
|
|
687
772
|
}),
|
|
688
|
-
openReadStream: async (docId, attachmentName) => {
|
|
689
|
-
const result = await this.rpc.call(
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
773
|
+
openReadStream: async (docId, attachmentName, options) => {
|
|
774
|
+
const result = await this.rpc.call(
|
|
775
|
+
"attachments.openReadStream",
|
|
776
|
+
{
|
|
777
|
+
databaseId: this.databaseId,
|
|
778
|
+
docId,
|
|
779
|
+
attachmentName,
|
|
780
|
+
timestamp: options?.timestamp,
|
|
781
|
+
revisionId: options?.revisionId
|
|
782
|
+
}
|
|
783
|
+
);
|
|
784
|
+
return new MindooDBAppReadableAttachmentStreamImpl(
|
|
785
|
+
this.rpc,
|
|
786
|
+
result.streamId
|
|
787
|
+
);
|
|
695
788
|
},
|
|
696
789
|
openWriteStream: async (docId, attachmentName, contentType) => {
|
|
697
|
-
const result = await this.rpc.call(
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
790
|
+
const result = await this.rpc.call(
|
|
791
|
+
"attachments.openWriteStream",
|
|
792
|
+
{
|
|
793
|
+
databaseId: this.databaseId,
|
|
794
|
+
docId,
|
|
795
|
+
attachmentName,
|
|
796
|
+
contentType
|
|
797
|
+
}
|
|
798
|
+
);
|
|
799
|
+
return new MindooDBAppWritableAttachmentStreamImpl(
|
|
800
|
+
this.rpc,
|
|
801
|
+
result.streamId
|
|
802
|
+
);
|
|
803
|
+
},
|
|
804
|
+
scan: async (docId, options) => {
|
|
805
|
+
const scannerTab = shouldUseWindowedHostTab() ? window.open("", "_blank") : null;
|
|
806
|
+
if (scannerTab) {
|
|
807
|
+
try {
|
|
808
|
+
scannerTab.document.title = "Opening document scanner...";
|
|
809
|
+
const preparedSession = await this.rpc.call("attachments.prepareScanSession", {
|
|
810
|
+
databaseId: this.databaseId,
|
|
811
|
+
docId,
|
|
812
|
+
defaultFileName: options?.defaultFileName,
|
|
813
|
+
preset: options?.preset,
|
|
814
|
+
mimeType: options?.mimeType
|
|
815
|
+
});
|
|
816
|
+
scannerTab.location.href = preparedSession.scanUrl;
|
|
817
|
+
return await this.rpc.call(
|
|
818
|
+
"attachments.awaitScanSession",
|
|
819
|
+
{
|
|
820
|
+
databaseId: this.databaseId,
|
|
821
|
+
sessionId: preparedSession.sessionId
|
|
822
|
+
}
|
|
823
|
+
);
|
|
824
|
+
} catch (error) {
|
|
825
|
+
scannerTab.close();
|
|
826
|
+
throw error;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return await this.rpc.call(
|
|
830
|
+
"attachments.scanAndWrite",
|
|
831
|
+
{
|
|
832
|
+
databaseId: this.databaseId,
|
|
833
|
+
docId,
|
|
834
|
+
defaultFileName: options?.defaultFileName,
|
|
835
|
+
preset: options?.preset,
|
|
836
|
+
mimeType: options?.mimeType
|
|
837
|
+
}
|
|
838
|
+
);
|
|
704
839
|
},
|
|
705
840
|
preparePreviewSession: async (docId, attachmentName, options) => await this.rpc.call("attachments.preparePreviewSession", {
|
|
706
841
|
databaseId: this.databaseId,
|
|
707
842
|
docId,
|
|
708
843
|
attachmentName,
|
|
709
|
-
timestamp: options?.timestamp
|
|
844
|
+
timestamp: options?.timestamp,
|
|
845
|
+
revisionId: options?.revisionId
|
|
710
846
|
}),
|
|
711
|
-
openPreview: async (docId, attachmentName, options) =>
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
847
|
+
openPreview: async (docId, attachmentName, options) => {
|
|
848
|
+
const previewTab = shouldUseWindowedHostTab() ? window.open("", "_blank") : null;
|
|
849
|
+
if (previewTab) {
|
|
850
|
+
try {
|
|
851
|
+
previewTab.document.title = "Opening attachment preview...";
|
|
852
|
+
const previewSession = await this.rpc.call("attachments.preparePreviewSession", {
|
|
853
|
+
databaseId: this.databaseId,
|
|
854
|
+
docId,
|
|
855
|
+
attachmentName,
|
|
856
|
+
timestamp: options?.timestamp,
|
|
857
|
+
revisionId: options?.revisionId
|
|
858
|
+
});
|
|
859
|
+
previewTab.location.href = previewSession.previewUrl;
|
|
860
|
+
return { ok: true };
|
|
861
|
+
} catch (error) {
|
|
862
|
+
previewTab.close();
|
|
863
|
+
throw error;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return await this.rpc.call("attachments.openPreview", {
|
|
867
|
+
databaseId: this.databaseId,
|
|
868
|
+
docId,
|
|
869
|
+
attachmentName,
|
|
870
|
+
timestamp: options?.timestamp,
|
|
871
|
+
revisionId: options?.revisionId
|
|
872
|
+
});
|
|
873
|
+
}
|
|
717
874
|
};
|
|
718
875
|
}
|
|
876
|
+
rpc;
|
|
877
|
+
databaseId;
|
|
719
878
|
documents;
|
|
720
879
|
attachments;
|
|
721
880
|
/** Returns database metadata for the currently opened binding. */
|
|
@@ -735,8 +894,9 @@ var MindooDBAppSessionImpl = class {
|
|
|
735
894
|
}
|
|
736
895
|
};
|
|
737
896
|
}
|
|
897
|
+
rpc;
|
|
738
898
|
menus;
|
|
739
|
-
/** Returns the launch context provided by the
|
|
899
|
+
/** Returns the launch context provided by the Haven host. */
|
|
740
900
|
async getLaunchContext() {
|
|
741
901
|
return await this.rpc.call("session.getLaunchContext", {});
|
|
742
902
|
}
|
|
@@ -750,7 +910,9 @@ var MindooDBAppSessionImpl = class {
|
|
|
750
910
|
return new MindooDBAppDatabaseImpl(this.rpc, databaseId);
|
|
751
911
|
}
|
|
752
912
|
async listDocumentsSinceViewCursor(cursor) {
|
|
753
|
-
return await this.rpc.call("session.listDocumentsSinceViewCursor", {
|
|
913
|
+
return await this.rpc.call("session.listDocumentsSinceViewCursor", {
|
|
914
|
+
cursor
|
|
915
|
+
});
|
|
754
916
|
}
|
|
755
917
|
/**
|
|
756
918
|
* Create a navigator from an ad-hoc view definition and one or more database bindings.
|
|
@@ -761,7 +923,11 @@ var MindooDBAppSessionImpl = class {
|
|
|
761
923
|
*/
|
|
762
924
|
async createViewNavigator(input) {
|
|
763
925
|
const result = await this.rpc.call("session.createViewNavigator", input);
|
|
764
|
-
return new MindooDBAppViewNavigatorImpl(
|
|
926
|
+
return new MindooDBAppViewNavigatorImpl(
|
|
927
|
+
this.rpc,
|
|
928
|
+
result.navigatorId,
|
|
929
|
+
result.viewCursor
|
|
930
|
+
);
|
|
765
931
|
}
|
|
766
932
|
/**
|
|
767
933
|
* Open a navigator for a preconfigured view that the host already knows about.
|
|
@@ -771,7 +937,11 @@ var MindooDBAppSessionImpl = class {
|
|
|
771
937
|
*/
|
|
772
938
|
async openViewNavigator(viewId, options) {
|
|
773
939
|
const result = await this.rpc.call("session.openViewNavigator", { viewId, options: options ?? {} });
|
|
774
|
-
return new MindooDBAppViewNavigatorImpl(
|
|
940
|
+
return new MindooDBAppViewNavigatorImpl(
|
|
941
|
+
this.rpc,
|
|
942
|
+
result.navigatorId,
|
|
943
|
+
result.viewCursor
|
|
944
|
+
);
|
|
775
945
|
}
|
|
776
946
|
/** Subscribe to host-pushed theme changes (dark/light mode, color tokens). */
|
|
777
947
|
onThemeChange(listener) {
|
|
@@ -817,6 +987,146 @@ function createMindooDBAppBridge() {
|
|
|
817
987
|
};
|
|
818
988
|
}
|
|
819
989
|
|
|
990
|
+
// src/textBuffer.ts
|
|
991
|
+
var MindooDBTextBuffer = class {
|
|
992
|
+
constructor(options) {
|
|
993
|
+
this.options = options;
|
|
994
|
+
this.valueInternal = readTextAtPath(options.document.data, options.path);
|
|
995
|
+
this.heads = options.document.heads ? [...options.document.heads] : [];
|
|
996
|
+
}
|
|
997
|
+
options;
|
|
998
|
+
valueInternal;
|
|
999
|
+
heads;
|
|
1000
|
+
pendingEdits = [];
|
|
1001
|
+
get value() {
|
|
1002
|
+
return this.valueInternal;
|
|
1003
|
+
}
|
|
1004
|
+
/** Whether there are local edits that have not been flushed yet. */
|
|
1005
|
+
get dirty() {
|
|
1006
|
+
return this.pendingEdits.length > 0;
|
|
1007
|
+
}
|
|
1008
|
+
/** Number of pending text operations currently buffered. */
|
|
1009
|
+
get pendingCount() {
|
|
1010
|
+
return this.pendingEdits.length;
|
|
1011
|
+
}
|
|
1012
|
+
/** Return the current local text value. */
|
|
1013
|
+
toString() {
|
|
1014
|
+
return this.valueInternal;
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Apply an exact local text splice and queue it for the next flush.
|
|
1018
|
+
*
|
|
1019
|
+
* Offsets use JavaScript string indexing. The delete count is clamped to the
|
|
1020
|
+
* remaining local text length so callers can safely delete to the end.
|
|
1021
|
+
*/
|
|
1022
|
+
splice(index, deleteCount, insert = "") {
|
|
1023
|
+
if (!Number.isInteger(index) || index < 0 || index > this.valueInternal.length) {
|
|
1024
|
+
throw new RangeError("Text splice index is out of range");
|
|
1025
|
+
}
|
|
1026
|
+
if (!Number.isInteger(deleteCount) || deleteCount < 0) {
|
|
1027
|
+
throw new RangeError("Text splice deleteCount must be a non-negative integer");
|
|
1028
|
+
}
|
|
1029
|
+
const clampedDeleteCount = Math.min(deleteCount, this.valueInternal.length - index);
|
|
1030
|
+
this.valueInternal = this.valueInternal.slice(0, index) + insert + this.valueInternal.slice(index + clampedDeleteCount);
|
|
1031
|
+
this.pendingEdits.push({ index, deleteCount: clampedDeleteCount, insert });
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Replace the current local text value and queue the change as one splice.
|
|
1035
|
+
*
|
|
1036
|
+
* This is useful for editors such as Milkdown that can produce the full
|
|
1037
|
+
* markdown string after each transaction but do not expose raw text splices.
|
|
1038
|
+
*/
|
|
1039
|
+
replaceText(nextValue) {
|
|
1040
|
+
if (nextValue === this.valueInternal) {
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
const edit = computeSingleSplice(this.valueInternal, nextValue);
|
|
1044
|
+
this.splice(edit.index, edit.deleteCount, edit.insert ?? "");
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Replace local state from a fresh document snapshot and clear pending edits.
|
|
1048
|
+
*
|
|
1049
|
+
* Returns whether the text value changed. Use this after an external refresh
|
|
1050
|
+
* or after receiving a document update through another app-level mechanism.
|
|
1051
|
+
*/
|
|
1052
|
+
reconcile(document) {
|
|
1053
|
+
const nextValue = readTextAtPath(document.data, this.options.path);
|
|
1054
|
+
const changed = nextValue !== this.valueInternal;
|
|
1055
|
+
this.valueInternal = nextValue;
|
|
1056
|
+
this.heads = document.heads ? [...document.heads] : [];
|
|
1057
|
+
this.pendingEdits = [];
|
|
1058
|
+
return changed;
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Flush pending edits to Haven using `documents.update({ text: ... })`.
|
|
1062
|
+
*
|
|
1063
|
+
* The request includes the document heads this buffer is based on, allowing
|
|
1064
|
+
* Haven to apply the text operations at the original causal version and merge
|
|
1065
|
+
* them with any concurrent document changes. After a successful flush the
|
|
1066
|
+
* buffer adopts the returned canonical value and heads, and clears the
|
|
1067
|
+
* pending edit queue.
|
|
1068
|
+
*/
|
|
1069
|
+
async flush() {
|
|
1070
|
+
if (this.pendingEdits.length === 0) {
|
|
1071
|
+
return {
|
|
1072
|
+
document: this.options.document,
|
|
1073
|
+
value: this.valueInternal,
|
|
1074
|
+
reconciled: false
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
const localValueAtFlush = this.valueInternal;
|
|
1078
|
+
const document = await this.options.database.documents.update(this.options.document.id, {
|
|
1079
|
+
text: [{
|
|
1080
|
+
path: this.options.path,
|
|
1081
|
+
baseHeads: this.heads,
|
|
1082
|
+
edits: this.pendingEdits.map((edit) => ({ ...edit }))
|
|
1083
|
+
}]
|
|
1084
|
+
});
|
|
1085
|
+
const nextValue = readTextAtPath(document.data, this.options.path);
|
|
1086
|
+
const reconciled = nextValue !== localValueAtFlush;
|
|
1087
|
+
this.valueInternal = nextValue;
|
|
1088
|
+
this.heads = document.heads ? [...document.heads] : [];
|
|
1089
|
+
this.pendingEdits = [];
|
|
1090
|
+
return {
|
|
1091
|
+
document,
|
|
1092
|
+
value: this.valueInternal,
|
|
1093
|
+
reconciled
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
function createMindooDBTextBuffer(options) {
|
|
1098
|
+
return new MindooDBTextBuffer(options);
|
|
1099
|
+
}
|
|
1100
|
+
function readTextAtPath(data, path) {
|
|
1101
|
+
let value = data;
|
|
1102
|
+
for (const segment of path) {
|
|
1103
|
+
if (value == null || typeof value !== "object") {
|
|
1104
|
+
return "";
|
|
1105
|
+
}
|
|
1106
|
+
value = value[segment];
|
|
1107
|
+
}
|
|
1108
|
+
return typeof value === "string" ? value : "";
|
|
1109
|
+
}
|
|
1110
|
+
function computeSingleSplice(previous, next) {
|
|
1111
|
+
let prefixLength = 0;
|
|
1112
|
+
const maxPrefix = Math.min(previous.length, next.length);
|
|
1113
|
+
while (prefixLength < maxPrefix && previous[prefixLength] === next[prefixLength]) {
|
|
1114
|
+
prefixLength += 1;
|
|
1115
|
+
}
|
|
1116
|
+
let suffixLength = 0;
|
|
1117
|
+
const previousRemaining = previous.length - prefixLength;
|
|
1118
|
+
const nextRemaining = next.length - prefixLength;
|
|
1119
|
+
const maxSuffix = Math.min(previousRemaining, nextRemaining);
|
|
1120
|
+
while (suffixLength < maxSuffix && previous[previous.length - 1 - suffixLength] === next[next.length - 1 - suffixLength]) {
|
|
1121
|
+
suffixLength += 1;
|
|
1122
|
+
}
|
|
1123
|
+
return {
|
|
1124
|
+
index: prefixLength,
|
|
1125
|
+
deleteCount: previous.length - prefixLength - suffixLength,
|
|
1126
|
+
insert: next.slice(prefixLength, next.length - suffixLength)
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
|
|
820
1130
|
// src/viewLanguage.ts
|
|
821
1131
|
import {
|
|
822
1132
|
createViewLanguage,
|
|
@@ -825,9 +1135,11 @@ import {
|
|
|
825
1135
|
mindooDBViewLanguageHelpersByName
|
|
826
1136
|
} from "mindoodb-view-language";
|
|
827
1137
|
export {
|
|
1138
|
+
MindooDBTextBuffer,
|
|
828
1139
|
abbreviateCanonicalName,
|
|
829
1140
|
canPreviewAttachment,
|
|
830
1141
|
createMindooDBAppBridge,
|
|
1142
|
+
createMindooDBTextBuffer,
|
|
831
1143
|
createViewLanguage,
|
|
832
1144
|
expandAbbreviatedName
|
|
833
1145
|
};
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ac as MindooDBAppLaunchContext, X as MindooDBAppDatabaseInfo, Y as MindooDBAppDocumentApi, W as MindooDBAppCreateViewNavigatorInput, aK as MindooDBAppViewNavigator, aM as MindooDBAppViewNavigatorOpenOptions, d as MindooDBAppAttachmentApi, a as MindooDBAppBridge, ay as MindooDBAppSession, q as MindooDBAppBridgeRpcRequest, a6 as MindooDBAppHostTheme, aR as MindooDBAppViewport, aE as MindooDBAppUiPreferences, n as MindooDBAppBridgePortMessage } from '../types-Dw6YRApH.js';
|
|
2
2
|
import 'mindoodb-view-language';
|
|
3
3
|
|
|
4
4
|
type MaybePromise<T> = T | Promise<T>;
|